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

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

starting to implement terminal version of new morphology. need to fix. return bariables always returning null

File size: 34.9 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 //Split output by tab for processing in next java program
185 //imageFilename = 1, result = 3, classifierType = 4
186
187 switch (classifierType) {
188 case "count":
189 enableLineClustering = false;
190 algorithmResult = Algorithm_HoughLinesP_Single(imageFilename, enableLineClustering);
191 bw.write("Filename:" + '\t' + imageFilename + '\t' + "Classified as:" + '\t' + algorithmResult.getBoolean() + '\t' + "Number of lines:" + '\t' + algorithmResult.getInteger() + '\t' + classifierType + '\n');
192 break;
193 case "cluster":
194 enableLineClustering = true;
195 algorithmResult = Algorithm_HoughLinesP_Single(imageFilename, enableLineClustering);
196 bw.write("Filename:" + '\t' + imageFilename + '\t' + "Classified as:" + '\t' + algorithmResult.getBoolean() + '\t' + "Number of lines:" + '\t' + algorithmResult.getInteger() + '\t' + classifierType + '\n');
197 break;
198 case "combo":
199 algorithmResult = Algorithm_HoughLinesP_Combo(imageFilename);
200 bw.write("Filename:" + '\t' + imageFilename + '\t' + "Classified as:" + '\t' + algorithmResult.getBoolean() + '\t' + "Number of lines:" + '\t' + algorithmResult.getInteger() + '\t' + classifierType + '\n');
201 break;
202 case "morphology":
203 algorithmResult = Algorithm_MorphologyOLD(imageFilename);
204 bw.write("Filename:" + '\t' + imageFilename + '\t' + "Classified as:" + '\t' + algorithmResult.getBoolean() + '\t' + "Number of areas:" + '\t' + algorithmResult.getInteger() + '\t' + classifierType + '\n');
205 break;
206 default:
207 System.out.println("unknown algorithm");
208 break;
209 }
210
211 bw.close();
212 }
213 } catch (Exception e) {
214 System.err.println(e);
215 }
216 }
217
218 //******************
219 //ALGORITHM FUNCTIONS
220 //******************
221 private static Pair Algorithm_HoughLinesP_Single(String filename, Boolean enableLineClusterDetection){
222 System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
223 Boolean isSheetMusic = null;
224 Pair returnVariables = new Pair();
225 try{
226 //Variables
227 int horizontalLineCount =0;
228 Mat edgesDetected = new Mat();
229 Mat edgesDetectedRGB = new Mat();
230 Mat edgesExtra = new Mat();
231 Mat edgesDetectedRGBProb;
232 ArrayList<StartAndEndPoint> pointArrayList = new ArrayList<StartAndEndPoint>();
233
234 //****************EXPLANATION**************************************************
235 //
236 //Load an image in greyscale
237 //Additional matrix to hold results of line detection
238 //Inversed Binarization of image
239 //Detect lines in image
240 //Go thru every line detected and check its gradient is less than SLOPEGRADIENT
241 //
242 //****************EXPLANATION**************************************************
243
244 Mat original = Imgcodecs.imread(filename, Imgcodecs.IMREAD_GRAYSCALE);
245 Mat linesP = new Mat(); //will hold the results of the detection
246 Imgproc.adaptiveThreshold(original, edgesDetected,255, Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C,Imgproc.THRESH_BINARY_INV,15, THRESHOLD_C);
247 double minLineLength = edgesDetected.size().width/8;
248 Imgproc.HoughLinesP(edgesDetected, linesP, 1, Math.PI / 720, HOUGHLINEP_THRESHOLD, minLineLength, MAXLINEGAP);
249 for (int x = 0; x < linesP.rows(); x++) {
250 double[] l = linesP.get(x, 0);
251 Point p1 = new Point(l[0], l[1]);
252 Point p2 = new Point(l[2], l[3]);
253 double m = Math.abs(p2.y - p1.y)/(p2.x - p1.x);
254 if(m<SLOPEGRADIENT) {
255 horizontalLineCount++;
256 pointArrayList.add(new StartAndEndPoint(p1, p2));
257 }
258 }
259
260 //Calculate if its sheet music or not
261 if(enableLineClusterDetection ==true){returnVariables = Classifier_ClusterDetection(pointArrayList);}
262 else {
263 isSheetMusic = Classifier_LineCounter(horizontalLineCount);
264 returnVariables.setBoolean(isSheetMusic);
265 returnVariables.setInteger(horizontalLineCount);
266 }
267 }
268 catch(Exception e){
269 System.err.println(e);
270 }
271 return returnVariables;
272 }
273 private static Pair Algorithm_HoughLinesP_Combo(String filename){
274 System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
275 Boolean isSheetMusic = null;
276 Pair returnVariables = new Pair();
277 try{
278 //Variables
279 int horizontalLineCount =0;
280 Mat edgesDetected = new Mat();
281 Mat edgesDetectedRGB = new Mat();
282 Mat edgesExtra = new Mat();
283 Mat edgesDetectedRGBProb;
284 ArrayList<StartAndEndPoint> pointArrayList = new ArrayList<StartAndEndPoint>();
285
286 //****************EXPLANATION**************************************************
287 //
288 //Load an image in greyscale
289 //Additional matrix to hold results of line detection
290 //Inversed Binarization of image
291 //Detect lines in image
292 //Go thru every line detected and check its gradient is less than SLOPEGRADIENT
293 //
294 //****************EXPLANATION**************************************************
295
296 Mat original = Imgcodecs.imread(filename, Imgcodecs.IMREAD_GRAYSCALE);
297 Mat linesP = new Mat(); //will hold the results of the detection
298 Imgproc.adaptiveThreshold(original, edgesDetected,255, Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C,Imgproc.THRESH_BINARY_INV,15, THRESHOLD_C);
299 double minLineLength = edgesDetected.size().width/8;
300 Imgproc.HoughLinesP(edgesDetected, linesP, 1, Math.PI / 720, HOUGHLINEP_THRESHOLD, minLineLength, MAXLINEGAP);
301 for (int x = 0; x < linesP.rows(); x++) {
302 double[] l = linesP.get(x, 0);
303 Point p1 = new Point(l[0], l[1]);
304 Point p2 = new Point(l[2], l[3]);
305 double m = Math.abs(p2.y - p1.y)/(p2.x - p1.x);
306 if(m<SLOPEGRADIENT) {
307 horizontalLineCount++;
308 pointArrayList.add(new StartAndEndPoint(p1, p2));
309 }
310 }
311
312 //Calculate if its sheet music or not
313 isSheetMusic = Classifier_LineCounter(horizontalLineCount);
314 if(isSheetMusic == true){
315 returnVariables.setBoolean(isSheetMusic);
316 returnVariables.setInteger(horizontalLineCount);
317 }
318 else if (isSheetMusic == false){
319 returnVariables = Classifier_ClusterDetection(pointArrayList);
320 }
321 }
322 catch(Exception e){
323 System.err.println(e);
324 }
325 return returnVariables;
326 }
327 private static Pair Algorithm_MorphologyOLD(String filename){
328
329 System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
330 Boolean isSheetMusic = null;
331 Pair returnVariables = new Pair();
332 try{
333 //Variables
334 int areaCounter = 0;
335 Mat edgesDetectedRGB = new Mat();
336 Mat original = Imgcodecs.imread(filename, Imgcodecs.IMREAD_GRAYSCALE);
337
338 ArrayList<MatOfPoint> contours = new ArrayList<MatOfPoint>();
339 Mat hierarchy = new Mat();
340
341 //Thresholds
342 Imgproc.adaptiveThreshold(original, original,255, Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C,Imgproc.THRESH_BINARY_INV, 15, THRESHOLD_C);
343 Mat processed = original.clone();
344 //Morphological Processing
345 Mat kernelErode = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(10,1));
346 Imgproc.erode(processed,processed,kernelErode);
347
348 Mat kernelDilate = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(20,3));
349 Imgproc.dilate(processed,processed,kernelDilate);
350
351 Mat kernelOpening = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(4,4));
352 Imgproc.morphologyEx(processed, processed, Imgproc.MORPH_CLOSE, kernelOpening);
353
354 Mat kernelErode02 = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(8,8));
355 Imgproc.erode(processed,processed,kernelErode02);
356
357 //Detect contours
358 Imgproc.findContours(processed, contours, hierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE);
359
360 //Record areas
361 for (int i = 0; i < contours.size(); i++) {
362 double area = Imgproc.contourArea(contours.get(i));
363 //Check if area detected meets threshold
364 if(area > THRESHOLD_AREA_SIZE) {
365 areaCounter++;
366 //System.out.println("AREA: " + area);
367 }
368 }
369
370
371
372
373
374
375 //Calculates if sheet music or not
376 if(areaCounter >= THRESHOLD_AREA_COUNT){
377 returnVariables.setBoolean(true);
378 returnVariables.setInteger(areaCounter);
379 }
380 }
381 catch(Exception e){
382 System.err.println(e);
383 }
384 return returnVariables;
385 }
386 private static Pair Algorithm_Morphology(String filename){
387
388 System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
389 Boolean isSheetMusic = null;
390 Pair returnVariables = new Pair();
391 try{
392 int FILLED = -1;
393 //Display Original
394 //imageViewer("original", original1);
395 Mat original = Imgcodecs.imread(filename, Imgcodecs.IMREAD_GRAYSCALE);
396 Mat test = original.clone();
397 //imageViewer("00 Inverse Binarized Original", test);
398
399
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 //imageViewer("01 Denoize - mask", maskLOR);
411
412 //close up gaps
413 Mat gapCloser = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(5,5));
414 Imgproc.morphologyEx(maskLOR,maskLOR,Imgproc.MORPH_CLOSE, gapCloser);
415 //imageViewer("02 gap closer - mask", maskLOR);
416
417 //Isolate large items
418 Mat isolateLarge = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(8, 8));
419 Imgproc.morphologyEx(maskLOR,maskLOR,Imgproc.MORPH_OPEN, isolateLarge);
420 //imageViewer("03 Isolate Large - mask", maskLOR);
421
422 //Remove large items from image
423 Core.bitwise_not(maskLOR,maskLOR);
424 srcLOR.copyTo(dstLOR, maskLOR);
425 //imageViewer("04 Large Items Removed", dstLOR);
426
427 //****************************************
428 //Small object removal (SOR)
429 //****************************************
430
431 Mat srcSOR = dstLOR.clone();
432 Mat maskSOR = new Mat();
433 Mat dstSOR = new Mat();
434
435 Mat startSOR =Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(7,7));
436 Imgproc.morphologyEx(srcSOR,maskSOR, Imgproc.MORPH_OPEN, startSOR);
437 //imageViewer("11 show small - mask", maskSOR);
438
439 Mat highlightSmall = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(7,7));
440 Imgproc.dilate(maskSOR, maskSOR, highlightSmall);
441 //imageViewer("12 highlight small - mask", maskSOR);
442
443/* Mat isolateSmall =Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(10,10));
444 Imgproc.morphologyEx(maskSOR,maskSOR,Imgproc.MORPH_CLOSE, isolateSmall);
445 imageViewer("13 isolate small - mask", maskSOR);
446*/
447
448 //Remove small items from image
449 Core.bitwise_not(maskSOR, maskSOR);
450 srcSOR.copyTo(dstSOR, maskSOR);
451 //imageViewer("14 Small Items Removed", dstSOR);
452
453
454 //****************************************
455 //start staff line detection
456 //****************************************
457
458 Mat kernelErode = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(15,2)); //10,2
459 Imgproc.erode(dstSOR,test,kernelErode);
460 //imageViewer("21 Erode plus pre", test);
461
462 Mat kernelDilate = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(10,4)); //20,3
463 Imgproc.dilate(test,test,kernelDilate);
464 //imageViewer("22 Dilate", test);
465
466 Mat kernelClose = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(10,4)); //4,4
467 Imgproc.morphologyEx(test, test, Imgproc.MORPH_CLOSE, kernelClose);
468 //imageViewer("23 Close", test);
469
470
471 Mat kernelErode02 = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(10,4)); //10,1
472 Imgproc.erode(test,test,kernelErode02);
473 //imageViewer("24 Erode (Final)", test);
474
475 //********************************************************************************
476 //DETECT OUTLINE AND FIND AREA OF THESE LINES.
477 //********************************************************************************
478 ArrayList<MatOfPoint> contours = new ArrayList<MatOfPoint>();
479 ArrayList<MatOfPoint> largeContours = new ArrayList<MatOfPoint>();
480 ArrayList<MatOfPoint> postContours = new ArrayList<MatOfPoint>();
481 Mat hierarchy = new Mat();
482
483 //PARAMETERS: input image, output array of arrays, output array, contour retrieval mode, contour approximation method.
484 //(contours) output array of arrays: Detected contours. Each contour is stored as a vector of points
485 //(hierarchy) output array: Optional output vector, containing information about the image topology.
486 //https://docs.opencv.org/3.3.1/d3/dc0/group__imgproc__shape.html#ga17ed9f5d79ae97bd4c7cf18403e1689a
487
488 Imgproc.findContours(test, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
489
490 System.out.println(contours.size());
491 //Draw contours and record areas
492 Mat allContoursFound = Mat.zeros(test.size(), CvType.CV_8UC3);
493 Mat largeContoursFound = allContoursFound.clone() ;
494 Mat postContoursFound = allContoursFound.clone();
495 int areaCounter = 0;
496
497 //Have created a preprocess to remove large objects.
498 //Need to now finalized Classifier, re try area detection.
499 //Paths to take - rectangle boxes around detected contours over threshold (area or perimeter)
500 //Just use area and periemter to determine if sheet music
501 //Discuss with david before weekend perhaps?
502
503 Imgproc.drawContours(allContoursFound, contours, -1, new Scalar(0, 255, 0), 1); //USES LINE_8
504 for (int i = 0; i < contours.size(); i++) {
505 double area = Imgproc.contourArea(contours.get(i));
506 if(area > 100) {
507 //System.out.println("AREA: " + area);
508 Imgproc.drawContours(largeContoursFound, contours, i, new Scalar(255, 0, 0), FILLED);
509 //create list of large coutours found
510 largeContours.add(contours.get(i));
511 }
512 }
513 //imageViewer("80 All Contours found", allContoursFound);
514 //imageViewer("81 Large Contours Found", largeContoursFound);
515
516 //*****************************************************************
517 //Circles and centres on processed images
518 //*****************************************************************
519
520 //Init arrays
521 Mat circleOutput = allContoursFound.clone();
522 MatOfPoint2f[] contoursPoly = new MatOfPoint2f[largeContours.size()];
523 Point[] centers = new Point[largeContours.size()];
524 float[][] radius = new float[largeContours.size()][1];
525
526 //Fill arrays
527 for (int i = 0; i < largeContours.size(); i++) {
528 contoursPoly[i] = new MatOfPoint2f();
529 Imgproc.approxPolyDP(new MatOfPoint2f(largeContours.get(i).toArray()), contoursPoly[i], 1, true);
530 centers[i] = new Point();
531 Imgproc.minEnclosingCircle(contoursPoly[i], centers[i], radius[i]);
532
533 }
534 //Draw circle for each large contour
535 for (int i = 0; i < largeContours.size(); i++) {
536 Imgproc.circle(circleOutput, centers[i], (int) radius[i][0],new Scalar(255, 0, 0), 1);
537 }
538 //imageViewer("82 Circles found", circleOutput);
539
540 //********************************************************************************
541 //Centroids - Everything must be to scale
542 //********************************************************************************
543
544 ArrayList<Moments> mu = new ArrayList<Moments>(largeContours.size());
545 Mat centreOutput = Mat.zeros(largeContoursFound.size(), CvType.CV_8UC3);
546 for (int i = 0; i < largeContours.size(); i++) {
547 mu.add(i, Imgproc.moments(largeContours.get(i), false));
548 Moments p = mu.get(i);
549 int x = (int) (p.get_m10() / p.get_m00());
550 int y = (int) (p.get_m01() / p.get_m00());
551 Imgproc.circle(centreOutput, new Point(x, y), 4, new Scalar(255, 255, 255), 30);
552 }
553 //imageViewer("83 Centres found", centreOutput);
554
555
556 //***********************************************
557 //PostProcessing - Morphology Classifier
558 // Use dilation to "Connect the dots"
559 // Testing showed the centroids were clustered together
560 // Then use area or perimeter as a classifier filter
561 //***********************************************
562
563 Mat postDilate = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(150,15));
564 Imgproc.dilate(centreOutput,centreOutput,postDilate);
565 //imageViewer("91 PostDilated", centreOutput);
566
567 Mat postClose = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(10,4)); //4,4
568 Imgproc.morphologyEx(centreOutput, centreOutput, Imgproc.MORPH_CLOSE, postClose);
569 //imageViewer("92 PostClose", centreOutput);
570
571 Mat postDenoize = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(100,100));
572 Imgproc.morphologyEx(centreOutput,centreOutput, Imgproc.MORPH_OPEN, postDenoize);
573 //imageViewer("93 PostDenoize", centreOutput);
574
575 //Mat postOutline = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(50,50));
576 //Imgproc.morphologyEx(centreOutput, centreOutput, Imgproc.MORPH_GRADIENT, postOutline);
577
578 //Find area
579 Mat centreOutputGrey = new Mat();
580 Imgproc.cvtColor(centreOutput, centreOutputGrey, Imgproc.COLOR_RGB2GRAY);
581 Imgproc.findContours(centreOutputGrey, postContours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
582
583 for (int i = 0; i < postContours.size(); i++) {
584 double area = Imgproc.contourArea(postContours.get(i));
585 if(area > THRESHOLD_AREA_SIZE) {
586 System.out.println("POST AREA: " + area + "AREA COUNTER: " + areaCounter);
587 //Imgproc.drawContours(postContoursFound, postContours, i, new Scalar(0, 255, 0), FILLED);
588 areaCounter++;
589 }
590 }
591
592 //imageViewer("93 PostEND", postContoursFound);
593
594 //Calculates if sheet music or not
595 if(areaCounter >= THRESHOLD_AREA_COUNT){
596 returnVariables = new Pair(true, areaCounter);
597 //returnVariables.setBoolean(true);
598 //returnVariables.setInteger(areaCounter);
599 System.out.println("TEST RETURN VARIABLES: "+ returnVariables.toString());
600 }
601
602 }
603 catch(Exception e){
604 System.err.println(e);
605 }
606 return returnVariables;
607 }
608 //******************
609 //CLASSIFIER FUNCTIONS
610 //******************
611
612 private static boolean Classifier_LineCounter(int lineCount){
613 if(lineCount>MINLINECOUNT){return true;}
614 else{return false;}
615 }
616 private static Pair Classifier_ClusterDetection(ArrayList<StartAndEndPoint> linePointsArray){
617
618 Pair returnPair = new Pair();
619 ArrayList<StartAndEndPoint> closeLinePts = new ArrayList<StartAndEndPoint>();
620 ArrayList<StartAndEndPoint[]> clusterPtArray = new ArrayList<StartAndEndPoint[]>();
621 int clusterCount = 0;
622 try {
623
624 if(linePointsArray.size()> 1) {
625 for (int i = 0; i < linePointsArray.size(); i++){
626 for (int j = 0; j < linePointsArray.size(); j++) {
627 if(Math.abs(linePointsArray.get(j).getP1().y - linePointsArray.get(i).getP1().y) < 5){
628 if(linePointsArray.get(j).getP1().y != linePointsArray.get(i).getP1().y){
629 closeLinePts.add(linePointsArray.get(i));
630 }
631 }
632 }
633 }
634
635 Collections.sort(closeLinePts, new Comparator<StartAndEndPoint>() {
636 @Override
637 public int compare(StartAndEndPoint p1, StartAndEndPoint p2) {
638 return (int)(p1.getP1().y - p2.getP1().y);
639 }
640 });
641
642 closeLinePts = removeDuplicates(closeLinePts);
643
644 if(closeLinePts.size() >= 4) {
645 for(int i= 0; i < closeLinePts.size(); i++){
646 if(i + 4 >= closeLinePts.size()){
647 break;
648 }
649 else{
650 StartAndEndPoint[] tempPtArray = new StartAndEndPoint[4];
651 tempPtArray[0] = closeLinePts.get(i);
652 tempPtArray[1] = closeLinePts.get(i + 1);
653 tempPtArray[2] = closeLinePts.get(i + 2);
654 tempPtArray[3] = closeLinePts.get(i + 3);
655 if(ClusterCheck(tempPtArray)){
656 clusterPtArray.add(tempPtArray);
657 if((i + 4 < closeLinePts.size())){
658 i = i+4;
659 }
660 else{
661 break;
662 }
663 }
664 }
665 }
666 }
667
668 /* for(StartAndEndPoint pt : linePointsArray){
669 for(int i =0; i < clusterPtArray.size(); i++){
670 for(StartAndEndPoint item : clusterPtArray.get(i)) {
671 if (item.getP1().y == pt.getP1().y){
672 Imgproc.line(clustersFoundRGB, pt.getP1(), pt.getP2(), new Scalar(0, 255, 0), 1, Imgproc.LINE_4, 0);
673 }
674 }
675 }
676 }*/
677
678 clusterCount = clusterPtArray.size();
679 //SETUP RETURN ARRAY
680 if(clusterCount >= 1){
681 returnPair.setBoolean(true);
682 returnPair.setInteger(clusterCount);
683 //returnArray.add(clustersFoundRGB);
684 }
685 else{
686 returnPair.setBoolean(false);
687 returnPair.setInteger(clusterCount);
688 //returnArray.add(clustersFoundRGB);
689 }
690 }
691 }
692 catch (Exception e) {
693 System.err.println(e.getMessage());
694 }
695 return returnPair;
696 }
697
698 //******************
699 //INTERNAL FUNCTIONS
700 //******************
701
702 public static <T> ArrayList<T> removeDuplicates(ArrayList<T> list) {
703 //DIRECTLY COPIED//DIRECTLY COPIED//DIRECTLY COPIED//DIRECTLY COPIED//DIRECTLY COPIED//DIRECTLY COPIED
704 // Function to remove duplicates from an ArrayList
705 // Create a new ArrayList
706 ArrayList<T> newList = new ArrayList<T>();
707 // Traverse through the first list
708 for (T element : list) {
709 // If this element is not present in newList
710 // then add it
711 if (!newList.contains(element)) {
712 newList.add(element);
713 }
714 }
715 // return the new list
716 return newList;
717 //DIRECTLY COPIED//DIRECTLY COPIED//DIRECTLY COPIED//DIRECTLY COPIED//DIRECTLY COPIED//DIRECTLY COPIED
718 }
719 public static double VarianceCalc(StartAndEndPoint parseArray[]){
720 double sum =0;
721 double temp =0;
722 double mean, variance;
723 int size = parseArray.length;
724 //Calculate sum of array
725 for(int i =0; i < parseArray.length; i++){
726 sum += parseArray[i].getP1().y;
727 }
728 //Calculate mean of array
729 mean = sum/parseArray.length;
730 //Calculate variants
731 for(int i =0; i < size; i++){
732 temp += Math.pow((parseArray[i].getP1().y-mean),2);
733 }
734 variance = Math.abs(temp/(size -1));
735 //System.out.println("VARIANCE: " + variance);
736 return variance;
737 }
738 public static Boolean lineComparison(double baseLineS, double compareLineS, double compareLineE ){
739 //System.out.print("Comparing baseLineS: " + baseLineS + " with compareLineE: " + compareLineE + " and compareLineS: " + compareLineS);
740 if(baseLineS < compareLineE && baseLineS > compareLineS){
741 return true;
742 }
743 return false;
744 }
745 public static Boolean ClusterCheck(StartAndEndPoint parseArray[]){
746 try {
747 //System.out.println("LENGTH: " + parseArray.length);
748 //MAKE THREE COMPARISONS
749 //After clusters have been found.
750 //Check if their x positions intersect
751 //Logic being
752 //(L1.S < L2.E && L1.S > L2.S)
753 //or
754 //(L2.S < L1.E && L2.S > L1.S)
755 //Variance is using Start of line point.
756 //USING VARIANTS
757 double variance = VarianceCalc(parseArray);
758 Boolean consistent = false;
759 if (variance <= CLUSTER_DISTANCE_MAX && variance > CLUSTER_DISTANCE_MIN) {
760
761 for (int i = 0; i < parseArray.length - 1; i++) {
762 //System.out.println(i);
763 double l1_S = parseArray[i].getP1().x;
764 double l1_E = parseArray[i].getP2().x;
765 double l2_S = parseArray[i + 1].getP1().x;
766 double l2_E = parseArray[i + 1].getP2().x;
767
768 //Check which starts after
769 if (l1_S >= l2_S) {
770 //baseLineStart is l1_S (call with lineComparison)
771 consistent = lineComparison(l1_S, l2_S, l2_E);
772 } else if (l2_S > l1_S) {
773 //baseLineStart is l2_S (call with lineComparison)
774 consistent = lineComparison(l2_S, l1_S, l1_E);
775 } else {
776 System.err.println("An error, comparing l1_S and l2_S, has occurred");
777 }
778
779 //Check if false was returned;
780 if (consistent == false) {
781 /*System.out.print(" X positions of two lines did not overlap each other:" + '\t');
782 System.out.print("l1_S: " + l1_S + '\t');
783 System.out.print("l1_E: " + l1_E + '\t');
784 System.out.print("l2_S: " + l2_S + '\t');
785 System.out.print("l2_E: " + l2_E);
786 System.out.println(" ");*/
787 return false;
788 }
789 }
790 //Have been through for loop, maintaining consistent being true.
791 //Have also meet the variance MIN and MAX requirement. Therefore it is a cluster
792 return true;
793 }
794 //System.out.println("Did not meet Cluster Distance Min and Max requirements, Variance = " + variance);
795 return false;
796 }
797 catch (Exception e){
798 System.err.println(" "+e.getMessage());
799 return false;
800 }
801 }
802}
Note: See TracBrowser for help on using the repository browser.