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
This commit is contained in:
srowen 2008-06-12 15:17:53 +00:00
parent 038add9da1
commit 14895cf9b3
4 changed files with 40 additions and 27 deletions

View file

@ -35,6 +35,8 @@ import java.util.Hashtable;
*/ */
public abstract class AbstractOneDReader implements OneDReader { public abstract class AbstractOneDReader implements OneDReader {
private static final int INTEGER_MATH_SHIFT = 8;
public final Result decode(MonochromeBitmapSource image) throws ReaderException { public final Result decode(MonochromeBitmapSource image) throws ReaderException {
return decode(image, null); return decode(image, null);
} }
@ -181,26 +183,37 @@ public abstract class AbstractOneDReader implements OneDReader {
* *
* @param counters observed counters * @param counters observed counters
* @param pattern expected pattern * @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) { static int patternMatchVariance(int[] counters, int[] pattern) {
int total = 0;
int numCounters = counters.length; int numCounters = counters.length;
int total = 0;
int patternLength = 0; int patternLength = 0;
for (int i = 0; i < numCounters; i++) { for (int i = 0; i < numCounters; i++) {
total += counters[i]; total += counters[i];
patternLength += pattern[i]; patternLength += pattern[i];
} }
float unitBarWidth = (float) total / (float) patternLength; if (total < patternLength) {
// If we don't even have one pixel per unit of bar width, assume this is too small
float totalVariance = 0.0f; // to reliably match, so fail:
for (int x = 0; x < numCounters; x++) { return Integer.MAX_VALUE;
float scaledCounter = (float) counters[x] / unitBarWidth;
float width = pattern[x];
float abs = scaledCounter > width ? scaledCounter - width : width - scaledCounter;
totalVariance += abs;
} }
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 // This declaration should not be necessary, since this class is

View file

@ -35,7 +35,7 @@ import java.util.Hashtable;
*/ */
public abstract class AbstractUPCEANReader extends AbstractOneDReader implements UPCEANReader { 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. * Start/end guard pattern.
@ -102,9 +102,8 @@ public abstract class AbstractUPCEANReader extends AbstractOneDReader implements
return decodeRow(rowNumber, row, findStartGuardPattern(row)); return decodeRow(rowNumber, row, findStartGuardPattern(row));
} }
public final Result decodeRow(int rowNumber, BitArray row, int[] startGuardRange) public final Result decodeRow(int rowNumber, BitArray row, int[] startGuardRange) throws ReaderException {
throws ReaderException { StringBuffer result = new StringBuffer(20);
StringBuffer result = new StringBuffer();
int endStart = decodeMiddle(row, startGuardRange, result); int endStart = decodeMiddle(row, startGuardRange, result);
int[] endRange = decodeEnd(row, endStart); 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) static int decodeDigit(BitArray row, int[] counters, int rowOffset, int[][] patterns)
throws ReaderException { throws ReaderException {
recordPattern(row, rowOffset, counters); 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; int bestMatch = -1;
for (int d = 0; d < patterns.length; d++) { int max = patterns.length;
int[] pattern = patterns[d]; for (int i = 0; i < max; i++) {
float variance = patternMatchVariance(counters, pattern); int[] pattern = patterns[i];
int variance = patternMatchVariance(counters, pattern);
if (variance < bestVariance) { if (variance < bestVariance) {
bestVariance = variance; bestVariance = variance;
bestMatch = d; bestMatch = i;
} }
} }
if (bestMatch >= 0) { if (bestMatch >= 0) {

View file

@ -142,7 +142,7 @@ public final class Code128Reader extends AbstractOneDReader {
{2, 3, 3, 1, 1, 1, 2} {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; private static final int CODE_SHIFT = 98;
@ -183,10 +183,10 @@ public final class Code128Reader extends AbstractOneDReader {
counters[counterPosition]++; counters[counterPosition]++;
} else { } else {
if (counterPosition == patternLength - 1) { if (counterPosition == patternLength - 1) {
float bestVariance = MAX_VARIANCE; int bestVariance = MAX_VARIANCE;
int bestMatch = -1; int bestMatch = -1;
for (int startCode = CODE_START_A; startCode <= CODE_START_C; startCode++) { 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) { if (variance < bestVariance) {
bestVariance = variance; bestVariance = variance;
bestMatch = startCode; bestMatch = startCode;
@ -214,11 +214,11 @@ public final class Code128Reader extends AbstractOneDReader {
private static int decodeCode(BitArray row, int[] counters, int rowOffset) throws ReaderException { private static int decodeCode(BitArray row, int[] counters, int rowOffset) throws ReaderException {
recordPattern(row, rowOffset, counters); 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; int bestMatch = -1;
for (int d = 0; d < CODE_PATTERNS.length; d++) { for (int d = 0; d < CODE_PATTERNS.length; d++) {
int[] pattern = CODE_PATTERNS[d]; int[] pattern = CODE_PATTERNS[d];
float variance = patternMatchVariance(counters, pattern); int variance = patternMatchVariance(counters, pattern);
if (variance < bestVariance) { if (variance < bestVariance) {
bestVariance = variance; bestVariance = variance;
bestMatch = d; bestMatch = d;

View file

@ -30,7 +30,7 @@ public final class QRCodeBlackBox2TestCase extends AbstractBlackBoxTestCase {
public QRCodeBlackBox2TestCase() { public QRCodeBlackBox2TestCase() {
super(new File("test/data/blackbox/qrcode-2"), new MultiFormatReader(), BarcodeFormat.QR_CODE); super(new File("test/data/blackbox/qrcode-2"), new MultiFormatReader(), BarcodeFormat.QR_CODE);
addTest(10, 0.0f); addTest(10, 0.0f);
addTest(5, 90.0f); addTest(6, 90.0f);
addTest(8, 180.0f); addTest(8, 180.0f);
addTest(2, 270.0f); addTest(2, 270.0f);
} }