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

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

final01. Need Map results still

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