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 {
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

View file

@ -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) {

View file

@ -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;

View file

@ -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);
}