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

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

updated, after unable to commit due to setup.bash being out of date. Added mainMorph for morphological development

File size: 16.2 KB
Line 
1
2import org.opencv.core.*;
3import org.opencv.core.Point;
4import org.opencv.highgui.HighGui;
5import org.opencv.imgcodecs.Imgcodecs;
6import org.opencv.imgproc.Imgproc;
7import static org.opencv.imgcodecs.Imgcodecs.imwrite;
8import java.awt.image.BufferedImage;
9import java.awt.image.DataBufferByte;
10//import java.io.File;
11//import java.io.BufferedWriter;
12//import java.io.FileWriter;
13import javax.imageio.ImageIO;
14//import java.util.logging.Logger;
15//import java.util.ArrayList;
16//import java.util.Collections.*;
17import java.util.*;
18import java.lang.*;
19import java.io.*;
20
21//REFERENCES:
22//https://docs.opencv.org/3.4.3/d9/db0/tutorial_hough_lines.
23//https://stackoverflow.com/questions/43443309/count-red-pixel-in-a-given-image
24//https://www.wikihow.com/Calculate-Percentage-in-Java
25//https://riptutorial.com/opencv/example/21963/converting-an-mat-object-to-an-bufferedimage-object
26//https://stackoverflow.com/questions/15758685/how-to-write-logs-in-text-file-when-using-java-util-logging-logger
27//https://stackoverflow.com/questions/9961292/write-to-text-file-without-overwriting-in-java
28//https://alvinalexander.com/java/edu/pj/pj010005
29//https://stackoverflow.com/questions/8557716/how-to-return-multiple-values
30
31//OUTPUT OF THIS JAVA PROGRAM FOUND IN log.txt
32//Each image processed will have an output of
33//True =classifierType + 1 + Filename + Status
34//False =classifierType + 0 + Filename + Status
35public class javaClassifierComparison {
36 //GLOBALS Constants
37 static int CLASSIFIER_HOUGHLINESP_MIN = 10;
38 static int CLASSIFIER_HOUGHLINESP_MAX = 65;
39 static int HOUGHLINEP_THRESHOLD = 10;
40 static int STANDARD_DEVIATION_THRESHOLD = 6;
41 static int MINLINECOUNT = 40;
42 static int MAXLINEGAP = 1;
43 static double THRESHOLD_C = 4;
44 static double SLOPEGRADIENT = 0.02;
45 static double CLUSTER_DISTANCE_MAX = 40;
46 static double CLUSTER_DISTANCE_MIN = 2;
47
48
49 static public class StartAndEndPoint {
50 //PRIVATES
51 private Point _p1;
52 private Point _p2;
53
54 //CONSTRUCTOR
55 public StartAndEndPoint(Point p1, Point p2) {
56 _p1 = p1;
57 _p2 = p2;
58 }
59
60 //GETTERS
61 public Point getP1() {
62 return _p1;
63 }
64
65 public Point getP2() {
66 return _p2;
67 }
68
69 //SETTERS
70 public void setP1(Point p1) {
71 _p1 = p1;
72 }
73
74 public void setP2(Point p2) {
75 _p2 = p2;
76 }
77
78 //ToString
79 public String toString() {
80 return "Start: " + _p1 + " End: " + _p2;
81 }
82 }
83 static public class Pair{
84 //Privates
85 private Boolean _b;
86 private Integer _i;
87
88 //Constructor
89 public Pair(Boolean b, Integer i){
90 _b = b;
91 _i = i;
92 }
93 public Pair(){
94 _b = null;
95 _i = null;
96 }
97
98 //Getters
99 public Boolean getBoolean() {return _b;}
100 public Integer getInteger() {return _i;}
101
102 //Setters
103 public void setBoolean (Boolean b){_b = b;}
104 public void setInteger (Integer i){_i = i;}
105
106 //ToString
107 public String toString() {return "Boolean: " + _b + " Integer: " + _i;}
108 }
109
110 public static void main(String[] args) {
111 try {
112 if (args.length != 3) {
113 System.out.println("Usage: imageClassifier <inputFilename> <classifierType> <outputFilename>");
114 } else {
115 Pair houghlinesPResult = new Pair();
116
117 Boolean result = null;
118 String result_cluster = "";
119 String imageFilename = args[0];
120 String classifierType = args[1];
121 String outputFilename = args[2];
122 Boolean enableLineClustering = null;
123 //Prep Writing output to disc
124 File log = new File(outputFilename);
125 FileWriter fileWriter = new FileWriter(log, true);
126 BufferedWriter bw = new BufferedWriter(fileWriter);
127 //Execute classifierType defined from arguement
128
129 //Split output by tab for processing in next java program
130 //imageFilename = 1, result = 3, classifierType = 4
131 switch (classifierType) {
132 case "count":
133 enableLineClustering = false;
134 houghlinesPResult = Algorithm_HoughLinesP(imageFilename, enableLineClustering);
135 bw.write("Filename:" + '\t' + imageFilename + '\t' + "Classified as:" + '\t' + houghlinesPResult.getBoolean() + '\t' + "Number of lines:" + '\t' + houghlinesPResult.getInteger() + '\t' + classifierType + '\n');
136 break;
137 case "cluster":
138 enableLineClustering = true;
139 houghlinesPResult = Algorithm_HoughLinesP(imageFilename, enableLineClustering);
140 bw.write("Filename:" + '\t' + imageFilename + '\t' + "Classified as:" + '\t' + houghlinesPResult.getBoolean() + '\t' + "Number of lines:" + '\t' + houghlinesPResult.getInteger() + '\t' + classifierType + '\n');
141 break;
142 case "morphology":
143 //result_cluster = setup_Cluster(imageFilename);
144 //bw.write(result_cluster);
145 break;
146 default:
147 System.out.println("unknown algorithm");
148 break;
149 }
150
151 bw.close();
152 }
153 } catch (Exception e) {
154 System.err.println(e);
155 }
156 }
157
158 //******************
159 //ALGORITHM FUNCTIONS
160 //******************
161 private static Pair Algorithm_HoughLinesP(String filename, Boolean enableLineClusterDetection){
162 System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
163 Boolean isSheetMusic = null;
164 Pair returnVariables = new Pair();
165 try{
166 //Variables
167 int horizontalLineCount =0;
168 Mat edgesDetected = new Mat();
169 Mat edgesDetectedRGB = new Mat();
170 Mat edgesExtra = new Mat();
171 Mat edgesDetectedRGBProb;
172 ArrayList<StartAndEndPoint> pointArrayList = new ArrayList<>();
173
174 //****************EXPLANATION**************************************************
175 //
176 //Load an image in greyscale
177 //Additional matrix to hold results of line detection
178 //Inversed Binarization of image
179 //Detect lines in image
180 //Go thru every line detected and check its gradient is less than SLOPEGRADIENT
181 //
182 //****************EXPLANATION**************************************************
183
184 Mat original = Imgcodecs.imread(filename, Imgcodecs.IMREAD_GRAYSCALE);
185 Mat linesP = new Mat(); //will hold the results of the detection
186 Imgproc.adaptiveThreshold(original, edgesDetected,255, Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C,Imgproc.THRESH_BINARY_INV,15, THRESHOLD_C);
187 double minLineLength = edgesDetected.size().width/8;
188 Imgproc.HoughLinesP(edgesDetected, linesP, 1, Math.PI / 720, HOUGHLINEP_THRESHOLD, minLineLength, MAXLINEGAP);
189 for (int x = 0; x < linesP.rows(); x++) {
190 double[] l = linesP.get(x, 0);
191 Point p1 = new Point(l[0], l[1]);
192 Point p2 = new Point(l[2], l[3]);
193 double m = Math.abs(p2.y - p1.y)/(p2.x - p1.x);
194 if(m<SLOPEGRADIENT) {
195 horizontalLineCount++;
196 pointArrayList.add(new StartAndEndPoint(p1, p2));
197 }
198 }
199
200 //Calculate if its sheet music or not
201 if(enableLineClusterDetection ==true){returnVariables = Classifier_ClusterDetection(pointArrayList);}
202 else {
203 isSheetMusic = Classifier_LineCounter(horizontalLineCount);
204 returnVariables.setBoolean(isSheetMusic);
205 returnVariables.setInteger(horizontalLineCount);
206 }
207 }
208 catch(Exception e){
209 System.err.println(e);
210 }
211 return returnVariables;
212 }
213
214 //******************
215 //CLASSIFIER FUNCTIONS
216 //******************
217
218 private static boolean Classifier_LineCounter(int lineCount){
219 if(lineCount>MINLINECOUNT){return true;}
220 else{return false;}
221 }
222 private static Pair Classifier_ClusterDetection(ArrayList<StartAndEndPoint> linePointsArray){
223
224 Pair returnPair = new Pair();
225 ArrayList<StartAndEndPoint> closeLinePts = new ArrayList<StartAndEndPoint>();
226 ArrayList<StartAndEndPoint[]> clusterPtArray = new ArrayList<StartAndEndPoint[]>();
227 int clusterCount = 0;
228 try {
229
230 if(linePointsArray.size()> 1) {
231 for (int i = 0; i < linePointsArray.size(); i++){
232 for (int j = 0; j < linePointsArray.size(); j++) {
233 if(Math.abs(linePointsArray.get(j).getP1().y - linePointsArray.get(i).getP1().y) < 5){
234 if(linePointsArray.get(j).getP1().y != linePointsArray.get(i).getP1().y){
235 closeLinePts.add(linePointsArray.get(i));
236 }
237 }
238 }
239 }
240
241 Collections.sort(closeLinePts, new Comparator<StartAndEndPoint>() {
242 @Override
243 public int compare(StartAndEndPoint p1, StartAndEndPoint p2) {
244 return (int)(p1.getP1().y - p2.getP1().y);
245 }
246 });
247
248 closeLinePts = removeDuplicates(closeLinePts);
249
250 if(closeLinePts.size() >= 4) {
251 for(int i= 0; i < closeLinePts.size(); i++){
252 if(i + 4 >= closeLinePts.size()){
253 break;
254 }
255 else{
256 StartAndEndPoint[] tempPtArray = new StartAndEndPoint[4];
257 tempPtArray[0] = closeLinePts.get(i);
258 tempPtArray[1] = closeLinePts.get(i + 1);
259 tempPtArray[2] = closeLinePts.get(i + 2);
260 tempPtArray[3] = closeLinePts.get(i + 3);
261 if(ClusterCheck(tempPtArray)){
262 clusterPtArray.add(tempPtArray);
263 if((i + 4 < closeLinePts.size())){
264 i = i+4;
265 }
266 else{
267 break;
268 }
269 }
270 }
271 }
272 }
273
274 /* for(StartAndEndPoint pt : linePointsArray){
275 for(int i =0; i < clusterPtArray.size(); i++){
276 for(StartAndEndPoint item : clusterPtArray.get(i)) {
277 if (item.getP1().y == pt.getP1().y){
278 Imgproc.line(clustersFoundRGB, pt.getP1(), pt.getP2(), new Scalar(0, 255, 0), 1, Imgproc.LINE_4, 0);
279 }
280 }
281 }
282 }*/
283
284 clusterCount = clusterPtArray.size();
285 //SETUP RETURN ARRAY
286 if(clusterCount >= 1){
287 returnPair.setBoolean(true);
288 returnPair.setInteger(clusterCount);
289 //returnArray.add(clustersFoundRGB);
290 }
291 else{
292 returnPair.setBoolean(false);
293 returnPair.setInteger(clusterCount);
294 //returnArray.add(clustersFoundRGB);
295 }
296 }
297 }
298 catch (Exception e) {
299 System.err.println(e.getMessage());
300 }
301 return returnPair;
302 }
303
304 //******************
305 //INTERNAL FUNCTIONS
306 //******************
307
308 public static <T> ArrayList<T> removeDuplicates(ArrayList<T> list) {
309 //DIRECTLY COPIED//DIRECTLY COPIED//DIRECTLY COPIED//DIRECTLY COPIED//DIRECTLY COPIED//DIRECTLY COPIED
310 // Function to remove duplicates from an ArrayList
311 // Create a new ArrayList
312 ArrayList<T> newList = new ArrayList<T>();
313 // Traverse through the first list
314 for (T element : list) {
315 // If this element is not present in newList
316 // then add it
317 if (!newList.contains(element)) {
318 newList.add(element);
319 }
320 }
321 // return the new list
322 return newList;
323 //DIRECTLY COPIED//DIRECTLY COPIED//DIRECTLY COPIED//DIRECTLY COPIED//DIRECTLY COPIED//DIRECTLY COPIED
324 }
325 public static double VarianceCalc(StartAndEndPoint parseArray[]){
326 double sum =0;
327 double temp =0;
328 double mean, variance;
329 int size = parseArray.length;
330 //Calculate sum of array
331 for(int i =0; i < parseArray.length; i++){
332 sum += parseArray[i].getP1().y;
333 }
334 //Calculate mean of array
335 mean = sum/parseArray.length;
336 //Calculate variants
337 for(int i =0; i < size; i++){
338 temp += Math.pow((parseArray[i].getP1().y-mean),2);
339 }
340 variance = Math.abs(temp/(size -1));
341 //System.out.println("VARIANCE: " + variance);
342 return variance;
343 }
344 public static Boolean lineComparison(double baseLineS, double compareLineS, double compareLineE ){
345 //System.out.print("Comparing baseLineS: " + baseLineS + " with compareLineE: " + compareLineE + " and compareLineS: " + compareLineS);
346 if(baseLineS < compareLineE && baseLineS > compareLineS){
347 return true;
348 }
349 return false;
350 }
351 public static Boolean ClusterCheck(StartAndEndPoint parseArray[]){
352 try {
353 //System.out.println("LENGTH: " + parseArray.length);
354 //MAKE THREE COMPARISONS
355 //After clusters have been found.
356 //Check if their x positions intersect
357 //Logic being
358 //(L1.S < L2.E && L1.S > L2.S)
359 //or
360 //(L2.S < L1.E && L2.S > L1.S)
361 //Variance is using Start of line point.
362 //USING VARIANTS
363 double variance = VarianceCalc(parseArray);
364 Boolean consistent = false;
365 if (variance <= CLUSTER_DISTANCE_MAX && variance > CLUSTER_DISTANCE_MIN) {
366
367 for (int i = 0; i < parseArray.length - 1; i++) {
368 //System.out.println(i);
369 double l1_S = parseArray[i].getP1().x;
370 double l1_E = parseArray[i].getP2().x;
371 double l2_S = parseArray[i + 1].getP1().x;
372 double l2_E = parseArray[i + 1].getP2().x;
373
374 //Check which starts after
375 if (l1_S >= l2_S) {
376 //baseLineStart is l1_S (call with lineComparison)
377 consistent = lineComparison(l1_S, l2_S, l2_E);
378 } else if (l2_S > l1_S) {
379 //baseLineStart is l2_S (call with lineComparison)
380 consistent = lineComparison(l2_S, l1_S, l1_E);
381 } else {
382 System.err.println("An error, comparing l1_S and l2_S, has occurred");
383 }
384
385 //Check if false was returned;
386 if (consistent == false) {
387 /*System.out.print(" X positions of two lines did not overlap each other:" + '\t');
388 System.out.print("l1_S: " + l1_S + '\t');
389 System.out.print("l1_E: " + l1_E + '\t');
390 System.out.print("l2_S: " + l2_S + '\t');
391 System.out.print("l2_E: " + l2_E);
392 System.out.println(" ");*/
393 return false;
394 }
395 }
396 //Have been through for loop, maintaining consistent being true.
397 //Have also meet the variance MIN and MAX requirement. Therefore it is a cluster
398 return true;
399 }
400 //System.out.println("Did not meet Cluster Distance Min and Max requirements, Variance = " + variance);
401 return false;
402 }
403 catch (Exception e){
404 System.err.println(" "+e.getMessage());
405 return false;
406 }
407 }
408}
Note: See TracBrowser for help on using the repository browser.