diff --git a/src/main/java/net/sf/javaanpr/imageanalysis/Band.java b/src/main/java/net/sf/javaanpr/imageanalysis/Band.java index 0a0ed33..58e7370 100644 --- a/src/main/java/net/sf/javaanpr/imageanalysis/Band.java +++ b/src/main/java/net/sf/javaanpr/imageanalysis/Band.java @@ -39,7 +39,7 @@ public BufferedImage renderGraph() { return this.graphHandle.renderHorizontally(this.getWidth(), 100); } - private Vector computeGraph() { + private Vector computeGraph() { if (this.graphHandle != null) { return this.graphHandle.peaks; } @@ -59,12 +59,12 @@ private Vector computeGraph() { */ public Vector getPlates() { Vector out = new Vector(); - Vector peaks = this.computeGraph(); + Vector peaks = this.computeGraph(); for (int i = 0; i < peaks.size(); i++) { // Cut from the original image of the plate and save to a vector. // ATTENTION: Cutting from original, // we have to apply an inverse transformation to the coordinates calculated from imageCopy - Graph.Peak p = peaks.elementAt(i); + Peak p = peaks.elementAt(i); out.add(new Plate(getImage().getSubimage(p.getLeft(), 0, p.getDiff(), getImage().getHeight()))); } return out; diff --git a/src/main/java/net/sf/javaanpr/imageanalysis/BandGraph.java b/src/main/java/net/sf/javaanpr/imageanalysis/BandGraph.java index 5fca076..ed382ae 100644 --- a/src/main/java/net/sf/javaanpr/imageanalysis/BandGraph.java +++ b/src/main/java/net/sf/javaanpr/imageanalysis/BandGraph.java @@ -45,7 +45,7 @@ public BandGraph(Band handle) { } public Vector findPeaks(int count) { - Vector outPeaks = new Vector(); + Vector outPeaks = new Vector(); for (int c = 0; c < count; c++) { float maxValue = 0.0f; int maxIndex = 0; diff --git a/src/main/java/net/sf/javaanpr/imageanalysis/CarSnapshot.java b/src/main/java/net/sf/javaanpr/imageanalysis/CarSnapshot.java index 98acedd..10189ee 100644 --- a/src/main/java/net/sf/javaanpr/imageanalysis/CarSnapshot.java +++ b/src/main/java/net/sf/javaanpr/imageanalysis/CarSnapshot.java @@ -54,7 +54,7 @@ public BufferedImage renderGraph() { return this.graphHandle.renderVertically(100, this.getHeight()); } - private Vector computeGraph() { + private Vector computeGraph() { if (this.graphHandle != null) { return this.graphHandle.peaks; } @@ -75,12 +75,12 @@ private Vector computeGraph() { */ public Vector getBands() { Vector out = new Vector(); - Vector peaks = this.computeGraph(); + Vector peaks = this.computeGraph(); for (int i = 0; i < peaks.size(); i++) { // Cut from the original image of the plate and save to a vector. // ATTENTION: Cutting from original, // we have to apply an inverse transformation to the coordinates calculated from imageCopy - Graph.Peak p = peaks.elementAt(i); + Peak p = peaks.elementAt(i); out.add(new Band(getImage().getSubimage(0, (p.getLeft()), getImage().getWidth(), (p.getDiff())))); } return out; diff --git a/src/main/java/net/sf/javaanpr/imageanalysis/Graph.java b/src/main/java/net/sf/javaanpr/imageanalysis/Graph.java index 1070bc3..fcf5cca 100644 --- a/src/main/java/net/sf/javaanpr/imageanalysis/Graph.java +++ b/src/main/java/net/sf/javaanpr/imageanalysis/Graph.java @@ -48,7 +48,7 @@ public void deActualizeFlags() { */ public boolean allowedInterval(Vector peaks, int xPosition) { for (Peak peak : peaks) { - if ((peak.left <= xPosition) && (xPosition <= peak.right)) { + if ((peak.getLeft() <= xPosition) && (xPosition <= peak.getRight())) { return false; } } @@ -185,9 +185,9 @@ public BufferedImage renderHorizontally(int width, int height) { final double multConst = (double) width / this.yValues.size(); int i = 0; for (Peak p : this.peaks) { - graphicContent.drawLine((int) (p.left * multConst), 0, (int) (p.center * multConst), 30); - graphicContent.drawLine((int) (p.center * multConst), 30, (int) (p.right * multConst), 0); - graphicContent.drawString(i + ".", (int) (p.center * multConst) - 5, 42); + graphicContent.drawLine((int) (p.getLeft() * multConst), 0, (int) (p.getCenter() * multConst), 30); + graphicContent.drawLine((int) (p.getCenter() * multConst), 30, (int) (p.getRight() * multConst), 0); + graphicContent.drawString(i + ".", (int) (p.getCenter() * multConst) - 5, 42); i++; } } @@ -237,9 +237,13 @@ public BufferedImage renderVertically(int width, int height) { int i = 0; double multConst = (double) height / this.yValues.size(); for (Peak p : this.peaks) { - graphicContent.drawLine(width, (int) (p.left * multConst), width - 30, (int) (p.center * multConst)); - graphicContent.drawLine(width - 30, (int) (p.center * multConst), width, (int) (p.right * multConst)); - graphicContent.drawString(i + ".", width - 38, (int) (p.center * multConst) + 5); + graphicContent.drawLine(width, + (int) (p.getLeft() * multConst), + width - 30, (int) (p.getCenter() * multConst)); + graphicContent.drawLine(width - 30, + (int) (p.getCenter() * multConst), width, + (int) (p.getRight() * multConst)); + graphicContent.drawString(i + ".", width - 38, (int) (p.getCenter() * multConst) + 5); i++; } } @@ -330,48 +334,4 @@ public Vector distribute(Vector peaks) { return distributedPeaks; } } - - public class Peak { - private int left, center, right; - - public Peak(int left, int center, int right) { - this.left = left; - this.center = center; - this.right = right; - } - - public Peak(int left, int right) { - this.left = left; - this.center = (left + right) / 2; - this.right = right; - } - - public int getLeft() { - return this.left; - } - - public void setLeft(int left) { - this.left = left; - } - - public int getRight() { - return this.right; - } - - public void setRight(int right) { - this.right = right; - } - - public int getCenter() { - return this.center; - } - - public void setCenter(int center) { - this.center = center; - } - - public int getDiff() { - return this.right - this.left; - } - } } diff --git a/src/main/java/net/sf/javaanpr/imageanalysis/Peak.java b/src/main/java/net/sf/javaanpr/imageanalysis/Peak.java new file mode 100644 index 0000000..fb77572 --- /dev/null +++ b/src/main/java/net/sf/javaanpr/imageanalysis/Peak.java @@ -0,0 +1,61 @@ +/* + * 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.imageanalysis; + +public class Peak { + private int left, center, right; + + public Peak(int left, int center, int right) { + this.left = left; + this.center = center; + this.right = right; + } + + public Peak(int left, int right) { + this.left = left; + this.center = (left + right) / 2; + this.right = right; + } + + public int getLeft() { + return this.left; + } + + public void setLeft(int left) { + this.left = left; + } + + public int getRight() { + return this.right; + } + + public void setRight(int right) { + this.right = right; + } + + public int getCenter() { + return this.center; + } + + public void setCenter(int center) { + this.center = center; + } + + public int getDiff() { + return this.right - this.left; + } +} diff --git a/src/main/java/net/sf/javaanpr/imageanalysis/PeakComparator.java b/src/main/java/net/sf/javaanpr/imageanalysis/PeakComparator.java new file mode 100644 index 0000000..d0cc4f5 --- /dev/null +++ b/src/main/java/net/sf/javaanpr/imageanalysis/PeakComparator.java @@ -0,0 +1,45 @@ +/* + * 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.imageanalysis; + +import java.util.Comparator; +import java.util.Vector; + +public class PeakComparator implements Comparator { + private Vector yValues; + + public PeakComparator(Vector yValues) { + this.yValues = yValues; + } + + private float getPeakValue(Peak peak) { + // heuristic: how high (wide on the graph) is the candidate character (prefer higher ones) + // return peak.getDiff(); + + // heuristic: height of the peak + return yValues.elementAt(peak.getCenter()); + + // heuristic: how far from the center is the candidate + // int peakCenter = (peak.getRight() + (peak.getLeft() )/2; + // return Math.abs(peakCenter - yValues.size()/2); + } + + @Override + public int compare(Peak peak1, Peak peak2) { + return Double.compare(getPeakValue(peak2), getPeakValue(peak1)); + } +} diff --git a/src/main/java/net/sf/javaanpr/imageanalysis/Plate.java b/src/main/java/net/sf/javaanpr/imageanalysis/Plate.java index b5c3af9..3c4cc21 100644 --- a/src/main/java/net/sf/javaanpr/imageanalysis/Plate.java +++ b/src/main/java/net/sf/javaanpr/imageanalysis/Plate.java @@ -47,7 +47,7 @@ public BufferedImage renderGraph() { return this.graphHandle.renderHorizontally(this.getWidth(), 100); } - private Vector computeGraph() { + private Vector computeGraph() { if (this.graphHandle != null) { return this.graphHandle.peaks; } @@ -59,12 +59,12 @@ private Vector computeGraph() { public Vector getChars() { Vector out = new Vector(); - Vector peaks = this.computeGraph(); + Vector peaks = this.computeGraph(); for (int i = 0; i < peaks.size(); i++) { // Cut from the original image of the plate and save to a vector. // ATTENTION: Cutting from original, // we have to apply an inverse transformation to the coordinates calculated from imageCopy - Graph.Peak p = peaks.elementAt(i); + Peak p = peaks.elementAt(i); if (p.getDiff() <= 0) { continue; } @@ -121,15 +121,15 @@ public void normalize() { private BufferedImage cutTopBottom(BufferedImage origin, PlateVerticalGraph graph) { graph.applyProbabilityDistributor(new Graph.ProbabilityDistributor(0f, 0f, 2, 2)); - Graph.Peak p = graph.findPeak(3).elementAt(0); + Peak p = graph.findPeak(3).elementAt(0); return origin.getSubimage(0, p.getLeft(), getImage().getWidth(), p.getDiff()); } private BufferedImage cutLeftRight(BufferedImage origin, PlateHorizontalGraph graph) { graph.applyProbabilityDistributor(new Graph.ProbabilityDistributor(0f, 0f, 2, 2)); - Vector peaks = graph.findPeak(); + Vector peaks = graph.findPeak(); if (peaks.size() != 0) { - Graph.Peak p = peaks.elementAt(0); + Peak p = peaks.elementAt(0); return origin.getSubimage(p.getLeft(), 0, p.getDiff(), getImage().getHeight()); } return origin; @@ -148,7 +148,7 @@ public PlateGraph histogram(BufferedImage bi) { } private PlateVerticalGraph histogramYaxis(BufferedImage bi) { - PlateVerticalGraph graph = new PlateVerticalGraph(this); + PlateVerticalGraph graph = new PlateVerticalGraph(); int w = bi.getWidth(); int h = bi.getHeight(); for (int y = 0; y < h; y++) { diff --git a/src/main/java/net/sf/javaanpr/imageanalysis/PlateVerticalGraph.java b/src/main/java/net/sf/javaanpr/imageanalysis/PlateVerticalGraph.java index 2fa9ab5..3375e0b 100644 --- a/src/main/java/net/sf/javaanpr/imageanalysis/PlateVerticalGraph.java +++ b/src/main/java/net/sf/javaanpr/imageanalysis/PlateVerticalGraph.java @@ -19,7 +19,6 @@ import net.sf.javaanpr.configurator.Configurator; import java.util.Collections; -import java.util.Comparator; import java.util.Vector; public class PlateVerticalGraph extends Graph { @@ -27,72 +26,33 @@ public class PlateVerticalGraph extends Graph { private static final double peakFootConstant = Configurator.getConfigurator().getDoubleProperty("plateverticalgraph_peakfootconstant"); // 0.42 - private Plate handle; - - public PlateVerticalGraph(Plate handle) { - this.handle = handle; - } - public Vector findPeak(int count) { // lower the peak - for (int i = 0; i < this.yValues.size(); i++) { - this.yValues.set(i, this.yValues.elementAt(i) - this.getMinValue()); + for (int i = 0; i < yValues.size(); i++) { + yValues.set(i, yValues.elementAt(i) - getMinValue()); } Vector outPeaks = new Vector(); for (int c = 0; c < count; c++) { float maxValue = 0.0f; int maxIndex = 0; - for (int i = 0; i < this.yValues.size(); i++) { // left to right - if (this.allowedInterval(outPeaks, i)) { - if (this.yValues.elementAt(i) >= maxValue) { - maxValue = this.yValues.elementAt(i); + for (int i = 0; i < yValues.size(); i++) { // left to right + if (allowedInterval(outPeaks, i)) { + if (yValues.elementAt(i) >= maxValue) { + maxValue = yValues.elementAt(i); maxIndex = i; } } } // we found the biggest peak - if (this.yValues.elementAt(maxIndex) < (0.05 * super.getMaxValue())) { + if (yValues.elementAt(maxIndex) < (0.05 * super.getMaxValue())) { break; // 0.4 } - int leftIndex = this.indexOfLeftPeakRel(maxIndex, PlateVerticalGraph.peakFootConstant); - int rightIndex = this.indexOfRightPeakRel(maxIndex, PlateVerticalGraph.peakFootConstant); - outPeaks.add(new Peak(Math.max(0, leftIndex), maxIndex, Math.min(this.yValues.size() - 1, rightIndex))); + int leftIndex = indexOfLeftPeakRel(maxIndex, PlateVerticalGraph.peakFootConstant); + int rightIndex = indexOfRightPeakRel(maxIndex, PlateVerticalGraph.peakFootConstant); + outPeaks.add(new Peak(Math.max(0, leftIndex), maxIndex, Math.min(yValues.size() - 1, rightIndex))); } - Collections.sort(outPeaks, new PeakComparer(this)); + Collections.sort(outPeaks, new PeakComparator(yValues)); super.peaks = outPeaks; return outPeaks; } - - public class PeakComparer implements Comparator { - - private PlateVerticalGraph graphHandle = null; - - public PeakComparer(PlateVerticalGraph graph) { - this.graphHandle = graph; - } - - private float getPeakValue(Object peak) { - // heuristic: how high (wide on the graph) is the candidate character (prefer higher ones) - // return ((Peak)peak).getDiff(); - - // heuristic: height of the peak - return this.graphHandle.yValues.elementAt(((Peak) peak).getCenter()); - - // heuristic: how far from the center is the candidate - // int peakCenter = ( ((Peak)peak).getRight() + ((Peak)peak).getLeft() )/2; - // return Math.abs(peakCenter - this.graphHandle.yValues.size()/2); - } - - @Override - public int compare(Object peak1, Object peak2) { - double comparison = this.getPeakValue(peak2) - this.getPeakValue(peak1); - if (comparison < 0) { - return -1; - } - if (comparison > 0) { - return 1; - } - return 0; - } - } } diff --git a/src/test/java/net/sf/javaanpr/imageanalysis/PeakComparatorTest.java b/src/test/java/net/sf/javaanpr/imageanalysis/PeakComparatorTest.java new file mode 100644 index 0000000..433456a --- /dev/null +++ b/src/test/java/net/sf/javaanpr/imageanalysis/PeakComparatorTest.java @@ -0,0 +1,69 @@ +/* + * 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.imageanalysis; + +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Vector; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class PeakComparatorTest { + PeakComparator peakComparator; + Peak peak1; + Peak peak2; + + @Before + public void setup() { + Vector yValues = new Vector(Arrays.asList(new Float[] {1.0f, 2.0f})); + peakComparator = new PeakComparator(yValues); + peak1 = mock(Peak.class); + peak2 = mock(Peak.class); + } + + @Test + public void testCompareEqualPeaksReturnsZero() { + when(peak1.getCenter()).thenReturn(0); + when(peak2.getCenter()).thenReturn(0); + assertEquals(peakComparator.compare(peak1, peak2), 0); + } + + @Test + public void testCompareFirstPeakSmallerReturnsResultGreaterThanZero() { + when(peak1.getCenter()).thenReturn(0); + when(peak2.getCenter()).thenReturn(1); + int comparisonResult = peakComparator.compare(peak1, peak2); + assertTrue("Expecting a result which is greater than 0 when comparing peak with centre " + peak1.getCenter() + + " to peak with centre " + peak2.getCenter() + ". Got result " + comparisonResult, + comparisonResult > 0); + } + + @Test + public void testCompareFirstPeakLargerReturnsResultLessThanZero() { + when(peak1.getCenter()).thenReturn(1); + when(peak2.getCenter()).thenReturn(0); + int comparisonResult = peakComparator.compare(peak1, peak2); + assertTrue("Expecting a result which is less than 0 when comparing peak with centre " + peak1.getCenter() + + " to peak with centre " + peak2.getCenter() + ". Got result " + comparisonResult, + comparisonResult < 0); + } +}