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 53ca149..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 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 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 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 9afc87e..b933ead 100644 --- a/src/main/java/net/sf/javaanpr/recognizer/KnnPatternClassificator.java +++ b/src/main/java/net/sf/javaanpr/recognizer/KnnPatternClassificator.java @@ -60,9 +60,9 @@ 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 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 e34b792..66cc7e5 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,10 +90,10 @@ 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 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/PatternComparator.java b/src/main/java/net/sf/javaanpr/recognizer/PatternComparator.java new file mode 100644 index 0000000..6a273c2 --- /dev/null +++ b/src/main/java/net/sf/javaanpr/recognizer/PatternComparator.java @@ -0,0 +1,34 @@ +/* + * 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 PatternComparator implements Comparator { + private boolean shouldSortDescending; + + public PatternComparator(boolean shouldSortDescending) { + this.shouldSortDescending = shouldSortDescending; + } + + @Override + public int compare(RecognizedPattern recognizedPattern1, RecognizedPattern recognizedPattern2) { + Float cost1 = recognizedPattern1.getCost(); + Float cost2 = recognizedPattern2.getCost(); + return shouldSortDescending ? -1 * cost1.compareTo(cost2) : cost1.compareTo(cost2); + } +} 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..b82edee --- /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(boolean shouldSortDescending) { + if (this.isSorted) { + return; + } + this.isSorted = true; + Collections.sort(this.patterns, new PatternComparator(shouldSortDescending)); + } + + /** + * @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; + } +} diff --git a/src/test/java/net/sf/javaanpr/recognizer/PatternComparatorTest.java b/src/test/java/net/sf/javaanpr/recognizer/PatternComparatorTest.java new file mode 100644 index 0000000..adb2e6f --- /dev/null +++ b/src/test/java/net/sf/javaanpr/recognizer/PatternComparatorTest.java @@ -0,0 +1,71 @@ +/* + * 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; +import static org.junit.Assert.assertTrue; + +public class PatternComparatorTest { + + @Test + public void testCompareAscendingPatternsEqualReturnsZero() { + RecognizedPattern recognizedPattern1 = new RecognizedPattern('A', 1.0f); + RecognizedPattern recognizedPattern2 = new RecognizedPattern('B', 1.0f); + 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); + 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); + int comparisonResult = new PatternComparator(false).compare(recognizedPattern1, recognizedPattern2); + assertTrue("Expected comparison result " + comparisonResult + " to be greater than 0", comparisonResult > 0); + } + + @Test + public void testCompareDescendingPatternsEqualReturnsZero() { + RecognizedPattern recognizedPattern1 = new RecognizedPattern('A', 1.0f); + RecognizedPattern recognizedPattern2 = new RecognizedPattern('B', 1.0f); + 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); + 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); + int comparisonResult = new PatternComparator(true).compare(recognizedPattern1, recognizedPattern2); + assertTrue("Expected comparison result " + comparisonResult + " to be less than 0", comparisonResult < 0); + } +} diff --git a/src/test/java/net/sf/javaanpr/recognizer/RecognizedCharTest.java b/src/test/java/net/sf/javaanpr/recognizer/RecognizedCharTest.java new file mode 100644 index 0000000..7c15c13 --- /dev/null +++ b/src/test/java/net/sf/javaanpr/recognizer/RecognizedCharTest.java @@ -0,0 +1,70 @@ +/* + * 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.Before; +import org.junit.Test; + +import java.util.Vector; + +import static org.junit.Assert.*; + +public class RecognizedCharTest { + private static final double epsilon = 5.96e-08; + private RecognizedChar recognizedChar; + + @Before + public void setup() { + 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 + public void testPatternsCorrectlySortedAscending() { + assertFalse(recognizedChar.isSorted()); + recognizedChar.sort(false); + assertTrue(recognizedChar.isSorted()); + 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); + } + + @Test + public void testPatternsCorrectlySortedDescending() { + assertFalse(recognizedChar.isSorted()); + recognizedChar.sort(true); + assertTrue(recognizedChar.isSorted()); + 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); + } + + @Test + public void testGetPatternReturnsCorrectPatternWhenPatternsSorted() { + recognizedChar.sort(false); + assertEquals(recognizedChar.getPattern(2).getCost(), 4.0f, epsilon); + } + + @Test + public void testGetPatternReturnsNullWhenPatternsNotSorted() { + assertNull(recognizedChar.getPattern(2)); + } +}