From 14895cf9b381ac8bf4d7fde34d2dfe69a966c94e Mon Sep 17 00:00:00 2001 From: srowen Date: Thu, 12 Jun 2008 15:17:53 +0000 Subject: [PATCH] Now use integer math in patternMatchVariance for performance, plus a few other similar style and speed tweaks git-svn-id: https://zxing.googlecode.com/svn/trunk@422 59b500cc-1b3d-0410-9834-0bbf25fbcc57 --- .../google/zxing/oned/AbstractOneDReader.java | 37 +++++++++++++------ .../zxing/oned/AbstractUPCEANReader.java | 18 ++++----- .../com/google/zxing/oned/Code128Reader.java | 10 ++--- .../zxing/qrcode/QRCodeBlackBox2TestCase.java | 2 +- 4 files changed, 40 insertions(+), 27 deletions(-) diff --git a/core/src/com/google/zxing/oned/AbstractOneDReader.java b/core/src/com/google/zxing/oned/AbstractOneDReader.java index fa1cbaf72..d642547d5 100644 --- a/core/src/com/google/zxing/oned/AbstractOneDReader.java +++ b/core/src/com/google/zxing/oned/AbstractOneDReader.java @@ -35,6 +35,8 @@ import java.util.Hashtable; */ public abstract class AbstractOneDReader implements OneDReader { + private static final int INTEGER_MATH_SHIFT = 8; + public final Result decode(MonochromeBitmapSource image) throws ReaderException { return decode(image, null); } @@ -181,26 +183,37 @@ public abstract class AbstractOneDReader implements OneDReader { * * @param counters observed counters * @param pattern expected pattern - * @return average variance between counters and pattern + * @return ratio of total variance between counters and pattern compared to total pattern size, + * where the ratio has been multiplied by 256. So, 0 means no variance (perfect match); 256 means + * the total variance between counters and patterns equals the pattern length, higher values mean + * even more variance */ - static float patternMatchVariance(int[] counters, int[] pattern) { - int total = 0; + static int patternMatchVariance(int[] counters, int[] pattern) { int numCounters = counters.length; + int total = 0; int patternLength = 0; for (int i = 0; i < numCounters; i++) { total += counters[i]; patternLength += pattern[i]; } - float unitBarWidth = (float) total / (float) patternLength; - - float totalVariance = 0.0f; - for (int x = 0; x < numCounters; x++) { - float scaledCounter = (float) counters[x] / unitBarWidth; - float width = pattern[x]; - float abs = scaledCounter > width ? scaledCounter - width : width - scaledCounter; - totalVariance += abs; + if (total < patternLength) { + // If we don't even have one pixel per unit of bar width, assume this is too small + // to reliably match, so fail: + return Integer.MAX_VALUE; } - return totalVariance / (float) patternLength; + // We're going to fake floating-point math in integers. We just need to use more bits. + // Scale up patternLength so that intermediate values below like scaledCounter will have + // more "significant digits" + patternLength <<= INTEGER_MATH_SHIFT; + int patternRatio = patternLength / total; + + int totalVariance = 0; + for (int x = 0; x < numCounters; x++) { + int scaledCounter = counters[x] * patternRatio; + int width = pattern[x] << INTEGER_MATH_SHIFT; + totalVariance += scaledCounter > width ? scaledCounter - width : width - scaledCounter; + } + return (totalVariance << 8) / patternLength; } // This declaration should not be necessary, since this class is diff --git a/core/src/com/google/zxing/oned/AbstractUPCEANReader.java b/core/src/com/google/zxing/oned/AbstractUPCEANReader.java index b4800128f..f4b1fa606 100644 --- a/core/src/com/google/zxing/oned/AbstractUPCEANReader.java +++ b/core/src/com/google/zxing/oned/AbstractUPCEANReader.java @@ -35,7 +35,7 @@ import java.util.Hashtable; */ public abstract class AbstractUPCEANReader extends AbstractOneDReader implements UPCEANReader { - private static final float MAX_VARIANCE = 0.4f; + private static final int MAX_VARIANCE = 104; /** * Start/end guard pattern. @@ -102,9 +102,8 @@ public abstract class AbstractUPCEANReader extends AbstractOneDReader implements return decodeRow(rowNumber, row, findStartGuardPattern(row)); } - public final Result decodeRow(int rowNumber, BitArray row, int[] startGuardRange) - throws ReaderException { - StringBuffer result = new StringBuffer(); + public final Result decodeRow(int rowNumber, BitArray row, int[] startGuardRange) throws ReaderException { + StringBuffer result = new StringBuffer(20); int endStart = decodeMiddle(row, startGuardRange, result); int[] endRange = decodeEnd(row, endStart); @@ -243,14 +242,15 @@ public abstract class AbstractUPCEANReader extends AbstractOneDReader implements static int decodeDigit(BitArray row, int[] counters, int rowOffset, int[][] patterns) throws ReaderException { recordPattern(row, rowOffset, counters); - float bestVariance = MAX_VARIANCE; // worst variance we'll accept + int bestVariance = MAX_VARIANCE; // worst variance we'll accept int bestMatch = -1; - for (int d = 0; d < patterns.length; d++) { - int[] pattern = patterns[d]; - float variance = patternMatchVariance(counters, pattern); + int max = patterns.length; + for (int i = 0; i < max; i++) { + int[] pattern = patterns[i]; + int variance = patternMatchVariance(counters, pattern); if (variance < bestVariance) { bestVariance = variance; - bestMatch = d; + bestMatch = i; } } if (bestMatch >= 0) { diff --git a/core/src/com/google/zxing/oned/Code128Reader.java b/core/src/com/google/zxing/oned/Code128Reader.java index 7a59bbd9a..eec326efd 100644 --- a/core/src/com/google/zxing/oned/Code128Reader.java +++ b/core/src/com/google/zxing/oned/Code128Reader.java @@ -142,7 +142,7 @@ public final class Code128Reader extends AbstractOneDReader { {2, 3, 3, 1, 1, 1, 2} }; - private static final float MAX_VARIANCE = 0.3f; + private static final int MAX_VARIANCE = 56; private static final int CODE_SHIFT = 98; @@ -183,10 +183,10 @@ public final class Code128Reader extends AbstractOneDReader { counters[counterPosition]++; } else { if (counterPosition == patternLength - 1) { - float bestVariance = MAX_VARIANCE; + int bestVariance = MAX_VARIANCE; int bestMatch = -1; for (int startCode = CODE_START_A; startCode <= CODE_START_C; startCode++) { - float variance = patternMatchVariance(counters, CODE_PATTERNS[startCode]); + int variance = patternMatchVariance(counters, CODE_PATTERNS[startCode]); if (variance < bestVariance) { bestVariance = variance; bestMatch = startCode; @@ -214,11 +214,11 @@ public final class Code128Reader extends AbstractOneDReader { private static int decodeCode(BitArray row, int[] counters, int rowOffset) throws ReaderException { recordPattern(row, rowOffset, counters); - float bestVariance = MAX_VARIANCE; // worst variance we'll accept + int bestVariance = MAX_VARIANCE; // worst variance we'll accept int bestMatch = -1; for (int d = 0; d < CODE_PATTERNS.length; d++) { int[] pattern = CODE_PATTERNS[d]; - float variance = patternMatchVariance(counters, pattern); + int variance = patternMatchVariance(counters, pattern); if (variance < bestVariance) { bestVariance = variance; bestMatch = d; diff --git a/core/test/src/com/google/zxing/qrcode/QRCodeBlackBox2TestCase.java b/core/test/src/com/google/zxing/qrcode/QRCodeBlackBox2TestCase.java index a7a5988bb..7dc00f717 100644 --- a/core/test/src/com/google/zxing/qrcode/QRCodeBlackBox2TestCase.java +++ b/core/test/src/com/google/zxing/qrcode/QRCodeBlackBox2TestCase.java @@ -30,7 +30,7 @@ public final class QRCodeBlackBox2TestCase extends AbstractBlackBoxTestCase { public QRCodeBlackBox2TestCase() { super(new File("test/data/blackbox/qrcode-2"), new MultiFormatReader(), BarcodeFormat.QR_CODE); addTest(10, 0.0f); - addTest(5, 90.0f); + addTest(6, 90.0f); addTest(8, 180.0f); addTest(2, 270.0f); }