mirror of
https://github.com/zxing/zxing.git
synced 2025-03-05 20:48:51 -08:00
More optimizations plus some improved RSS expanded misdetection detection
git-svn-id: https://zxing.googlecode.com/svn/trunk@2517 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
14b2eeb7ae
commit
6767168801
|
@ -99,10 +99,12 @@ public final class Code39Reader extends OneDReader {
|
||||||
public Result decodeRow(int rowNumber, BitArray row, Map<DecodeHintType,?> hints)
|
public Result decodeRow(int rowNumber, BitArray row, Map<DecodeHintType,?> hints)
|
||||||
throws NotFoundException, ChecksumException, FormatException {
|
throws NotFoundException, ChecksumException, FormatException {
|
||||||
|
|
||||||
Arrays.fill(counters, 0);
|
int[] theCounters = counters;
|
||||||
decodeRowResult.setLength(0);
|
Arrays.fill(theCounters, 0);
|
||||||
|
StringBuilder result = decodeRowResult;
|
||||||
|
result.setLength(0);
|
||||||
|
|
||||||
int[] start = findAsteriskPattern(row, counters);
|
int[] start = findAsteriskPattern(row, theCounters);
|
||||||
// Read off white space
|
// Read off white space
|
||||||
int nextStart = row.getNextSet(start[1]);
|
int nextStart = row.getNextSet(start[1]);
|
||||||
int end = row.getSize();
|
int end = row.getSize();
|
||||||
|
@ -110,25 +112,25 @@ public final class Code39Reader extends OneDReader {
|
||||||
char decodedChar;
|
char decodedChar;
|
||||||
int lastStart;
|
int lastStart;
|
||||||
do {
|
do {
|
||||||
recordPattern(row, nextStart, counters);
|
recordPattern(row, nextStart, theCounters);
|
||||||
int pattern = toNarrowWidePattern(counters);
|
int pattern = toNarrowWidePattern(theCounters);
|
||||||
if (pattern < 0) {
|
if (pattern < 0) {
|
||||||
throw NotFoundException.getNotFoundInstance();
|
throw NotFoundException.getNotFoundInstance();
|
||||||
}
|
}
|
||||||
decodedChar = patternToChar(pattern);
|
decodedChar = patternToChar(pattern);
|
||||||
decodeRowResult.append(decodedChar);
|
result.append(decodedChar);
|
||||||
lastStart = nextStart;
|
lastStart = nextStart;
|
||||||
for (int counter : counters) {
|
for (int counter : theCounters) {
|
||||||
nextStart += counter;
|
nextStart += counter;
|
||||||
}
|
}
|
||||||
// Read off white space
|
// Read off white space
|
||||||
nextStart = row.getNextSet(nextStart);
|
nextStart = row.getNextSet(nextStart);
|
||||||
} while (decodedChar != '*');
|
} while (decodedChar != '*');
|
||||||
decodeRowResult.setLength(decodeRowResult.length() - 1); // remove asterisk
|
result.setLength(result.length() - 1); // remove asterisk
|
||||||
|
|
||||||
// Look for whitespace after pattern:
|
// Look for whitespace after pattern:
|
||||||
int lastPatternSize = 0;
|
int lastPatternSize = 0;
|
||||||
for (int counter : counters) {
|
for (int counter : theCounters) {
|
||||||
lastPatternSize += counter;
|
lastPatternSize += counter;
|
||||||
}
|
}
|
||||||
int whiteSpaceAfterEnd = nextStart - lastStart - lastPatternSize;
|
int whiteSpaceAfterEnd = nextStart - lastStart - lastPatternSize;
|
||||||
|
@ -139,27 +141,27 @@ public final class Code39Reader extends OneDReader {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usingCheckDigit) {
|
if (usingCheckDigit) {
|
||||||
int max = decodeRowResult.length() - 1;
|
int max = result.length() - 1;
|
||||||
int total = 0;
|
int total = 0;
|
||||||
for (int i = 0; i < max; i++) {
|
for (int i = 0; i < max; i++) {
|
||||||
total += ALPHABET_STRING.indexOf(decodeRowResult.charAt(i));
|
total += ALPHABET_STRING.indexOf(decodeRowResult.charAt(i));
|
||||||
}
|
}
|
||||||
if (decodeRowResult.charAt(max) != ALPHABET[total % 43]) {
|
if (result.charAt(max) != ALPHABET[total % 43]) {
|
||||||
throw ChecksumException.getChecksumInstance();
|
throw ChecksumException.getChecksumInstance();
|
||||||
}
|
}
|
||||||
decodeRowResult.setLength(max);
|
result.setLength(max);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decodeRowResult.length() == 0) {
|
if (result.length() == 0) {
|
||||||
// false positive
|
// false positive
|
||||||
throw NotFoundException.getNotFoundInstance();
|
throw NotFoundException.getNotFoundInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
String resultString;
|
String resultString;
|
||||||
if (extendedMode) {
|
if (extendedMode) {
|
||||||
resultString = decodeExtended(decodeRowResult);
|
resultString = decodeExtended(result);
|
||||||
} else {
|
} else {
|
||||||
resultString = decodeRowResult.toString();
|
resultString = result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
float left = (float) (start[1] + start[0]) / 2.0f;
|
float left = (float) (start[1] + start[0]) / 2.0f;
|
||||||
|
|
|
@ -25,6 +25,7 @@ import com.google.zxing.Result;
|
||||||
import com.google.zxing.ResultPoint;
|
import com.google.zxing.ResultPoint;
|
||||||
import com.google.zxing.common.BitArray;
|
import com.google.zxing.common.BitArray;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -53,6 +54,14 @@ public final class Code93Reader extends OneDReader {
|
||||||
};
|
};
|
||||||
private static final int ASTERISK_ENCODING = CHARACTER_ENCODINGS[47];
|
private static final int ASTERISK_ENCODING = CHARACTER_ENCODINGS[47];
|
||||||
|
|
||||||
|
private final StringBuilder decodeRowResult;
|
||||||
|
private final int[] counters;
|
||||||
|
|
||||||
|
public Code93Reader() {
|
||||||
|
decodeRowResult = new StringBuilder(20);
|
||||||
|
counters = new int[6];
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result decodeRow(int rowNumber, BitArray row, Map<DecodeHintType,?> hints)
|
public Result decodeRow(int rowNumber, BitArray row, Map<DecodeHintType,?> hints)
|
||||||
throws NotFoundException, ChecksumException, FormatException {
|
throws NotFoundException, ChecksumException, FormatException {
|
||||||
|
@ -62,20 +71,23 @@ public final class Code93Reader extends OneDReader {
|
||||||
int nextStart = row.getNextSet(start[1]);
|
int nextStart = row.getNextSet(start[1]);
|
||||||
int end = row.getSize();
|
int end = row.getSize();
|
||||||
|
|
||||||
StringBuilder result = new StringBuilder(20);
|
int[] theCounters = counters;
|
||||||
int[] counters = new int[6];
|
Arrays.fill(theCounters, 0);
|
||||||
|
StringBuilder result = decodeRowResult;
|
||||||
|
result.setLength(0);
|
||||||
|
|
||||||
char decodedChar;
|
char decodedChar;
|
||||||
int lastStart;
|
int lastStart;
|
||||||
do {
|
do {
|
||||||
recordPattern(row, nextStart, counters);
|
recordPattern(row, nextStart, theCounters);
|
||||||
int pattern = toPattern(counters);
|
int pattern = toPattern(theCounters);
|
||||||
if (pattern < 0) {
|
if (pattern < 0) {
|
||||||
throw NotFoundException.getNotFoundInstance();
|
throw NotFoundException.getNotFoundInstance();
|
||||||
}
|
}
|
||||||
decodedChar = patternToChar(pattern);
|
decodedChar = patternToChar(pattern);
|
||||||
result.append(decodedChar);
|
result.append(decodedChar);
|
||||||
lastStart = nextStart;
|
lastStart = nextStart;
|
||||||
for (int counter : counters) {
|
for (int counter : theCounters) {
|
||||||
nextStart += counter;
|
nextStart += counter;
|
||||||
}
|
}
|
||||||
// Read off white space
|
// Read off white space
|
||||||
|
@ -111,33 +123,34 @@ public final class Code93Reader extends OneDReader {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int[] findAsteriskPattern(BitArray row) throws NotFoundException {
|
private int[] findAsteriskPattern(BitArray row) throws NotFoundException {
|
||||||
int width = row.getSize();
|
int width = row.getSize();
|
||||||
int rowOffset = row.getNextSet(0);
|
int rowOffset = row.getNextSet(0);
|
||||||
|
|
||||||
int counterPosition = 0;
|
Arrays.fill(counters, 0);
|
||||||
int[] counters = new int[6];
|
int[] theCounters = counters;
|
||||||
int patternStart = rowOffset;
|
int patternStart = rowOffset;
|
||||||
boolean isWhite = false;
|
boolean isWhite = false;
|
||||||
int patternLength = counters.length;
|
int patternLength = theCounters.length;
|
||||||
|
|
||||||
|
int counterPosition = 0;
|
||||||
for (int i = rowOffset; i < width; i++) {
|
for (int i = rowOffset; i < width; i++) {
|
||||||
if (row.get(i) ^ isWhite) {
|
if (row.get(i) ^ isWhite) {
|
||||||
counters[counterPosition]++;
|
theCounters[counterPosition]++;
|
||||||
} else {
|
} else {
|
||||||
if (counterPosition == patternLength - 1) {
|
if (counterPosition == patternLength - 1) {
|
||||||
if (toPattern(counters) == ASTERISK_ENCODING) {
|
if (toPattern(theCounters) == ASTERISK_ENCODING) {
|
||||||
return new int[]{patternStart, i};
|
return new int[]{patternStart, i};
|
||||||
}
|
}
|
||||||
patternStart += counters[0] + counters[1];
|
patternStart += theCounters[0] + theCounters[1];
|
||||||
System.arraycopy(counters, 2, counters, 0, patternLength - 2);
|
System.arraycopy(theCounters, 2, theCounters, 0, patternLength - 2);
|
||||||
counters[patternLength - 2] = 0;
|
theCounters[patternLength - 2] = 0;
|
||||||
counters[patternLength - 1] = 0;
|
theCounters[patternLength - 1] = 0;
|
||||||
counterPosition--;
|
counterPosition--;
|
||||||
} else {
|
} else {
|
||||||
counterPosition++;
|
counterPosition++;
|
||||||
}
|
}
|
||||||
counters[counterPosition] = 1;
|
theCounters[counterPosition] = 1;
|
||||||
isWhite = !isWhite;
|
isWhite = !isWhite;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,9 +71,13 @@ public final class RSS14Reader extends AbstractRSSReader {
|
||||||
Pair rightPair = decodePair(row, true, rowNumber, hints);
|
Pair rightPair = decodePair(row, true, rowNumber, hints);
|
||||||
addOrTally(possibleRightPairs, rightPair);
|
addOrTally(possibleRightPairs, rightPair);
|
||||||
row.reverse();
|
row.reverse();
|
||||||
for (Pair left : possibleLeftPairs) {
|
int lefSize = possibleLeftPairs.size();
|
||||||
|
for (int i = 0; i < lefSize; i++) {
|
||||||
|
Pair left = possibleLeftPairs.get(i);
|
||||||
if (left.getCount() > 1) {
|
if (left.getCount() > 1) {
|
||||||
for (Pair right : possibleRightPairs) {
|
int rightSize = possibleRightPairs.size();
|
||||||
|
for (int j = 0; j < rightSize; j++) {
|
||||||
|
Pair right = possibleRightPairs.get(j);
|
||||||
if (right.getCount() > 1) {
|
if (right.getCount() > 1) {
|
||||||
if (checkChecksum(left, right)) {
|
if (checkChecksum(left, right)) {
|
||||||
return constructResult(left, right);
|
return constructResult(left, right);
|
||||||
|
|
|
@ -89,7 +89,6 @@ public final class RSSExpandedReader extends AbstractRSSReader {
|
||||||
{ 45, 135, 194, 160, 58, 174, 100, 89}
|
{ 45, 135, 194, 160, 58, 174, 100, 89}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
private static final int FINDER_PAT_A = 0;
|
private static final int FINDER_PAT_A = 0;
|
||||||
private static final int FINDER_PAT_B = 1;
|
private static final int FINDER_PAT_B = 1;
|
||||||
private static final int FINDER_PAT_C = 2;
|
private static final int FINDER_PAT_C = 2;
|
||||||
|
@ -110,8 +109,7 @@ public final class RSSExpandedReader extends AbstractRSSReader {
|
||||||
{ FINDER_PAT_A, FINDER_PAT_A, FINDER_PAT_B, FINDER_PAT_B, FINDER_PAT_C, FINDER_PAT_D, FINDER_PAT_D, FINDER_PAT_E, FINDER_PAT_E, FINDER_PAT_F, FINDER_PAT_F },
|
{ FINDER_PAT_A, FINDER_PAT_A, FINDER_PAT_B, FINDER_PAT_B, FINDER_PAT_C, FINDER_PAT_D, FINDER_PAT_D, FINDER_PAT_E, FINDER_PAT_E, FINDER_PAT_F, FINDER_PAT_F },
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final int LONGEST_SEQUENCE_SIZE = FINDER_PATTERN_SEQUENCES[FINDER_PATTERN_SEQUENCES.length - 1].length;
|
//private static final int LONGEST_SEQUENCE_SIZE = FINDER_PATTERN_SEQUENCES[FINDER_PATTERN_SEQUENCES.length - 1].length;
|
||||||
*/
|
|
||||||
|
|
||||||
private static final int MAX_PAIRS = 11;
|
private static final int MAX_PAIRS = 11;
|
||||||
|
|
||||||
|
@ -188,24 +186,90 @@ public final class RSSExpandedReader extends AbstractRSSReader {
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ExpandedPair> checkRows(boolean reverse) {
|
private List<ExpandedPair> checkRows(boolean reverse) {
|
||||||
|
// Limit number of rows we are checking
|
||||||
|
// We use recursive algorithm with pure complexity and don't want it to take forever
|
||||||
|
// Stacked barcode can have up to 11 rows, so 25 seems resonable enough
|
||||||
|
if (this.rows.size() > 25) {
|
||||||
|
this.rows.clear(); // We will never have a chance to get result, so clear it
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
this.pairs.clear();
|
this.pairs.clear();
|
||||||
if (reverse) {
|
if (reverse) {
|
||||||
Collections.reverse(this.rows);
|
Collections.reverse(this.rows);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(ExpandedRow erow : this.rows) {
|
List<ExpandedPair> ps = null;
|
||||||
this.pairs.addAll(erow.getPairs());
|
try {
|
||||||
}
|
ps = checkRows(new ArrayList<ExpandedRow>(), 0);
|
||||||
//System.out.println(this.pairs.size()+" pairs on MULTIPLE ROWS: "+this.rows);
|
} catch (NotFoundException e) {
|
||||||
if (checkChecksum()) {
|
// OK
|
||||||
return this.pairs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reverse) {
|
if (reverse) {
|
||||||
Collections.reverse(this.rows);
|
Collections.reverse(this.rows);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return ps;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to construct a valid rows sequence
|
||||||
|
// Recursion is used to implement backtracking
|
||||||
|
private List<ExpandedPair> checkRows(List<ExpandedRow> collectedRows, int currentRow) throws NotFoundException {
|
||||||
|
for (int i = currentRow; i < rows.size(); i++) {
|
||||||
|
ExpandedRow row = rows.get(i);
|
||||||
|
this.pairs.clear();
|
||||||
|
int size = collectedRows.size();
|
||||||
|
for (int j = 0; j < size; j++) {
|
||||||
|
this.pairs.addAll(collectedRows.get(j).getPairs());
|
||||||
|
}
|
||||||
|
this.pairs.addAll(row.getPairs());
|
||||||
|
|
||||||
|
if (!isValidSequence(this.pairs)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkChecksum()) {
|
||||||
|
return this.pairs;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ExpandedRow> rs = new ArrayList<ExpandedRow>();
|
||||||
|
rs.addAll(collectedRows);
|
||||||
|
rs.add(row);
|
||||||
|
try {
|
||||||
|
// Recursion: try to add more rows
|
||||||
|
return checkRows(rs, i + 1);
|
||||||
|
} catch (NotFoundException e) {
|
||||||
|
// We failed, try the next candidate
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw NotFoundException.getNotFoundInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Whether the pairs form a valid find pattern seqience,
|
||||||
|
// either complete or a prefix
|
||||||
|
private static boolean isValidSequence(List<ExpandedPair> pairs) {
|
||||||
|
for (int[] sequence : FINDER_PATTERN_SEQUENCES) {
|
||||||
|
if (pairs.size() > sequence.length) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean stop = true;
|
||||||
|
for (int j = 0; j < pairs.size(); j++) {
|
||||||
|
if (pairs.get(j).getFinderPattern().getValue() != sequence[j]) {
|
||||||
|
stop = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stop) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void storeRow(int rowNumber, boolean wasReversed) {
|
private void storeRow(int rowNumber, boolean wasReversed) {
|
||||||
|
|
Loading…
Reference in a new issue