source: other-projects/is-sheet-music-encore/trunk/image-identification-terminal/javaClassifierComparison.java@ 33458

Last change on this file since 33458 was 33458, checked in by cpb16, 5 years ago

Running new morphology version after quick meeting with david last week. init tests are looking good. Running on whole corpus now...

File size: 38.4 KB
Line 
1import org.opencv.core.*;
2import org.opencv.core.Point;
3import org.opencv.highgui.HighGui;
4import org.opencv.imgcodecs.Imgcodecs;
5import org.opencv.imgproc.Imgproc;
6import org.opencv.imgproc.Moments;
7//import org.opencv.core.Core.FILLED;
8//import org.opencv.imgcodecs.Imgcodecs.imwrite;
9import java.awt.image.BufferedImage;
10import java.awt.image.DataBufferByte;
11import java.io.FileInputStream;
12import java.io.IOException;
13//import java.io.File;
14//import java.io.BufferedWriter;
15//import java.io.FileWriter;
16import javax.imageio.ImageIO;
17//import java.util.logging.Logger;
18//import java.util.ArrayList;
19//import java.util.Collections.*;
20import java.util.*;
21//import java.util.Properties;
22import java.lang.*;
23import java.io.*;
24
25//REFERENCES:
26//https://docs.opencv.org/3.4.3/d9/db0/tutorial_hough_lines.
27//https://stackoverflow.com/questions/43443309/count-red-pixel-in-a-given-image
28//https://www.wikihow.com/Calculate-Percentage-in-Java
29//https://riptutorial.com/opencv/example/21963/converting-an-mat-object-to-an-bufferedimage-object
30//https://stackoverflow.com/questions/15758685/how-to-write-logs-in-text-file-when-using-java-util-logging-logger
31//https://stackoverflow.com/questions/9961292/write-to-text-file-without-overwriting-in-java
32//https://alvinalexander.com/java/edu/pj/pj010005
33//https://stackoverflow.com/questions/8557716/how-to-return-multiple-values
34
35//OUTPUT OF THIS JAVA PROGRAM FOUND IN log.txt
36//Each image processed will have an output of
37//True =classifierType + 1 + Filename + Status
38//False =classifierType + 0 + Filename + Status
39public class javaClassifierComparison {
40
41//*******************************************************************************************
42//GLOBALS
43//*******************************************************************************************
44/*
45 //HOUGHLINE
46 static int CLASSIFIER_HOUGHLINESP_MIN = 10;
47 static int CLASSIFIER_HOUGHLINESP_MAX = 65;
48 static int HOUGHLINEP_THRESHOLD = 10;
49 static int STANDARD_DEVIATION_THRESHOLD = 6;
50 static int MINLINECOUNT = 40;
51 static int MAXLINEGAP = 1;
52 static double THRESHOLD_C = 4;
53 static double SLOPEGRADIENT = 0.02;
54 static double CLUSTER_DISTANCE_MAX = 40;
55 static double CLUSTER_DISTANCE_MIN = 2;
56 //MORPHOLOGY
57 static double THRESHOLD_AREA_SIZE = 1000;
58 static double THRESHOLD_AREA_COUNT = 4;
59*/
60 static int CLASSIFIER_HOUGHLINESP_MIN;
61 static int CLASSIFIER_HOUGHLINESP_MAX;
62 static int HOUGHLINEP_THRESHOLD;
63 static int STANDARD_DEVIATION_THRESHOLD;
64 static int MINLINECOUNT;
65 static int MAXLINEGAP;
66 static double THRESHOLD_C;
67 static double SLOPEGRADIENT;
68 static double CLUSTER_DISTANCE_MAX;
69 static double CLUSTER_DISTANCE_MIN;
70 //MORPHOLOGY
71 static double THRESHOLD_AREA_SIZE;
72 static double THRESHOLD_AREA_COUNT;
73
74//********************************************************************************************
75//CLASSES
76//********************************************************************************************
77
78 //Sets globals based off properties file
79 public static void init(){
80 try{
81 Properties config = new Properties();
82 FileInputStream input = new FileInputStream("configClassifierComparison.properties");
83 config.load(input);
84 CLASSIFIER_HOUGHLINESP_MIN = Integer.parseInt(config.getProperty("CLASSIFIER_HOUGHLINESP_MIN"));
85 CLASSIFIER_HOUGHLINESP_MAX = Integer.parseInt(config.getProperty("CLASSIFIER_HOUGHLINESP_MAX"));
86 HOUGHLINEP_THRESHOLD = Integer.parseInt(config.getProperty("HOUGHLINEP_THRESHOLD"));
87 STANDARD_DEVIATION_THRESHOLD = Integer.parseInt(config.getProperty("STANDARD_DEVIATION_THRESHOLD"));
88 MINLINECOUNT = Integer.parseInt(config.getProperty("MINLINECOUNT"));
89 MAXLINEGAP = Integer.parseInt(config.getProperty("MAXLINEGAP"));
90 THRESHOLD_C = Double.parseDouble(config.getProperty("THRESHOLD_C"));
91 SLOPEGRADIENT = Double.parseDouble(config.getProperty("SLOPEGRADIENT"));
92 CLUSTER_DISTANCE_MAX = Double.parseDouble(config.getProperty("CLUSTER_DISTANCE_MAX"));
93 CLUSTER_DISTANCE_MIN = Double.parseDouble(config.getProperty("CLUSTER_DISTANCE_MIN"));
94 THRESHOLD_AREA_SIZE = Double.parseDouble(config.getProperty("THRESHOLD_AREA_SIZE"));
95 THRESHOLD_AREA_COUNT = Double.parseDouble(config.getProperty("THRESHOLD_AREA_COUNT"));
96 }
97 catch(Exception e){
98 e.printStackTrace();
99 }
100 }
101
102 static public class StartAndEndPoint {
103 //PRIVATES
104 private Point _p1;
105 private Point _p2;
106
107 //CONSTRUCTOR
108 public StartAndEndPoint(Point p1, Point p2) {
109 _p1 = p1;
110 _p2 = p2;
111 }
112
113 //GETTERS
114 public Point getP1() {
115 return _p1;
116 }
117
118 public Point getP2() {
119 return _p2;
120 }
121
122 //SETTERS
123 public void setP1(Point p1) {
124 _p1 = p1;
125 }
126
127 public void setP2(Point p2) {
128 _p2 = p2;
129 }
130
131 //ToString
132 public String toString() {
133 return "Start: " + _p1 + " End: " + _p2;
134 }
135 }
136 static public class Pair{
137 //Privates
138 private Boolean _b;
139 private Integer _i;
140
141 //Constructor
142 public Pair(Boolean b, Integer i){
143 _b = b;
144 _i = i;
145 }
146 public Pair(){
147 _b = null;
148 _i = null;
149 }
150
151 //Getters
152 public Boolean getBoolean() {return _b;}
153 public Integer getInteger() {return _i;}
154
155 //Setters
156 public void setBoolean (Boolean b){_b = b;}
157 public void setInteger (Integer i){_i = i;}
158
159 //ToString
160 public String toString() {return "Boolean: " + _b + " Integer: " + _i;}
161 }
162
163 public static void main(String[] args) {
164 init();
165 try {
166
167 if (args.length != 3) {
168 System.out.println("Usage: imageClassifier <inputFilename> <classifierType> <outputFilename>");
169 } else {
170 Pair algorithmResult = new Pair();
171
172 Boolean result = null;
173 String result_cluster = "";
174 String imageFilename = args[0];
175 String classifierType = args[1];
176 String outputFilename = args[2];
177 Boolean enableLineClustering = null;
178 //Prep Writing output to disc
179 File log = new File(outputFilename);
180 FileWriter fileWriter = new FileWriter(log, true);
181 BufferedWriter bw = new BufferedWriter(fileWriter);
182 //Execute classifierType defined from arguement
183
184 File imgCheck = new File(imageFilename);
185 if(!imgCheck.exists()){System.err.println("Image not found: "+ imageFilename);}
186
187 //Split output by tab for processing in next java program
188 //imageFilename = 1, result = 3, classifierType = 4
189
190 switch (classifierType) {
191 case "count":
192 enableLineClustering = false;
193 algorithmResult = Algorithm_HoughLinesP_Single(imageFilename, enableLineClustering);
194 bw.write("Filename:" + '\t' + imageFilename + '\t' + "Classified as:" + '\t' + algorithmResult.getBoolean() + '\t' + "Number of lines:" + '\t' + algorithmResult.getInteger() + '\t' + classifierType + '\n');
195 break;
196 case "cluster":
197 enableLineClustering = true;
198 algorithmResult = Algorithm_HoughLinesP_Single(imageFilename, enableLineClustering);
199 bw.write("Filename:" + '\t' + imageFilename + '\t' + "Classified as:" + '\t' + algorithmResult.getBoolean() + '\t' + "Number of lines:" + '\t' + algorithmResult.getInteger() + '\t' + classifierType + '\n');
200 break;
201 case "combo":
202 algorithmResult = Algorithm_HoughLinesP_Combo(imageFilename);
203 bw.write("Filename:" + '\t' + imageFilename + '\t' + "Classified as:" + '\t' + algorithmResult.getBoolean() + '\t' + "Number of lines:" + '\t' + algorithmResult.getInteger() + '\t' + classifierType + '\n');
204 break;
205 case "morphology":
206 algorithmResult = Algorithm_Morphology(imageFilename);
207 bw.write("Filename:" + '\t' + imageFilename + '\t' + "Classified as:" + '\t' + algorithmResult.getBoolean() + '\t' + "Number of areas:" + '\t' + algorithmResult.getInteger() + '\t' + classifierType + '\n');
208 break;
209 default:
210 System.out.println("unknown algorithm");
211 break;
212 }
213
214 bw.close();
215 }
216 } catch (Exception e) {
217 System.err.println(e);
218 }
219 }
220
221 //******************
222 //ALGORITHM FUNCTIONS
223 //******************
224 private static Pair Algorithm_HoughLinesP_Single(String filename, Boolean enableLineClusterDetection){
225 System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
226 Boolean isSheetMusic = null;
227 Pair returnVariables = new Pair();
228 try{
229 //Variables
230 int horizontalLineCount =0;
231 Mat edgesDetected = new Mat();
232 Mat edgesDetectedRGB = new Mat();
233 Mat edgesExtra = new Mat();
234 Mat edgesDetectedRGBProb;
235 ArrayList<StartAndEndPoint> pointArrayList = new ArrayList<StartAndEndPoint>();
236
237 //****************EXPLANATION**************************************************
238 //
239 //Load an image in greyscale
240 //Additional matrix to hold results of line detection
241 //Inversed Binarization of image
242 //Detect lines in image
243 //Go thru every line detected and check its gradient is less than SLOPEGRADIENT
244 //
245 //****************EXPLANATION**************************************************
246
247 Mat original = Imgcodecs.imread(filename, Imgcodecs.IMREAD_GRAYSCALE);
248 Mat linesP = new Mat(); //will hold the results of the detection
249 Imgproc.adaptiveThreshold(original, edgesDetected,255, Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C,Imgproc.THRESH_BINARY_INV,15, THRESHOLD_C);
250 double minLineLength = edgesDetected.size().width/8;
251 Imgproc.HoughLinesP(edgesDetected, linesP, 1, Math.PI / 720, HOUGHLINEP_THRESHOLD, minLineLength, MAXLINEGAP);
252 for (int x = 0; x < linesP.rows(); x++) {
253 double[] l = linesP.get(x, 0);
254 Point p1 = new Point(l[0], l[1]);
255 Point p2 = new Point(l[2], l[3]);
256 double m = Math.abs(p2.y - p1.y)/(p2.x - p1.x);
257 if(m<SLOPEGRADIENT) {
258 horizontalLineCount++;
259 pointArrayList.add(new StartAndEndPoint(p1, p2));
260 }
261 }
262
263 //Calculate if its sheet music or not
264 if(enableLineClusterDetection ==true){returnVariables = Classifier_ClusterDetection(pointArrayList);}
265 else {
266 isSheetMusic = Classifier_LineCounter(horizontalLineCount);
267 returnVariables.setBoolean(isSheetMusic);
268 returnVariables.setInteger(horizontalLineCount);
269 }
270 }
271 catch(Exception e){
272 System.err.println(e);
273 }
274 return returnVariables;
275 }
276 private static Pair Algorithm_HoughLinesP_Combo(String filename){
277 System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
278 Boolean isSheetMusic = null;
279 Pair returnVariables = new Pair();
280 try{
281 //Variables
282 int horizontalLineCount =0;
283 Mat edgesDetected = new Mat();
284 Mat edgesDetectedRGB = new Mat();
285 Mat edgesExtra = new Mat();
286 Mat edgesDetectedRGBProb;
287 ArrayList<StartAndEndPoint> pointArrayList = new ArrayList<StartAndEndPoint>();
288
289 //****************EXPLANATION**************************************************
290 //
291 //Load an image in greyscale
292 //Additional matrix to hold results of line detection
293 //Inversed Binarization of image
294 //Detect lines in image
295 //Go thru every line detected and check its gradient is less than SLOPEGRADIENT
296 //
297 //****************EXPLANATION**************************************************
298
299 Mat original = Imgcodecs.imread(filename, Imgcodecs.IMREAD_GRAYSCALE);
300 Mat linesP = new Mat(); //will hold the results of the detection
301 Imgproc.adaptiveThreshold(original, edgesDetected,255, Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C,Imgproc.THRESH_BINARY_INV,15, THRESHOLD_C);
302 double minLineLength = edgesDetected.size().width/8;
303 Imgproc.HoughLinesP(edgesDetected, linesP, 1, Math.PI / 720, HOUGHLINEP_THRESHOLD, minLineLength, MAXLINEGAP);
304 for (int x = 0; x < linesP.rows(); x++) {
305 double[] l = linesP.get(x, 0);
306 Point p1 = new Point(l[0], l[1]);
307 Point p2 = new Point(l[2], l[3]);
308 double m = Math.abs(p2.y - p1.y)/(p2.x - p1.x);
309 if(m<SLOPEGRADIENT) {
310 horizontalLineCount++;
311 pointArrayList.add(new StartAndEndPoint(p1, p2));
312 }
313 }
314
315 //Calculate if its sheet music or not
316 isSheetMusic = Classifier_LineCounter(horizontalLineCount);
317 if(isSheetMusic == true){
318 returnVariables.setBoolean(isSheetMusic);
319 returnVariables.setInteger(horizontalLineCount);
320 }
321 else if (isSheetMusic == false){
322 returnVariables = Classifier_ClusterDetection(pointArrayList);
323 }
324 }
325 catch(Exception e){
326 System.err.println(e);
327 }
328 return returnVariables;
329 }
330 private static Pair Algorithm_MorphologyOLD2(String filename){
331
332 System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
333 Boolean isSheetMusic = null;
334 Pair returnVariables = new Pair();
335 int areaCounter = 0;
336 try{
337 Mat edgesDetectedRGB = new Mat();
338 Mat original = Imgcodecs.imread(filename, Imgcodecs.IMREAD_GRAYSCALE);
339
340 System.out.println("Width: " + original.width() + " Height: " + original.height());
341
342 ArrayList<MatOfPoint> contours = new ArrayList<MatOfPoint>();
343 Mat hierarchy = new Mat();
344
345 //Thresholds
346 Imgproc.adaptiveThreshold(original, original,255, Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C,Imgproc.THRESH_BINARY_INV, 15, THRESHOLD_C);
347 Mat processed = original.clone();
348 //Morphological Processing
349 Mat kernelErode = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(10,1));
350 Imgproc.erode(processed,processed,kernelErode);
351
352 Mat kernelDilate = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(20,3));
353 Imgproc.dilate(processed,processed,kernelDilate);
354
355 Mat kernelOpening = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(4,4));
356 Imgproc.morphologyEx(processed, processed, Imgproc.MORPH_CLOSE, kernelOpening);
357
358 Mat kernelErode02 = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(8,8));
359 Imgproc.erode(processed,processed,kernelErode02);
360
361 //Detect contours
362 Imgproc.findContours(processed, contours, hierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE);
363
364 //Record areas
365 for (int i = 0; i < contours.size(); i++) {
366 double area = Imgproc.contourArea(contours.get(i));
367 System.out.println("AREA: " + area);
368 //Check if area detected meets threshold
369 if(area > THRESHOLD_AREA_SIZE) {
370 areaCounter++;
371
372 }
373 }
374 System.out.println("areacount = " + areaCounter);
375
376 //Calculates if sheet music or not
377 if(areaCounter >= THRESHOLD_AREA_COUNT){
378 isSheetMusic = true;
379 returnVariables.setBoolean(isSheetMusic);
380 returnVariables.setInteger(areaCounter);
381 }
382 }
383 catch(Exception e){
384 System.err.println(e);
385 }
386 return returnVariables;
387 }
388 private static Pair Algorithm_MorphologyOLD(String filename){
389
390 System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
391 Boolean isSheetMusic = null;
392 Pair returnVariables = new Pair();
393 int FILLED = -1;
394 try{
395 Mat original1 = Imgcodecs.imread(filename, Imgcodecs.IMREAD_GRAYSCALE);
396 System.out.println("Width: " + original1.width() + " Height: " + original1.height());
397 Mat original = original1.clone();
398 Imgproc.adaptiveThreshold(original1, original,255, Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C,Imgproc.THRESH_BINARY_INV, 15, THRESHOLD_C);
399 Mat test = original.clone();
400 //************************************
401 //Large Object Removal
402 //************************************
403 Mat srcLOR = original.clone();
404 Mat maskLOR = new Mat();
405 Mat dstLOR = new Mat();
406
407 //denoize
408 Mat denoize = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(5,5));
409 Imgproc.morphologyEx(srcLOR,maskLOR, Imgproc.MORPH_OPEN, denoize);
410
411 //close up gaps
412 Mat gapCloser = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(5,5));
413 Imgproc.morphologyEx(maskLOR,maskLOR,Imgproc.MORPH_CLOSE, gapCloser);
414
415 //Isolate large items
416 Mat isolateLarge = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(8, 8));
417 Imgproc.morphologyEx(maskLOR,maskLOR,Imgproc.MORPH_OPEN, isolateLarge);
418
419 //Remove large items from image
420 Core.bitwise_not(maskLOR,maskLOR);
421 srcLOR.copyTo(dstLOR, maskLOR);
422
423 //****************************************
424 //Small object removal (SOR)
425 //****************************************
426
427 Mat srcSOR = dstLOR.clone();
428 Mat maskSOR = new Mat();
429 Mat dstSOR = new Mat();
430
431 Mat startSOR =Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(7,7));
432 Imgproc.morphologyEx(srcSOR,maskSOR, Imgproc.MORPH_OPEN, startSOR);
433
434 Mat highlightSmall = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(7,7));
435 Imgproc.dilate(maskSOR, maskSOR, highlightSmall);
436
437
438/* Mat isolateSmall =Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(10,10));
439 Imgproc.morphologyEx(maskSOR,maskSOR,Imgproc.MORPH_CLOSE, isolateSmall);
440 imageViewer("13 isolate small - mask", maskSOR);
441*/
442
443 //Remove small items from image
444 Core.bitwise_not(maskSOR, maskSOR);
445 srcSOR.copyTo(dstSOR, maskSOR);
446
447
448 //****************************************
449 //start staff line detection
450 //****************************************
451
452 Mat kernelErode = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(15,2)); //10,2
453 Imgproc.erode(dstSOR,test,kernelErode);
454
455
456 Mat kernelDilate = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(10,4)); //20,3
457 Imgproc.dilate(test,test,kernelDilate);
458
459
460 Mat kernelClose = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(10,4)); //4,4
461 Imgproc.morphologyEx(test, test, Imgproc.MORPH_CLOSE, kernelClose);
462
463
464
465 Mat kernelErode02 = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(10,4)); //10,1
466 Imgproc.erode(test,test,kernelErode02);
467
468
469 //********************************************************************************
470 //DETECT OUTLINE AND FIND AREA OF THESE LINES.
471 //********************************************************************************
472 ArrayList<MatOfPoint> contours = new ArrayList<MatOfPoint>();
473 ArrayList<MatOfPoint> largeContours = new ArrayList<MatOfPoint>();
474 ArrayList<MatOfPoint> postContours = new ArrayList<MatOfPoint>();
475 Mat hierarchy = new Mat();
476
477 //PARAMETERS: input image, output array of arrays, output array, contour retrieval mode, contour approximation method.
478 //(contours) output array of arrays: Detected contours. Each contour is stored as a vector of points
479 //(hierarchy) output array: Optional output vector, containing information about the image topology.
480 //https://docs.opencv.org/3.3.1/d3/dc0/group__imgproc__shape.html#ga17ed9f5d79ae97bd4c7cf18403e1689a
481
482 Imgproc.findContours(test, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
483
484 System.out.println(contours.size());
485 //Draw contours and record areas
486 Mat allContoursFound = Mat.zeros(test.size(), CvType.CV_8UC3);
487 Mat largeContoursFound = allContoursFound.clone() ;
488 Mat postContoursFound = allContoursFound.clone();
489 int areaCounter = 0;
490
491 //Have created a preprocess to remove large objects.
492 //Need to now finalized Classifier, re try area detection.
493 //Paths to take - rectangle boxes around detected contours over threshold (area or perimeter)
494 //Just use area and periemter to determine if sheet music
495 //Discuss with david before weekend perhaps?
496
497 Imgproc.drawContours(allContoursFound, contours, -1, new Scalar(0, 255, 0), 1); //USES LINE_8
498 for (int i = 0; i < contours.size(); i++) {
499 double area = Imgproc.contourArea(contours.get(i));
500 if(area > 100) {
501 //System.out.println("AREA: " + area);
502 Imgproc.drawContours(largeContoursFound, contours, i, new Scalar(255, 0, 0), FILLED);
503 //create list of large coutours found
504 largeContours.add(contours.get(i));
505 }
506 }
507
508 //*****************************************************************
509 //Circles and centres on processed images
510 //*****************************************************************
511
512 //Init arrays
513 Mat circleOutput = allContoursFound.clone();
514 MatOfPoint2f[] contoursPoly = new MatOfPoint2f[largeContours.size()];
515 Point[] centers = new Point[largeContours.size()];
516 float[][] radius = new float[largeContours.size()][1];
517
518 //Fill arrays
519 for (int i = 0; i < largeContours.size(); i++) {
520 contoursPoly[i] = new MatOfPoint2f();
521 Imgproc.approxPolyDP(new MatOfPoint2f(largeContours.get(i).toArray()), contoursPoly[i], 1, true);
522 centers[i] = new Point();
523 Imgproc.minEnclosingCircle(contoursPoly[i], centers[i], radius[i]);
524
525 }
526 //Draw circle for each large contour
527 for (int i = 0; i < largeContours.size(); i++) {
528 Imgproc.circle(circleOutput, centers[i], (int) radius[i][0],new Scalar(255, 0, 0), 1);
529 }
530
531
532 //********************************************************************************
533 //Centroids - Everything must be to scale
534 //********************************************************************************
535
536 ArrayList<Moments> mu = new ArrayList<Moments>(largeContours.size());
537 Mat centreOutput = Mat.zeros(largeContoursFound.size(), CvType.CV_8UC3);
538 for (int i = 0; i < largeContours.size(); i++) {
539 mu.add(i, Imgproc.moments(largeContours.get(i), false));
540 Moments p = mu.get(i);
541 int x = (int) (p.get_m10() / p.get_m00());
542 int y = (int) (p.get_m01() / p.get_m00());
543 Imgproc.circle(centreOutput, new Point(x, y), 4, new Scalar(255, 255, 255), 30);
544 }
545
546 //***********************************************
547 //PostProcessing - Morphology Classifier
548 // Use dilation to "Connect the dots"
549 // Testing showed the centroids were clustered together
550 // Then use area or perimeter as a classifier filter
551 //***********************************************
552
553 Mat postDilate = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(150,15));
554 Imgproc.dilate(centreOutput,centreOutput,postDilate);
555
556 Mat postClose = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(10,4)); //4,4
557 Imgproc.morphologyEx(centreOutput, centreOutput, Imgproc.MORPH_CLOSE, postClose);
558
559 Mat postDenoize = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(100,100));
560 Imgproc.morphologyEx(centreOutput,centreOutput, Imgproc.MORPH_OPEN, postDenoize);
561
562 //Find area
563 Mat centreOutputGrey = new Mat();
564 Imgproc.cvtColor(centreOutput, centreOutputGrey, Imgproc.COLOR_RGB2GRAY);
565 Imgproc.findContours(centreOutputGrey, postContours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
566
567 for (int i = 0; i < postContours.size(); i++) {
568 double area = Imgproc.contourArea(postContours.get(i));
569 if(area > THRESHOLD_AREA_SIZE) {
570 //System.err.println("POST AREA: " + area);
571 Imgproc.drawContours(postContoursFound, postContours, i, new Scalar(0, 255, 0), FILLED);
572 areaCounter++;
573 }
574 }
575 //Classifier Calculation
576 if(areaCounter >= THRESHOLD_AREA_COUNT){
577 returnVariables.setBoolean(true);
578 returnVariables.setInteger(areaCounter);
579 }
580 }
581 catch(Exception e){
582 System.err.println(e);
583 }
584 return returnVariables;
585 }
586 private static Pair Algorithm_Morphology(String filename){
587 System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
588 Pair returnVariables = new Pair();
589 int areaCounter=0;
590 Mat original = Imgcodecs.imread(filename, Imgcodecs.IMREAD_GRAYSCALE);
591 Mat binarizedOriginal = original.clone();
592 Imgproc.adaptiveThreshold(original, binarizedOriginal,255, Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C,Imgproc.THRESH_BINARY_INV, 15, THRESHOLD_C);
593 try{
594 //************************************
595 //1. Large Object Remover
596 //************************************
597 Mat srcLOR = binarizedOriginal.clone();
598 Mat maskLOR = new Mat();
599 Mat dstLOR = new Mat();
600
601 //Remove small objects in prep for masking (De-Noise)
602 Mat removeSmallLOR = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(5,5));
603 Imgproc.morphologyEx(srcLOR,maskLOR, Imgproc.MORPH_OPEN, removeSmallLOR);
604
605 //Heal the large items
606 Mat healLOR = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(25,25));
607 Imgproc.morphologyEx(maskLOR,maskLOR, Imgproc.MORPH_CLOSE, healLOR);
608
609 //IsolateLarge
610 Mat isolateLargeLOR = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(30,30));
611 Imgproc.morphologyEx(maskLOR,maskLOR, Imgproc.MORPH_OPEN, isolateLargeLOR);
612
613 Core.bitwise_not(maskLOR,maskLOR);
614 srcLOR.copyTo(dstLOR, maskLOR);
615
616 Mat base = binarizedOriginal.clone();
617 //***********************************
618 //3. Isolate straight lines
619 //***********************************
620 //Heal lines
621 Mat healISL = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(82,1));
622 Imgproc.morphologyEx(dstLOR,base, Imgproc.MORPH_OPEN, healISL);
623
624 //Make White Blobs
625 Mat kernelOpen = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(4,1));
626 Imgproc.morphologyEx(base,base,Imgproc.MORPH_OPEN, kernelOpen);
627
628 Mat kernelDilateAgain = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(1,10));
629 Imgproc.dilate(base, base, kernelDilateAgain);
630
631 Mat kernelCloseAgain = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(12,50));
632 Imgproc.morphologyEx(base,base,Imgproc.MORPH_CLOSE, kernelCloseAgain);
633
634 //***********************************
635 //4. Find 'Clusters'
636 // Need to find areas, using bounding boxes
637 // Find how tall the bounding box is, if its taller than 'x' then classify as Sheet Music
638 //***********************************
639
640 //*****************************************************************
641 //4.1 Prep Rectangles on processed images
642 //*****************************************************************
643 ArrayList<MatOfPoint> contours = new ArrayList<MatOfPoint>();
644 Mat hierarchy = new Mat();
645 Imgproc.findContours(base, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
646 //Draw contours and record areas
647 Mat allContoursFound = Mat.zeros(base.size(), CvType.CV_8UC3);
648 Imgproc.drawContours(allContoursFound, contours, -1, new Scalar(0, 255, 0), 1); //USES LINE_8
649 //Init arrays
650 MatOfPoint2f[] contoursPoly = new MatOfPoint2f[contours.size()];
651 Rect[] boundRect = new Rect[contours.size()];
652
653 //Fill arrays
654 for (int i = 0; i < contours.size(); i++) {
655 contoursPoly[i] = new MatOfPoint2f();
656 Imgproc.approxPolyDP(new MatOfPoint2f(contours.get(i).toArray()), contoursPoly[i], 1, true);
657 boundRect[i] = Imgproc.boundingRect(new MatOfPoint(contoursPoly[i].toArray()));
658 }
659 //Draw circle for each large contour
660 //MAKE THE COMPARING VALUES GLOBAL CONSTANTS
661 for (int i = 0; i < contours.size(); i++) {
662 if(boundRect[i].height > 100){
663 if(boundRect[i].width > 300){
664 areaCounter++;
665 }
666 }
667 }
668
669 //Classifier Calculation
670 if(areaCounter >= THRESHOLD_AREA_COUNT){
671 returnVariables.setBoolean(true);
672 returnVariables.setInteger(areaCounter);
673 }
674 }
675 catch(Exception e){
676 System.err.println(e);
677 }
678 return returnVariables;
679 }
680 //******************
681 //CLASSIFIER FUNCTIONS
682 //******************
683
684 private static boolean Classifier_LineCounter(int lineCount){
685 if(lineCount>MINLINECOUNT){return true;}
686 else{return false;}
687 }
688 private static Pair Classifier_ClusterDetection(ArrayList<StartAndEndPoint> linePointsArray){
689
690 Pair returnPair = new Pair();
691 ArrayList<StartAndEndPoint> closeLinePts = new ArrayList<StartAndEndPoint>();
692 ArrayList<StartAndEndPoint[]> clusterPtArray = new ArrayList<StartAndEndPoint[]>();
693 int clusterCount = 0;
694 try {
695
696 if(linePointsArray.size()> 1) {
697 for (int i = 0; i < linePointsArray.size(); i++){
698 for (int j = 0; j < linePointsArray.size(); j++) {
699 if(Math.abs(linePointsArray.get(j).getP1().y - linePointsArray.get(i).getP1().y) < 5){
700 if(linePointsArray.get(j).getP1().y != linePointsArray.get(i).getP1().y){
701 closeLinePts.add(linePointsArray.get(i));
702 }
703 }
704 }
705 }
706
707 Collections.sort(closeLinePts, new Comparator<StartAndEndPoint>() {
708 @Override
709 public int compare(StartAndEndPoint p1, StartAndEndPoint p2) {
710 return (int)(p1.getP1().y - p2.getP1().y);
711 }
712 });
713
714 closeLinePts = removeDuplicates(closeLinePts);
715
716 if(closeLinePts.size() >= 4) {
717 for(int i= 0; i < closeLinePts.size(); i++){
718 if(i + 4 >= closeLinePts.size()){
719 break;
720 }
721 else{
722 StartAndEndPoint[] tempPtArray = new StartAndEndPoint[4];
723 tempPtArray[0] = closeLinePts.get(i);
724 tempPtArray[1] = closeLinePts.get(i + 1);
725 tempPtArray[2] = closeLinePts.get(i + 2);
726 tempPtArray[3] = closeLinePts.get(i + 3);
727 if(ClusterCheck(tempPtArray)){
728 clusterPtArray.add(tempPtArray);
729 if((i + 4 < closeLinePts.size())){
730 i = i+4;
731 }
732 else{
733 break;
734 }
735 }
736 }
737 }
738 }
739
740 /* for(StartAndEndPoint pt : linePointsArray){
741 for(int i =0; i < clusterPtArray.size(); i++){
742 for(StartAndEndPoint item : clusterPtArray.get(i)) {
743 if (item.getP1().y == pt.getP1().y){
744 Imgproc.line(clustersFoundRGB, pt.getP1(), pt.getP2(), new Scalar(0, 255, 0), 1, Imgproc.LINE_4, 0);
745 }
746 }
747 }
748 }*/
749
750 clusterCount = clusterPtArray.size();
751 //SETUP RETURN ARRAY
752 if(clusterCount >= 1){
753 returnPair.setBoolean(true);
754 returnPair.setInteger(clusterCount);
755 //returnArray.add(clustersFoundRGB);
756 }
757 else{
758 returnPair.setBoolean(false);
759 returnPair.setInteger(clusterCount);
760 //returnArray.add(clustersFoundRGB);
761 }
762 }
763 }
764 catch (Exception e) {
765 System.err.println(e.getMessage());
766 }
767 return returnPair;
768 }
769
770 //******************
771 //INTERNAL FUNCTIONS
772 //******************
773
774 public static <T> ArrayList<T> removeDuplicates(ArrayList<T> list) {
775 //DIRECTLY COPIED//DIRECTLY COPIED//DIRECTLY COPIED//DIRECTLY COPIED//DIRECTLY COPIED//DIRECTLY COPIED
776 // Function to remove duplicates from an ArrayList
777 // Create a new ArrayList
778 ArrayList<T> newList = new ArrayList<T>();
779 // Traverse through the first list
780 for (T element : list) {
781 // If this element is not present in newList
782 // then add it
783 if (!newList.contains(element)) {
784 newList.add(element);
785 }
786 }
787 // return the new list
788 return newList;
789 //DIRECTLY COPIED//DIRECTLY COPIED//DIRECTLY COPIED//DIRECTLY COPIED//DIRECTLY COPIED//DIRECTLY COPIED
790 }
791 public static double VarianceCalc(StartAndEndPoint parseArray[]){
792 double sum =0;
793 double temp =0;
794 double mean, variance;
795 int size = parseArray.length;
796 //Calculate sum of array
797 for(int i =0; i < parseArray.length; i++){
798 sum += parseArray[i].getP1().y;
799 }
800 //Calculate mean of array
801 mean = sum/parseArray.length;
802 //Calculate variants
803 for(int i =0; i < size; i++){
804 temp += Math.pow((parseArray[i].getP1().y-mean),2);
805 }
806 variance = Math.abs(temp/(size -1));
807 //System.out.println("VARIANCE: " + variance);
808 return variance;
809 }
810 public static Boolean lineComparison(double baseLineS, double compareLineS, double compareLineE ){
811 //System.out.print("Comparing baseLineS: " + baseLineS + " with compareLineE: " + compareLineE + " and compareLineS: " + compareLineS);
812 if(baseLineS < compareLineE && baseLineS > compareLineS){
813 return true;
814 }
815 return false;
816 }
817 public static Boolean ClusterCheck(StartAndEndPoint parseArray[]){
818 try {
819 //System.out.println("LENGTH: " + parseArray.length);
820 //MAKE THREE COMPARISONS
821 //After clusters have been found.
822 //Check if their x positions intersect
823 //Logic being
824 //(L1.S < L2.E && L1.S > L2.S)
825 //or
826 //(L2.S < L1.E && L2.S > L1.S)
827 //Variance is using Start of line point.
828 //USING VARIANTS
829 double variance = VarianceCalc(parseArray);
830 Boolean consistent = false;
831 if (variance <= CLUSTER_DISTANCE_MAX && variance > CLUSTER_DISTANCE_MIN) {
832
833 for (int i = 0; i < parseArray.length - 1; i++) {
834 //System.out.println(i);
835 double l1_S = parseArray[i].getP1().x;
836 double l1_E = parseArray[i].getP2().x;
837 double l2_S = parseArray[i + 1].getP1().x;
838 double l2_E = parseArray[i + 1].getP2().x;
839
840 //Check which starts after
841 if (l1_S >= l2_S) {
842 //baseLineStart is l1_S (call with lineComparison)
843 consistent = lineComparison(l1_S, l2_S, l2_E);
844 } else if (l2_S > l1_S) {
845 //baseLineStart is l2_S (call with lineComparison)
846 consistent = lineComparison(l2_S, l1_S, l1_E);
847 } else {
848 System.err.println("An error, comparing l1_S and l2_S, has occurred");
849 }
850
851 //Check if false was returned;
852 if (consistent == false) {
853 /*System.out.print(" X positions of two lines did not overlap each other:" + '\t');
854 System.out.print("l1_S: " + l1_S + '\t');
855 System.out.print("l1_E: " + l1_E + '\t');
856 System.out.print("l2_S: " + l2_S + '\t');
857 System.out.print("l2_E: " + l2_E);
858 System.out.println(" ");*/
859 return false;
860 }
861 }
862 //Have been through for loop, maintaining consistent being true.
863 //Have also meet the variance MIN and MAX requirement. Therefore it is a cluster
864 return true;
865 }
866 //System.out.println("Did not meet Cluster Distance Min and Max requirements, Variance = " + variance);
867 return false;
868 }
869 catch (Exception e){
870 System.err.println(" "+e.getMessage());
871 return false;
872 }
873 }
874}
Note: See TracBrowser for help on using the repository browser.