mirror of
https://github.com/zxing/zxing.git
synced 2025-03-05 20:48:51 -08:00
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:
parent
038add9da1
commit
14895cf9b3
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue