From 5b15d69b2d8a8f15f3e518ede1b352203794c021 Mon Sep 17 00:00:00 2001 From: Frida Tveit Date: Mon, 19 Dec 2016 17:47:48 +0000 Subject: [PATCH 1/7] Issue #1: Added unit tests for CharacterRecognizer. Changed nested classes in CharacterRecognizer to be static to make them easier to test. --- .../recognizer/CharacterRecognizer.java | 6 +- .../recognizer/KnnPatternClassificator.java | 2 +- .../NeuralPatternClassificator.java | 2 +- .../recognizer/CharacterRecognizerTest.java | 72 +++++++++++++++++++ 4 files changed, 77 insertions(+), 5 deletions(-) create mode 100644 src/test/java/net/sf/javaanpr/recognizer/CharacterRecognizerTest.java diff --git a/src/main/java/net/sf/javaanpr/recognizer/CharacterRecognizer.java b/src/main/java/net/sf/javaanpr/recognizer/CharacterRecognizer.java index 53ca149..44b7193 100644 --- a/src/main/java/net/sf/javaanpr/recognizer/CharacterRecognizer.java +++ b/src/main/java/net/sf/javaanpr/recognizer/CharacterRecognizer.java @@ -46,7 +46,7 @@ public abstract class CharacterRecognizer { public abstract RecognizedChar recognize(Char chr); - public class RecognizedChar { + public static class RecognizedChar { private Vector patterns; private boolean isSorted; @@ -117,7 +117,7 @@ public BufferedImage render() { return histogram; } - public final class RecognizedPattern { + public static final class RecognizedPattern { private char chr; private float cost; @@ -135,7 +135,7 @@ public float getCost() { } } - public class PatternComparer implements Comparator { + public static class PatternComparer implements Comparator { private int direction; diff --git a/src/main/java/net/sf/javaanpr/recognizer/KnnPatternClassificator.java b/src/main/java/net/sf/javaanpr/recognizer/KnnPatternClassificator.java index 9afc87e..0619c3b 100644 --- a/src/main/java/net/sf/javaanpr/recognizer/KnnPatternClassificator.java +++ b/src/main/java/net/sf/javaanpr/recognizer/KnnPatternClassificator.java @@ -60,7 +60,7 @@ public RecognizedChar recognize(Char chr) { RecognizedChar recognized = new RecognizedChar(); for (int x = 0; x < this.learnVectors.size(); x++) { float fx = this.simplifiedEuclideanDistance(tested, this.learnVectors.elementAt(x)); - recognized.addPattern(recognized.new RecognizedPattern(ALPHABET[x], fx)); + recognized.addPattern(new RecognizedChar.RecognizedPattern(ALPHABET[x], fx)); } recognized.sort(0); return recognized; diff --git a/src/main/java/net/sf/javaanpr/recognizer/NeuralPatternClassificator.java b/src/main/java/net/sf/javaanpr/recognizer/NeuralPatternClassificator.java index e34b792..a8daea3 100644 --- a/src/main/java/net/sf/javaanpr/recognizer/NeuralPatternClassificator.java +++ b/src/main/java/net/sf/javaanpr/recognizer/NeuralPatternClassificator.java @@ -90,7 +90,7 @@ public RecognizedChar recognize(Char imgChar) { Vector output = this.network.test(imgChar.extractFeatures()); RecognizedChar recognized = new RecognizedChar(); for (int i = 0; i < output.size(); i++) { - recognized.addPattern(recognized.new RecognizedPattern(ALPHABET[i], output.elementAt(i).floatValue())); + recognized.addPattern(new RecognizedChar.RecognizedPattern(ALPHABET[i], output.elementAt(i).floatValue())); } recognized.render(); recognized.sort(1); diff --git a/src/test/java/net/sf/javaanpr/recognizer/CharacterRecognizerTest.java b/src/test/java/net/sf/javaanpr/recognizer/CharacterRecognizerTest.java new file mode 100644 index 0000000..ad2af35 --- /dev/null +++ b/src/test/java/net/sf/javaanpr/recognizer/CharacterRecognizerTest.java @@ -0,0 +1,72 @@ +/* + * Copyright 2013 JavaANPR contributors + * Copyright 2006 Ondrej Martinsky + * Licensed under the Educational Community License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.osedu.org/licenses/ECL-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an "AS IS" + * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package net.sf.javaanpr.recognizer; + +import org.junit.Test; + +import java.util.Vector; + +import static org.junit.Assert.*; +import static org.hamcrest.CoreMatchers.*; + +public class CharacterRecognizerTest { + + private CharacterRecognizer.RecognizedChar getRecognizedCharWithThreePatterns() { + CharacterRecognizer.RecognizedChar recognizedChar = new CharacterRecognizer.RecognizedChar(); + recognizedChar.addPattern(new CharacterRecognizer.RecognizedChar.RecognizedPattern('A', 3.0f)); + recognizedChar.addPattern(new CharacterRecognizer.RecognizedChar.RecognizedPattern('B', 1.0f)); + recognizedChar.addPattern(new CharacterRecognizer.RecognizedChar.RecognizedPattern('C', 4.0f)); + return recognizedChar; + } + + @Test + public void testPatternsCorrectlySortedAscending() { + CharacterRecognizer.RecognizedChar recognizedChar = getRecognizedCharWithThreePatterns(); + assertFalse(recognizedChar.isSorted()); + recognizedChar.sort(0); + assertTrue(recognizedChar.isSorted()); + Vector patterns = recognizedChar.getPatterns(); + assertThat(patterns.get(0).getCost(), is(1.0f)); + assertThat(patterns.get(1).getCost(), is(3.0f)); + assertThat(patterns.get(2).getCost(), is(4.0f)); + } + + @Test + public void testPatternsCorrectlySortedDescending() { + CharacterRecognizer.RecognizedChar recognizedChar = getRecognizedCharWithThreePatterns(); + assertFalse(recognizedChar.isSorted()); + recognizedChar.sort(1); + assertTrue(recognizedChar.isSorted()); + Vector patterns = recognizedChar.getPatterns(); + assertThat(patterns.get(0).getCost(), is(4.0f)); + assertThat(patterns.get(1).getCost(), is(3.0f)); + assertThat(patterns.get(2).getCost(), is(1.0f)); + } + + @Test + public void testGetPatternReturnsCorrectPatternWhenPatternsSorted() { + CharacterRecognizer.RecognizedChar recognizedChar = getRecognizedCharWithThreePatterns(); + recognizedChar.sort(0); + assertThat(recognizedChar.getPattern(2).getCost(), is(4.0f)); + } + + @Test + public void testGetPatternReturnsNullWhenPatternsNotSorted() { + CharacterRecognizer.RecognizedChar recognizedChar = getRecognizedCharWithThreePatterns(); + assertNull(recognizedChar.getPattern(2)); + } +} From 842b063ecff9d6188d1e4b9f9ad255b18718449c Mon Sep 17 00:00:00 2001 From: Frida Tveit Date: Tue, 20 Dec 2016 17:56:29 +0000 Subject: [PATCH 2/7] Changed CharacterRecognizerTest to only use junit assertions and use @before setup method. --- .../recognizer/CharacterRecognizerTest.java | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/test/java/net/sf/javaanpr/recognizer/CharacterRecognizerTest.java b/src/test/java/net/sf/javaanpr/recognizer/CharacterRecognizerTest.java index ad2af35..9836d97 100644 --- a/src/test/java/net/sf/javaanpr/recognizer/CharacterRecognizerTest.java +++ b/src/test/java/net/sf/javaanpr/recognizer/CharacterRecognizerTest.java @@ -16,57 +16,55 @@ package net.sf.javaanpr.recognizer; +import org.junit.Before; import org.junit.Test; import java.util.Vector; import static org.junit.Assert.*; -import static org.hamcrest.CoreMatchers.*; public class CharacterRecognizerTest { + private static final double epsilon = 5.96e-08; + private CharacterRecognizer.RecognizedChar recognizedChar; - private CharacterRecognizer.RecognizedChar getRecognizedCharWithThreePatterns() { - CharacterRecognizer.RecognizedChar recognizedChar = new CharacterRecognizer.RecognizedChar(); + @Before + public void setup() { + recognizedChar = new CharacterRecognizer.RecognizedChar(); recognizedChar.addPattern(new CharacterRecognizer.RecognizedChar.RecognizedPattern('A', 3.0f)); recognizedChar.addPattern(new CharacterRecognizer.RecognizedChar.RecognizedPattern('B', 1.0f)); recognizedChar.addPattern(new CharacterRecognizer.RecognizedChar.RecognizedPattern('C', 4.0f)); - return recognizedChar; } @Test public void testPatternsCorrectlySortedAscending() { - CharacterRecognizer.RecognizedChar recognizedChar = getRecognizedCharWithThreePatterns(); assertFalse(recognizedChar.isSorted()); recognizedChar.sort(0); assertTrue(recognizedChar.isSorted()); Vector patterns = recognizedChar.getPatterns(); - assertThat(patterns.get(0).getCost(), is(1.0f)); - assertThat(patterns.get(1).getCost(), is(3.0f)); - assertThat(patterns.get(2).getCost(), is(4.0f)); + assertEquals(patterns.get(0).getCost(), 1.0f, epsilon); + assertEquals(patterns.get(1).getCost(), 3.0f, epsilon); + assertEquals(patterns.get(2).getCost(), 4.0f, epsilon); } @Test public void testPatternsCorrectlySortedDescending() { - CharacterRecognizer.RecognizedChar recognizedChar = getRecognizedCharWithThreePatterns(); assertFalse(recognizedChar.isSorted()); recognizedChar.sort(1); assertTrue(recognizedChar.isSorted()); Vector patterns = recognizedChar.getPatterns(); - assertThat(patterns.get(0).getCost(), is(4.0f)); - assertThat(patterns.get(1).getCost(), is(3.0f)); - assertThat(patterns.get(2).getCost(), is(1.0f)); + assertEquals(patterns.get(0).getCost(), 4.0f, epsilon); + assertEquals(patterns.get(1).getCost(), 3.0f, epsilon); + assertEquals(patterns.get(2).getCost(), 1.0f, epsilon); } @Test public void testGetPatternReturnsCorrectPatternWhenPatternsSorted() { - CharacterRecognizer.RecognizedChar recognizedChar = getRecognizedCharWithThreePatterns(); recognizedChar.sort(0); - assertThat(recognizedChar.getPattern(2).getCost(), is(4.0f)); + assertEquals(recognizedChar.getPattern(2).getCost(), 4.0f, epsilon); } @Test public void testGetPatternReturnsNullWhenPatternsNotSorted() { - CharacterRecognizer.RecognizedChar recognizedChar = getRecognizedCharWithThreePatterns(); assertNull(recognizedChar.getPattern(2)); } } From 89ed072fa3b5dd67b15559b654588ee6c9c63967 Mon Sep 17 00:00:00 2001 From: Frida Tveit Date: Tue, 20 Dec 2016 18:11:27 +0000 Subject: [PATCH 3/7] Extracted nested classes PatternComparer, RecognizedChar and RecognizedPattern. They are no longer nested inside CharacterRecognizer but have their own files. --- .../javaanpr/intelligence/Intelligence.java | 2 +- .../net/sf/javaanpr/intelligence/Parser.java | 5 +- .../intelligence/RecognizedPlate.java | 2 +- .../recognizer/CharacterRecognizer.java | 122 ------------------ .../recognizer/KnnPatternClassificator.java | 2 +- .../NeuralPatternClassificator.java | 4 +- .../javaanpr/recognizer/PatternComparer.java | 44 +++++++ .../javaanpr/recognizer/RecognizedChar.java | 94 ++++++++++++++ .../recognizer/RecognizedPattern.java | 35 +++++ 9 files changed, 181 insertions(+), 129 deletions(-) create mode 100644 src/main/java/net/sf/javaanpr/recognizer/PatternComparer.java create mode 100644 src/main/java/net/sf/javaanpr/recognizer/RecognizedChar.java create mode 100644 src/main/java/net/sf/javaanpr/recognizer/RecognizedPattern.java diff --git a/src/main/java/net/sf/javaanpr/intelligence/Intelligence.java b/src/main/java/net/sf/javaanpr/intelligence/Intelligence.java index 59c82ad..40e5c00 100644 --- a/src/main/java/net/sf/javaanpr/intelligence/Intelligence.java +++ b/src/main/java/net/sf/javaanpr/intelligence/Intelligence.java @@ -26,7 +26,7 @@ import net.sf.javaanpr.imageanalysis.Plate; import net.sf.javaanpr.jar.Main; import net.sf.javaanpr.recognizer.CharacterRecognizer; -import net.sf.javaanpr.recognizer.CharacterRecognizer.RecognizedChar; +import net.sf.javaanpr.recognizer.RecognizedChar; import net.sf.javaanpr.recognizer.KnnPatternClassificator; import net.sf.javaanpr.recognizer.NeuralPatternClassificator; import org.xml.sax.SAXException; diff --git a/src/main/java/net/sf/javaanpr/intelligence/Parser.java b/src/main/java/net/sf/javaanpr/intelligence/Parser.java index 6158811..8bb625a 100644 --- a/src/main/java/net/sf/javaanpr/intelligence/Parser.java +++ b/src/main/java/net/sf/javaanpr/intelligence/Parser.java @@ -18,7 +18,8 @@ import net.sf.javaanpr.configurator.Configurator; import net.sf.javaanpr.jar.Main; -import net.sf.javaanpr.recognizer.CharacterRecognizer.RecognizedChar; +import net.sf.javaanpr.recognizer.RecognizedChar; +import net.sf.javaanpr.recognizer.RecognizedPattern; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; @@ -204,7 +205,7 @@ public String parse(RecognizedPlate recognizedPlate, int syntaxAnalysisMode) { / finalPlate.requiredChanges++; // +1 for every char for (int x = 0; x < rc.getPatterns().size(); x++) { if (form.getPosition(j).isAllowed(rc.getPattern(x).getChar())) { - RecognizedChar.RecognizedPattern rp = rc.getPattern(x); + RecognizedPattern rp = rc.getPattern(x); finalPlate.requiredChanges += (rp.getCost() / 100); // +x for its cost finalPlate.addChar(rp.getChar()); break; diff --git a/src/main/java/net/sf/javaanpr/intelligence/RecognizedPlate.java b/src/main/java/net/sf/javaanpr/intelligence/RecognizedPlate.java index 1492a46..4c35228 100644 --- a/src/main/java/net/sf/javaanpr/intelligence/RecognizedPlate.java +++ b/src/main/java/net/sf/javaanpr/intelligence/RecognizedPlate.java @@ -16,7 +16,7 @@ package net.sf.javaanpr.intelligence; -import net.sf.javaanpr.recognizer.CharacterRecognizer.RecognizedChar; +import net.sf.javaanpr.recognizer.RecognizedChar; import java.util.Vector; diff --git a/src/main/java/net/sf/javaanpr/recognizer/CharacterRecognizer.java b/src/main/java/net/sf/javaanpr/recognizer/CharacterRecognizer.java index 44b7193..f745099 100644 --- a/src/main/java/net/sf/javaanpr/recognizer/CharacterRecognizer.java +++ b/src/main/java/net/sf/javaanpr/recognizer/CharacterRecognizer.java @@ -18,12 +18,6 @@ import net.sf.javaanpr.imageanalysis.Char; -import java.awt.*; -import java.awt.image.BufferedImage; -import java.util.Collections; -import java.util.Comparator; -import java.util.Vector; - public abstract class CharacterRecognizer { public static final char[] ALPHABET = @@ -45,120 +39,4 @@ public abstract class CharacterRecognizer { }; public abstract RecognizedChar recognize(Char chr); - - public static class RecognizedChar { - private Vector patterns; - private boolean isSorted; - - public RecognizedChar() { - this.patterns = new Vector(); - this.isSorted = false; - } - - public void addPattern(RecognizedPattern pattern) { - this.patterns.add(pattern); - } - - public boolean isSorted() { - return this.isSorted; - } - - public void sort(int direction) { - if (this.isSorted) { - return; - } - this.isSorted = true; - Collections.sort(this.patterns, new PatternComparer(direction)); - } - - /** - * @return null if not sorted - */ - public Vector getPatterns() { - if (this.isSorted) { - return this.patterns; - } - return null; - } - - public RecognizedPattern getPattern(int i) { - if (this.isSorted) { - return this.patterns.elementAt(i); - } - return null; - } - - public BufferedImage render() { - int width = 500; - int height = 200; - BufferedImage histogram = new BufferedImage(width + 20, height + 20, BufferedImage.TYPE_INT_RGB); - Graphics2D graphic = histogram.createGraphics(); - graphic.setColor(Color.LIGHT_GRAY); - Rectangle backRect = new Rectangle(0, 0, width + 20, height + 20); - graphic.fill(backRect); - graphic.draw(backRect); - graphic.setColor(Color.BLACK); - - int colWidth = width / this.patterns.size(); - int left, top; - for (int ay = 0; ay <= 100; ay += 10) { - int y = 15 + (int) (((100 - ay) / 100.0f) * (height - 20)); - graphic.drawString(new Integer(ay).toString(), 3, y + 11); - graphic.drawLine(25, y + 5, 35, y + 5); - } - graphic.drawLine(35, 19, 35, height); - graphic.setColor(Color.BLUE); - for (int i = 0; i < this.patterns.size(); i++) { - left = (i * colWidth) + 42; - top = height - (int) (this.patterns.elementAt(i).cost * (height - 20)); - graphic.drawRect(left, top, colWidth - 2, height - top); - graphic.drawString(this.patterns.elementAt(i).chr + " ", left + 2, top - 8); - } - return histogram; - } - - public static final class RecognizedPattern { - private char chr; - private float cost; - - public RecognizedPattern(char chr, float value) { - this.chr = chr; - this.cost = value; - } - - public char getChar() { - return this.chr; - } - - public float getCost() { - return this.cost; - } - } - - public static class PatternComparer implements Comparator { - - private int direction; - - public PatternComparer(int direction) { - this.direction = direction; - } - - @Override - public int compare(Object o1, Object o2) { - float cost1 = ((RecognizedPattern) o1).getCost(); - float cost2 = ((RecognizedPattern) o2).getCost(); - int ret = 0; - if (cost1 < cost2) { - ret = -1; - } - if (cost1 > cost2) { - ret = 1; - } - if (this.direction == 1) { - ret *= -1; - } - return ret; - } - } - } } diff --git a/src/main/java/net/sf/javaanpr/recognizer/KnnPatternClassificator.java b/src/main/java/net/sf/javaanpr/recognizer/KnnPatternClassificator.java index 0619c3b..2d735a2 100644 --- a/src/main/java/net/sf/javaanpr/recognizer/KnnPatternClassificator.java +++ b/src/main/java/net/sf/javaanpr/recognizer/KnnPatternClassificator.java @@ -60,7 +60,7 @@ public RecognizedChar recognize(Char chr) { RecognizedChar recognized = new RecognizedChar(); for (int x = 0; x < this.learnVectors.size(); x++) { float fx = this.simplifiedEuclideanDistance(tested, this.learnVectors.elementAt(x)); - recognized.addPattern(new RecognizedChar.RecognizedPattern(ALPHABET[x], fx)); + recognized.addPattern(new RecognizedPattern(ALPHABET[x], fx)); } recognized.sort(0); return recognized; diff --git a/src/main/java/net/sf/javaanpr/recognizer/NeuralPatternClassificator.java b/src/main/java/net/sf/javaanpr/recognizer/NeuralPatternClassificator.java index a8daea3..398881a 100644 --- a/src/main/java/net/sf/javaanpr/recognizer/NeuralPatternClassificator.java +++ b/src/main/java/net/sf/javaanpr/recognizer/NeuralPatternClassificator.java @@ -82,7 +82,7 @@ public NeuralNetwork getNetwork() { * Image to character. * * @param imgChar the Char to recognize - * @return the {@link net.sf.javaanpr.recognizer.CharacterRecognizer.RecognizedChar} + * @return the {@link net.sf.javaanpr.recognizer.RecognizedChar} */ @Override public RecognizedChar recognize(Char imgChar) { @@ -90,7 +90,7 @@ public RecognizedChar recognize(Char imgChar) { Vector output = this.network.test(imgChar.extractFeatures()); RecognizedChar recognized = new RecognizedChar(); for (int i = 0; i < output.size(); i++) { - recognized.addPattern(new RecognizedChar.RecognizedPattern(ALPHABET[i], output.elementAt(i).floatValue())); + recognized.addPattern(new RecognizedPattern(ALPHABET[i], output.elementAt(i).floatValue())); } recognized.render(); recognized.sort(1); diff --git a/src/main/java/net/sf/javaanpr/recognizer/PatternComparer.java b/src/main/java/net/sf/javaanpr/recognizer/PatternComparer.java new file mode 100644 index 0000000..d2fcbe5 --- /dev/null +++ b/src/main/java/net/sf/javaanpr/recognizer/PatternComparer.java @@ -0,0 +1,44 @@ +/* + * Copyright 2013 JavaANPR contributors + * Copyright 2006 Ondrej Martinsky + * Licensed under the Educational Community License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.osedu.org/licenses/ECL-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an "AS IS" + * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package net.sf.javaanpr.recognizer; + +import java.util.Comparator; + +public class PatternComparer implements Comparator { + private int direction; + + public PatternComparer(int direction) { + this.direction = direction; + } + + @Override + public int compare(Object o1, Object o2) { + float cost1 = ((RecognizedPattern) o1).getCost(); + float cost2 = ((RecognizedPattern) o2).getCost(); + int ret = 0; + if (cost1 < cost2) { + ret = -1; + } + if (cost1 > cost2) { + ret = 1; + } + if (this.direction == 1) { + ret *= -1; + } + return ret; + } +} diff --git a/src/main/java/net/sf/javaanpr/recognizer/RecognizedChar.java b/src/main/java/net/sf/javaanpr/recognizer/RecognizedChar.java new file mode 100644 index 0000000..9c2eeeb --- /dev/null +++ b/src/main/java/net/sf/javaanpr/recognizer/RecognizedChar.java @@ -0,0 +1,94 @@ +/* + * Copyright 2013 JavaANPR contributors + * Copyright 2006 Ondrej Martinsky + * Licensed under the Educational Community License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.osedu.org/licenses/ECL-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an "AS IS" + * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package net.sf.javaanpr.recognizer; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.util.Collections; +import java.util.Vector; + +public class RecognizedChar { + private Vector patterns; + private boolean isSorted; + + public RecognizedChar() { + this.patterns = new Vector(); + this.isSorted = false; + } + + public void addPattern(RecognizedPattern pattern) { + this.patterns.add(pattern); + } + + public boolean isSorted() { + return this.isSorted; + } + + public void sort(int direction) { + if (this.isSorted) { + return; + } + this.isSorted = true; + Collections.sort(this.patterns, new PatternComparer(direction)); + } + + /** + * @return null if not sorted + */ + public Vector getPatterns() { + if (this.isSorted) { + return this.patterns; + } + return null; + } + + public RecognizedPattern getPattern(int i) { + if (this.isSorted) { + return this.patterns.elementAt(i); + } + return null; + } + + public BufferedImage render() { + int width = 500; + int height = 200; + BufferedImage histogram = new BufferedImage(width + 20, height + 20, BufferedImage.TYPE_INT_RGB); + Graphics2D graphic = histogram.createGraphics(); + graphic.setColor(Color.LIGHT_GRAY); + Rectangle backRect = new Rectangle(0, 0, width + 20, height + 20); + graphic.fill(backRect); + graphic.draw(backRect); + graphic.setColor(Color.BLACK); + + int colWidth = width / this.patterns.size(); + int left, top; + for (int ay = 0; ay <= 100; ay += 10) { + int y = 15 + (int) (((100 - ay) / 100.0f) * (height - 20)); + graphic.drawString(new Integer(ay).toString(), 3, y + 11); + graphic.drawLine(25, y + 5, 35, y + 5); + } + graphic.drawLine(35, 19, 35, height); + graphic.setColor(Color.BLUE); + for (int i = 0; i < this.patterns.size(); i++) { + left = (i * colWidth) + 42; + top = height - (int) (this.patterns.elementAt(i).getCost() * (height - 20)); + graphic.drawRect(left, top, colWidth - 2, height - top); + graphic.drawString(this.patterns.elementAt(i).getChar() + " ", left + 2, top - 8); + } + return histogram; + } +} diff --git a/src/main/java/net/sf/javaanpr/recognizer/RecognizedPattern.java b/src/main/java/net/sf/javaanpr/recognizer/RecognizedPattern.java new file mode 100644 index 0000000..325cae5 --- /dev/null +++ b/src/main/java/net/sf/javaanpr/recognizer/RecognizedPattern.java @@ -0,0 +1,35 @@ +/* + * Copyright 2013 JavaANPR contributors + * Copyright 2006 Ondrej Martinsky + * Licensed under the Educational Community License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.osedu.org/licenses/ECL-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an "AS IS" + * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package net.sf.javaanpr.recognizer; + +public final class RecognizedPattern { + private char chr; + private float cost; + + public RecognizedPattern(char chr, float value) { + this.chr = chr; + this.cost = value; + } + + public char getChar() { + return this.chr; + } + + public float getCost() { + return this.cost; + } +} From 87b7575f6f3acfc8ab05bed24cc7787630ca24b2 Mon Sep 17 00:00:00 2001 From: Frida Tveit Date: Tue, 20 Dec 2016 18:13:07 +0000 Subject: [PATCH 4/7] Updated CharacterRecognizerTest to reflect the fact that the nested classes in CharacterRecognizer have been extracted. --- .../recognizer/CharacterRecognizerTest.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/java/net/sf/javaanpr/recognizer/CharacterRecognizerTest.java b/src/test/java/net/sf/javaanpr/recognizer/CharacterRecognizerTest.java index 9836d97..53cc81d 100644 --- a/src/test/java/net/sf/javaanpr/recognizer/CharacterRecognizerTest.java +++ b/src/test/java/net/sf/javaanpr/recognizer/CharacterRecognizerTest.java @@ -25,14 +25,14 @@ public class CharacterRecognizerTest { private static final double epsilon = 5.96e-08; - private CharacterRecognizer.RecognizedChar recognizedChar; + private RecognizedChar recognizedChar; @Before public void setup() { - recognizedChar = new CharacterRecognizer.RecognizedChar(); - recognizedChar.addPattern(new CharacterRecognizer.RecognizedChar.RecognizedPattern('A', 3.0f)); - recognizedChar.addPattern(new CharacterRecognizer.RecognizedChar.RecognizedPattern('B', 1.0f)); - recognizedChar.addPattern(new CharacterRecognizer.RecognizedChar.RecognizedPattern('C', 4.0f)); + recognizedChar = new RecognizedChar(); + recognizedChar.addPattern(new RecognizedPattern('A', 3.0f)); + recognizedChar.addPattern(new RecognizedPattern('B', 1.0f)); + recognizedChar.addPattern(new RecognizedPattern('C', 4.0f)); } @Test @@ -40,7 +40,7 @@ public void testPatternsCorrectlySortedAscending() { assertFalse(recognizedChar.isSorted()); recognizedChar.sort(0); assertTrue(recognizedChar.isSorted()); - Vector patterns = recognizedChar.getPatterns(); + Vector patterns = recognizedChar.getPatterns(); assertEquals(patterns.get(0).getCost(), 1.0f, epsilon); assertEquals(patterns.get(1).getCost(), 3.0f, epsilon); assertEquals(patterns.get(2).getCost(), 4.0f, epsilon); @@ -51,7 +51,7 @@ public void testPatternsCorrectlySortedDescending() { assertFalse(recognizedChar.isSorted()); recognizedChar.sort(1); assertTrue(recognizedChar.isSorted()); - Vector patterns = recognizedChar.getPatterns(); + Vector patterns = recognizedChar.getPatterns(); assertEquals(patterns.get(0).getCost(), 4.0f, epsilon); assertEquals(patterns.get(1).getCost(), 3.0f, epsilon); assertEquals(patterns.get(2).getCost(), 1.0f, epsilon); From 93ce0aecf73f3318c8824f9a2b2746be88601056 Mon Sep 17 00:00:00 2001 From: Frida Tveit Date: Tue, 20 Dec 2016 18:39:46 +0000 Subject: [PATCH 5/7] Added unit tests for PatternComparer. Renamed CharacterRecognizer tests as they were really testing RecognizedChar. CharacterRecognizer and RecognizedPattern don't really have anything to test. --- .../recognizer/PatternComparerTest.java | 66 +++++++++++++++++++ ...nizerTest.java => RecognizedCharTest.java} | 2 +- 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 src/test/java/net/sf/javaanpr/recognizer/PatternComparerTest.java rename src/test/java/net/sf/javaanpr/recognizer/{CharacterRecognizerTest.java => RecognizedCharTest.java} (98%) diff --git a/src/test/java/net/sf/javaanpr/recognizer/PatternComparerTest.java b/src/test/java/net/sf/javaanpr/recognizer/PatternComparerTest.java new file mode 100644 index 0000000..4862957 --- /dev/null +++ b/src/test/java/net/sf/javaanpr/recognizer/PatternComparerTest.java @@ -0,0 +1,66 @@ +/* + * Copyright 2013 JavaANPR contributors + * Copyright 2006 Ondrej Martinsky + * Licensed under the Educational Community License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.osedu.org/licenses/ECL-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an "AS IS" + * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package net.sf.javaanpr.recognizer; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class PatternComparerTest { + + @Test + public void testCompareAscendingPatternsEqualReturnsZero() { + RecognizedPattern recognizedPattern1 = new RecognizedPattern('A', 1.0f); + RecognizedPattern recognizedPattern2 = new RecognizedPattern('B', 1.0f); + assertEquals(new PatternComparer(0).compare(recognizedPattern1, recognizedPattern2), 0); + } + + @Test + public void testCompareAscendingFirstPatternSmallerReturnsMinusOne() { + RecognizedPattern recognizedPattern1 = new RecognizedPattern('A', 1.0f); + RecognizedPattern recognizedPattern2 = new RecognizedPattern('A', 2.0f); + assertEquals(new PatternComparer(0).compare(recognizedPattern1, recognizedPattern2), -1); + } + + @Test + public void testCompareAscendingFirstPatternLargerReturnsPlusOne() { + RecognizedPattern recognizedPattern1 = new RecognizedPattern('A', 2.0f); + RecognizedPattern recognizedPattern2 = new RecognizedPattern('A', 1.0f); + assertEquals(new PatternComparer(0).compare(recognizedPattern1, recognizedPattern2), 1); + } + + @Test + public void testCompareDescendingPatternsEqualReturnsZero() { + RecognizedPattern recognizedPattern1 = new RecognizedPattern('A', 1.0f); + RecognizedPattern recognizedPattern2 = new RecognizedPattern('B', 1.0f); + assertEquals(new PatternComparer(1).compare(recognizedPattern1, recognizedPattern2), 0); + } + + @Test + public void testCompareDescendingFirstPatternSmallerReturnsPlusOne() { + RecognizedPattern recognizedPattern1 = new RecognizedPattern('A', 1.0f); + RecognizedPattern recognizedPattern2 = new RecognizedPattern('A', 2.0f); + assertEquals(new PatternComparer(1).compare(recognizedPattern1, recognizedPattern2), 1); + } + + @Test + public void testCompareDescendingFirstPatternLargerReturnsMinusOne() { + RecognizedPattern recognizedPattern1 = new RecognizedPattern('A', 2.0f); + RecognizedPattern recognizedPattern2 = new RecognizedPattern('A', 1.0f); + assertEquals(new PatternComparer(1).compare(recognizedPattern1, recognizedPattern2), -1); + } +} diff --git a/src/test/java/net/sf/javaanpr/recognizer/CharacterRecognizerTest.java b/src/test/java/net/sf/javaanpr/recognizer/RecognizedCharTest.java similarity index 98% rename from src/test/java/net/sf/javaanpr/recognizer/CharacterRecognizerTest.java rename to src/test/java/net/sf/javaanpr/recognizer/RecognizedCharTest.java index 53cc81d..988ee84 100644 --- a/src/test/java/net/sf/javaanpr/recognizer/CharacterRecognizerTest.java +++ b/src/test/java/net/sf/javaanpr/recognizer/RecognizedCharTest.java @@ -23,7 +23,7 @@ import static org.junit.Assert.*; -public class CharacterRecognizerTest { +public class RecognizedCharTest { private static final double epsilon = 5.96e-08; private RecognizedChar recognizedChar; From ce322b7802b442d5708f822afa7449ab0f042aa8 Mon Sep 17 00:00:00 2001 From: Frida Tveit Date: Wed, 21 Dec 2016 19:45:01 +0000 Subject: [PATCH 6/7] Renamed PatternComparer to PatternComparator and made it implement Comparator. Changed PatternComparator to take a boolean shouldSortDescending instead of int direction. --- .../recognizer/KnnPatternClassificator.java | 2 +- .../recognizer/NeuralPatternClassificator.java | 2 +- ...tternComparer.java => PatternComparator.java} | 16 ++++++++-------- .../sf/javaanpr/recognizer/RecognizedChar.java | 4 ++-- ...parerTest.java => PatternComparatorTest.java} | 14 +++++++------- .../javaanpr/recognizer/RecognizedCharTest.java | 6 +++--- 6 files changed, 22 insertions(+), 22 deletions(-) rename src/main/java/net/sf/javaanpr/recognizer/{PatternComparer.java => PatternComparator.java} (66%) rename src/test/java/net/sf/javaanpr/recognizer/{PatternComparerTest.java => PatternComparatorTest.java} (77%) diff --git a/src/main/java/net/sf/javaanpr/recognizer/KnnPatternClassificator.java b/src/main/java/net/sf/javaanpr/recognizer/KnnPatternClassificator.java index 2d735a2..b933ead 100644 --- a/src/main/java/net/sf/javaanpr/recognizer/KnnPatternClassificator.java +++ b/src/main/java/net/sf/javaanpr/recognizer/KnnPatternClassificator.java @@ -62,7 +62,7 @@ public RecognizedChar recognize(Char chr) { float fx = this.simplifiedEuclideanDistance(tested, this.learnVectors.elementAt(x)); recognized.addPattern(new RecognizedPattern(ALPHABET[x], fx)); } - recognized.sort(0); + recognized.sort(false); return recognized; } diff --git a/src/main/java/net/sf/javaanpr/recognizer/NeuralPatternClassificator.java b/src/main/java/net/sf/javaanpr/recognizer/NeuralPatternClassificator.java index 398881a..66cc7e5 100644 --- a/src/main/java/net/sf/javaanpr/recognizer/NeuralPatternClassificator.java +++ b/src/main/java/net/sf/javaanpr/recognizer/NeuralPatternClassificator.java @@ -93,7 +93,7 @@ public RecognizedChar recognize(Char imgChar) { recognized.addPattern(new RecognizedPattern(ALPHABET[i], output.elementAt(i).floatValue())); } recognized.render(); - recognized.sort(1); + recognized.sort(true); return recognized; } diff --git a/src/main/java/net/sf/javaanpr/recognizer/PatternComparer.java b/src/main/java/net/sf/javaanpr/recognizer/PatternComparator.java similarity index 66% rename from src/main/java/net/sf/javaanpr/recognizer/PatternComparer.java rename to src/main/java/net/sf/javaanpr/recognizer/PatternComparator.java index d2fcbe5..fc54cfc 100644 --- a/src/main/java/net/sf/javaanpr/recognizer/PatternComparer.java +++ b/src/main/java/net/sf/javaanpr/recognizer/PatternComparator.java @@ -18,17 +18,17 @@ import java.util.Comparator; -public class PatternComparer implements Comparator { - private int direction; +public class PatternComparator implements Comparator { + private boolean shouldSortDescending; - public PatternComparer(int direction) { - this.direction = direction; + public PatternComparator(boolean shouldSortDescending) { + this.shouldSortDescending = shouldSortDescending; } @Override - public int compare(Object o1, Object o2) { - float cost1 = ((RecognizedPattern) o1).getCost(); - float cost2 = ((RecognizedPattern) o2).getCost(); + public int compare(RecognizedPattern recognizedPattern1, RecognizedPattern recognizedPattern2) { + float cost1 = recognizedPattern1.getCost(); + float cost2 = recognizedPattern2.getCost(); int ret = 0; if (cost1 < cost2) { ret = -1; @@ -36,7 +36,7 @@ public int compare(Object o1, Object o2) { if (cost1 > cost2) { ret = 1; } - if (this.direction == 1) { + if (shouldSortDescending) { ret *= -1; } return ret; diff --git a/src/main/java/net/sf/javaanpr/recognizer/RecognizedChar.java b/src/main/java/net/sf/javaanpr/recognizer/RecognizedChar.java index 9c2eeeb..b82edee 100644 --- a/src/main/java/net/sf/javaanpr/recognizer/RecognizedChar.java +++ b/src/main/java/net/sf/javaanpr/recognizer/RecognizedChar.java @@ -38,12 +38,12 @@ public boolean isSorted() { return this.isSorted; } - public void sort(int direction) { + public void sort(boolean shouldSortDescending) { if (this.isSorted) { return; } this.isSorted = true; - Collections.sort(this.patterns, new PatternComparer(direction)); + Collections.sort(this.patterns, new PatternComparator(shouldSortDescending)); } /** diff --git a/src/test/java/net/sf/javaanpr/recognizer/PatternComparerTest.java b/src/test/java/net/sf/javaanpr/recognizer/PatternComparatorTest.java similarity index 77% rename from src/test/java/net/sf/javaanpr/recognizer/PatternComparerTest.java rename to src/test/java/net/sf/javaanpr/recognizer/PatternComparatorTest.java index 4862957..4ee3d14 100644 --- a/src/test/java/net/sf/javaanpr/recognizer/PatternComparerTest.java +++ b/src/test/java/net/sf/javaanpr/recognizer/PatternComparatorTest.java @@ -20,47 +20,47 @@ import static org.junit.Assert.assertEquals; -public class PatternComparerTest { +public class PatternComparatorTest { @Test public void testCompareAscendingPatternsEqualReturnsZero() { RecognizedPattern recognizedPattern1 = new RecognizedPattern('A', 1.0f); RecognizedPattern recognizedPattern2 = new RecognizedPattern('B', 1.0f); - assertEquals(new PatternComparer(0).compare(recognizedPattern1, recognizedPattern2), 0); + assertEquals(new PatternComparator(false).compare(recognizedPattern1, recognizedPattern2), 0); } @Test public void testCompareAscendingFirstPatternSmallerReturnsMinusOne() { RecognizedPattern recognizedPattern1 = new RecognizedPattern('A', 1.0f); RecognizedPattern recognizedPattern2 = new RecognizedPattern('A', 2.0f); - assertEquals(new PatternComparer(0).compare(recognizedPattern1, recognizedPattern2), -1); + assertEquals(new PatternComparator(false).compare(recognizedPattern1, recognizedPattern2), -1); } @Test public void testCompareAscendingFirstPatternLargerReturnsPlusOne() { RecognizedPattern recognizedPattern1 = new RecognizedPattern('A', 2.0f); RecognizedPattern recognizedPattern2 = new RecognizedPattern('A', 1.0f); - assertEquals(new PatternComparer(0).compare(recognizedPattern1, recognizedPattern2), 1); + assertEquals(new PatternComparator(false).compare(recognizedPattern1, recognizedPattern2), 1); } @Test public void testCompareDescendingPatternsEqualReturnsZero() { RecognizedPattern recognizedPattern1 = new RecognizedPattern('A', 1.0f); RecognizedPattern recognizedPattern2 = new RecognizedPattern('B', 1.0f); - assertEquals(new PatternComparer(1).compare(recognizedPattern1, recognizedPattern2), 0); + assertEquals(new PatternComparator(true).compare(recognizedPattern1, recognizedPattern2), 0); } @Test public void testCompareDescendingFirstPatternSmallerReturnsPlusOne() { RecognizedPattern recognizedPattern1 = new RecognizedPattern('A', 1.0f); RecognizedPattern recognizedPattern2 = new RecognizedPattern('A', 2.0f); - assertEquals(new PatternComparer(1).compare(recognizedPattern1, recognizedPattern2), 1); + assertEquals(new PatternComparator(true).compare(recognizedPattern1, recognizedPattern2), 1); } @Test public void testCompareDescendingFirstPatternLargerReturnsMinusOne() { RecognizedPattern recognizedPattern1 = new RecognizedPattern('A', 2.0f); RecognizedPattern recognizedPattern2 = new RecognizedPattern('A', 1.0f); - assertEquals(new PatternComparer(1).compare(recognizedPattern1, recognizedPattern2), -1); + assertEquals(new PatternComparator(true).compare(recognizedPattern1, recognizedPattern2), -1); } } diff --git a/src/test/java/net/sf/javaanpr/recognizer/RecognizedCharTest.java b/src/test/java/net/sf/javaanpr/recognizer/RecognizedCharTest.java index 988ee84..7c15c13 100644 --- a/src/test/java/net/sf/javaanpr/recognizer/RecognizedCharTest.java +++ b/src/test/java/net/sf/javaanpr/recognizer/RecognizedCharTest.java @@ -38,7 +38,7 @@ public void setup() { @Test public void testPatternsCorrectlySortedAscending() { assertFalse(recognizedChar.isSorted()); - recognizedChar.sort(0); + recognizedChar.sort(false); assertTrue(recognizedChar.isSorted()); Vector patterns = recognizedChar.getPatterns(); assertEquals(patterns.get(0).getCost(), 1.0f, epsilon); @@ -49,7 +49,7 @@ public void testPatternsCorrectlySortedAscending() { @Test public void testPatternsCorrectlySortedDescending() { assertFalse(recognizedChar.isSorted()); - recognizedChar.sort(1); + recognizedChar.sort(true); assertTrue(recognizedChar.isSorted()); Vector patterns = recognizedChar.getPatterns(); assertEquals(patterns.get(0).getCost(), 4.0f, epsilon); @@ -59,7 +59,7 @@ public void testPatternsCorrectlySortedDescending() { @Test public void testGetPatternReturnsCorrectPatternWhenPatternsSorted() { - recognizedChar.sort(0); + recognizedChar.sort(false); assertEquals(recognizedChar.getPattern(2).getCost(), 4.0f, epsilon); } From dc3804a14e26f8ed560492cdfcc7241fd2e8d7ec Mon Sep 17 00:00:00 2001 From: Frida Tveit Date: Wed, 21 Dec 2016 20:29:25 +0000 Subject: [PATCH 7/7] Simplified the compare method in PatternComparator. Changed PatternComparatorTest to check for < 0 and > 0 instead of = -1 and = 1. --- .../javaanpr/recognizer/PatternComparator.java | 16 +++------------- .../recognizer/PatternComparatorTest.java | 13 +++++++++---- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/main/java/net/sf/javaanpr/recognizer/PatternComparator.java b/src/main/java/net/sf/javaanpr/recognizer/PatternComparator.java index fc54cfc..6a273c2 100644 --- a/src/main/java/net/sf/javaanpr/recognizer/PatternComparator.java +++ b/src/main/java/net/sf/javaanpr/recognizer/PatternComparator.java @@ -27,18 +27,8 @@ public PatternComparator(boolean shouldSortDescending) { @Override public int compare(RecognizedPattern recognizedPattern1, RecognizedPattern recognizedPattern2) { - float cost1 = recognizedPattern1.getCost(); - float cost2 = recognizedPattern2.getCost(); - int ret = 0; - if (cost1 < cost2) { - ret = -1; - } - if (cost1 > cost2) { - ret = 1; - } - if (shouldSortDescending) { - ret *= -1; - } - return ret; + Float cost1 = recognizedPattern1.getCost(); + Float cost2 = recognizedPattern2.getCost(); + return shouldSortDescending ? -1 * cost1.compareTo(cost2) : cost1.compareTo(cost2); } } diff --git a/src/test/java/net/sf/javaanpr/recognizer/PatternComparatorTest.java b/src/test/java/net/sf/javaanpr/recognizer/PatternComparatorTest.java index 4ee3d14..adb2e6f 100644 --- a/src/test/java/net/sf/javaanpr/recognizer/PatternComparatorTest.java +++ b/src/test/java/net/sf/javaanpr/recognizer/PatternComparatorTest.java @@ -19,6 +19,7 @@ import org.junit.Test; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; public class PatternComparatorTest { @@ -33,14 +34,16 @@ public void testCompareAscendingPatternsEqualReturnsZero() { public void testCompareAscendingFirstPatternSmallerReturnsMinusOne() { RecognizedPattern recognizedPattern1 = new RecognizedPattern('A', 1.0f); RecognizedPattern recognizedPattern2 = new RecognizedPattern('A', 2.0f); - assertEquals(new PatternComparator(false).compare(recognizedPattern1, recognizedPattern2), -1); + int comparisonResult = new PatternComparator(false).compare(recognizedPattern1, recognizedPattern2); + assertTrue("Expected comparison result " + comparisonResult + " to be less than 0", comparisonResult < 0); } @Test public void testCompareAscendingFirstPatternLargerReturnsPlusOne() { RecognizedPattern recognizedPattern1 = new RecognizedPattern('A', 2.0f); RecognizedPattern recognizedPattern2 = new RecognizedPattern('A', 1.0f); - assertEquals(new PatternComparator(false).compare(recognizedPattern1, recognizedPattern2), 1); + int comparisonResult = new PatternComparator(false).compare(recognizedPattern1, recognizedPattern2); + assertTrue("Expected comparison result " + comparisonResult + " to be greater than 0", comparisonResult > 0); } @Test @@ -54,13 +57,15 @@ public void testCompareDescendingPatternsEqualReturnsZero() { public void testCompareDescendingFirstPatternSmallerReturnsPlusOne() { RecognizedPattern recognizedPattern1 = new RecognizedPattern('A', 1.0f); RecognizedPattern recognizedPattern2 = new RecognizedPattern('A', 2.0f); - assertEquals(new PatternComparator(true).compare(recognizedPattern1, recognizedPattern2), 1); + int comparisonResult = new PatternComparator(true).compare(recognizedPattern1, recognizedPattern2); + assertTrue("Expected comparison result " + comparisonResult + " to be greater than 0", comparisonResult > 0); } @Test public void testCompareDescendingFirstPatternLargerReturnsMinusOne() { RecognizedPattern recognizedPattern1 = new RecognizedPattern('A', 2.0f); RecognizedPattern recognizedPattern2 = new RecognizedPattern('A', 1.0f); - assertEquals(new PatternComparator(true).compare(recognizedPattern1, recognizedPattern2), -1); + int comparisonResult = new PatternComparator(true).compare(recognizedPattern1, recognizedPattern2); + assertTrue("Expected comparison result " + comparisonResult + " to be less than 0", comparisonResult < 0); } }