diff --git a/build.gradle b/build.gradle index b17ab70..0398c75 100644 --- a/build.gradle +++ b/build.gradle @@ -24,6 +24,9 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'com.auth0:java-jwt:3.4.0' + implementation 'com.google.zxing:core:3.3.0' + implementation 'com.google.zxing:javase:3.3.0' + compile group: 'org.bytedeco', name: 'javacv-platform', version: '1.5.2' // implementation name: 'opencv-420' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation('org.junit.jupiter:junit-jupiter-api') diff --git a/src/main/java/pl/edu/amu/wmi/bookapi/security/WebSecurity.java b/src/main/java/pl/edu/amu/wmi/bookapi/security/WebSecurity.java index 13bad36..41ba8a8 100644 --- a/src/main/java/pl/edu/amu/wmi/bookapi/security/WebSecurity.java +++ b/src/main/java/pl/edu/amu/wmi/bookapi/security/WebSecurity.java @@ -34,7 +34,8 @@ public class WebSecurity extends WebSecurityConfigurerAdapter { // .antMatchers(HttpMethod.PATCH, "/api/books/*").permitAll() .antMatchers(HttpMethod.POST, SIGN_UP_URL, - LOG_IN_URL).permitAll() + LOG_IN_URL, + "/api/books/image").permitAll() .anyRequest().authenticated() .and() .addFilter( diff --git a/src/main/java/pl/edu/amu/wmi/bookapi/service/ImageProcessingService.java b/src/main/java/pl/edu/amu/wmi/bookapi/service/ImageProcessingService.java index 65024b4..f9c96d9 100644 --- a/src/main/java/pl/edu/amu/wmi/bookapi/service/ImageProcessingService.java +++ b/src/main/java/pl/edu/amu/wmi/bookapi/service/ImageProcessingService.java @@ -1,9 +1,50 @@ package pl.edu.amu.wmi.bookapi.service; +import com.google.zxing.BinaryBitmap; +import com.google.zxing.ChecksumException; +import com.google.zxing.FormatException; +import com.google.zxing.LuminanceSource; +import com.google.zxing.NotFoundException; +import com.google.zxing.Reader; +import com.google.zxing.Result; +import com.google.zxing.client.j2se.BufferedImageLuminanceSource; +import com.google.zxing.common.HybridBinarizer; +import com.google.zxing.oned.EAN13Reader; +import org.bytedeco.opencv.global.opencv_imgproc; +import org.bytedeco.opencv.opencv_core.Mat; +import org.bytedeco.opencv.opencv_core.MatVector; +import org.bytedeco.opencv.opencv_core.Size; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferInt; +import java.io.File; +import java.io.IOException; + +import static org.bytedeco.opencv.global.opencv_core.CV_32F; +import static org.bytedeco.opencv.global.opencv_core.CV_8UC3; +import static org.bytedeco.opencv.global.opencv_core.convertScaleAbs; +import static org.bytedeco.opencv.global.opencv_core.subtract; +import static org.bytedeco.opencv.global.opencv_imgcodecs.imwrite; +import static org.bytedeco.opencv.global.opencv_imgproc.CHAIN_APPROX_SIMPLE; +import static org.bytedeco.opencv.global.opencv_imgproc.COLOR_BGR2GRAY; +import static org.bytedeco.opencv.global.opencv_imgproc.MORPH_CLOSE; +import static org.bytedeco.opencv.global.opencv_imgproc.MORPH_RECT; +import static org.bytedeco.opencv.global.opencv_imgproc.RETR_EXTERNAL; +import static org.bytedeco.opencv.global.opencv_imgproc.Sobel; +import static org.bytedeco.opencv.global.opencv_imgproc.THRESH_BINARY; +import static org.bytedeco.opencv.global.opencv_imgproc.blur; +import static org.bytedeco.opencv.global.opencv_imgproc.cvtColor; +import static org.bytedeco.opencv.global.opencv_imgproc.findContours; +import static org.bytedeco.opencv.global.opencv_imgproc.getStructuringElement; +import static org.bytedeco.opencv.global.opencv_imgproc.morphologyEx; +import static org.bytedeco.opencv.global.opencv_imgproc.threshold; + @Service public class ImageProcessingService { @@ -12,35 +53,140 @@ public class ImageProcessingService { } public String getDecodedEan(MultipartFile imageFile) throws Exception { + checkIfImageContainsBarcode(imageFile); - return ""; -// -// String fileId = UUID.randomUUID().toString(); -// Path path = Path.of(new File(".").getCanonicalPath()); -// -// byte[] starting = imageFile.getBytes(); -// -// saveImg(starting, path, fileId, 1); -// -// Mat mat = Imgcodecs.imdecode(new MatOfByte(starting), Imgcodecs.IMREAD_GRAYSCALE); -// -// Mat gray = new Mat(); -// Imgproc.cvtColor(mat, gray, COLOR_BGR2GRAY); -// -// byte[] grayed = mat2byteArr(gray); -// -// saveImg(grayed, path, fileId, 2); -// -// return ""; + return getBarcode(imageFile); } -// private byte[] mat2byteArr(Mat mat) { -// byte[] bytes = new byte[0]; -// mat.get(0, 0, bytes); -// return bytes; -// } + private String getBarcode(MultipartFile imageFile) throws IOException { + Reader reader = new EAN13Reader(); + BufferedImage img = ImageIO.read(imageFile.getInputStream()); + LuminanceSource source = new BufferedImageLuminanceSource(img); + BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); + try { + Result result = reader.decode(bitmap); + return result.getText(); + } catch (NotFoundException | FormatException | ChecksumException e) { + e.printStackTrace(); + return null; + } + } + + private void checkIfImageContainsBarcode(MultipartFile imageFile) throws IOException{ + BufferedImage img = ImageIO.read(imageFile.getInputStream()); + File outputfile = new File("start.jpg"); + ImageIO.write(img, "jpg", outputfile); + + Mat src = matify(img); + Mat dst = new Mat(); + cvtColor(src, dst, COLOR_BGR2GRAY); + imwrite("./before.png", src); + imwrite("./test.png", dst); + + Mat sobel = new Mat(); + + Mat matScharX = new Mat(); + Mat matScharY = new Mat(); + +// Scharr(dst, matScharX, CV_32F, 1, 0, 1.0d, -1.0, 0); +// Scharr(dst, matScharX, CV_32F, 0, 1, 1.0d, -1.0, 0); + Sobel(dst, matScharX, CV_32F, 1, 0, -1, 1.0, 1.0, 1); + Sobel(dst, matScharY, CV_32F, 0, 1, -1, 1.0, 1.0, 1); + + subtract(matScharX, matScharY); + Mat conv = new Mat(); + convertScaleAbs(matScharX, conv); + imwrite("./scharr.png", conv); + + Mat blurDestination = new Mat(); + blur(conv, blurDestination, new Size(9,9)); + + Mat thresholdDestination = new Mat(); + threshold(blurDestination, thresholdDestination, 230d, 255d, THRESH_BINARY); + + imwrite("./threshold.png", thresholdDestination); + + Mat kernel = getStructuringElement(MORPH_RECT, new Size(21, 7)); + Mat morph = new Mat(); + morphologyEx(thresholdDestination, morph, MORPH_CLOSE, kernel); + + imwrite("./morph.png", morph); // -// private void saveImg(byte[] bytes, Path path, String imageName, Integer version) throws IOException { -// Files.write(Path.of(path.toString(), "/" + imageName + "__v" + version + ".png"), bytes); -// } +// Mat erode = new Mat(); +// imwrite("./erodeBefore.png", morph); +// opencv_imgproc.erode(morph, erode, new Mat()); +// for(int i =0 ; i < 3 ; i++) { +// opencv_imgproc.erode(erode, erode, new Mat()); +// } +// +// Mat dilate = new Mat(); +// opencv_imgproc.dilate(morph, dilate, new Mat()); +// for(int i =0 ; i < 3 ; i++) { +// opencv_imgproc.erode(dilate, dilate, new Mat()); +// } + + imwrite("./erodeAfter.png", morph); + MatVector contour = new MatVector(); + findContours(morph, contour ,RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); + int count = 0; + for (int i = 0 ; i < contour.size(); i++){ + double minContourArea = (double) img.getHeight() * img.getWidth() * 0.05; + System.out.println("Min contour " + minContourArea + "current contour " + opencv_imgproc.contourArea(contour.get(i))); + if(opencv_imgproc.contourArea(contour.get(i)) > minContourArea) { + System.out.println("Contour " + i); + System.out.println(opencv_imgproc.contourArea(contour.get(i))); + count++; + } + } + + System.out.println("No of contours higher than threshold"); + System.out.println(count); + System.out.println("Total contours"); + System.out.println(contour.size()); + } + + public Mat matify(BufferedImage sourceImg) { + System.out.println("Matify"); + long millis = System.currentTimeMillis(); + + DataBuffer dataBuffer = sourceImg.getRaster().getDataBuffer(); + byte[] imgPixels = null; + Mat imgMat = null; + + int width = sourceImg.getWidth(); + int height = sourceImg.getHeight(); + + if(dataBuffer instanceof DataBufferByte) { + imgPixels = ((DataBufferByte)dataBuffer).getData(); + } + + if(dataBuffer instanceof DataBufferInt) { + System.out.println("Matify1"); + + int byteSize = width * height; + imgPixels = new byte[byteSize*3]; + + int[] imgIntegerPixels = ((DataBufferInt)dataBuffer).getData(); + System.out.println("Matify2"); + + for(int p = 0; p < byteSize; p++) { + imgPixels[p*3 + 0] = (byte) ((imgIntegerPixels[p] & 0x00FF0000) >> 16); + imgPixels[p*3 + 1] = (byte) ((imgIntegerPixels[p] & 0x0000FF00) >> 8); + imgPixels[p*3 + 2] = (byte) (imgIntegerPixels[p] & 0x000000FF); + } + System.out.println("Matify"); + + } + + if(imgPixels != null) { + imgMat = new Mat(height, width, CV_8UC3); + imgMat.data().put(imgPixels); + } + + Mat mat = new Mat(); + + System.out.println("matify exec millis: " + (System.currentTimeMillis() - millis)); + + return imgMat; + } } diff --git a/src/test/java/pl/edu/amu/wmi/bookapi/BookapiApplicationTests.java b/src/test/java/pl/edu/amu/wmi/bookapi/BookapiApplicationTests.java index 8573a8d..70eda33 100644 --- a/src/test/java/pl/edu/amu/wmi/bookapi/BookapiApplicationTests.java +++ b/src/test/java/pl/edu/amu/wmi/bookapi/BookapiApplicationTests.java @@ -16,5 +16,4 @@ class BookapiApplicationTests { void contextLoads() { System.out.println(mongoTemplate.findAll(UserDocument.class)); } - }