mirror of
https://github.com/zxing/zxing.git
synced 2024-11-09 20:44:03 -08:00
Try a diagonal cross check in PURE_BARCODE mode for QR codes to avoid false positives. HT fics.danmark
This commit is contained in:
parent
a8772054af
commit
be038c7eef
1
AUTHORS
1
AUTHORS
|
@ -37,6 +37,7 @@ Emanuele Aina
|
||||||
Eric Kobrin (Velocitude)
|
Eric Kobrin (Velocitude)
|
||||||
evansepdx
|
evansepdx
|
||||||
Erik Barbara
|
Erik Barbara
|
||||||
|
fics.danmark
|
||||||
Francois B. (Google)
|
Francois B. (Google)
|
||||||
Frank Yellin
|
Frank Yellin
|
||||||
Fred Lin (Anobiit)
|
Fred Lin (Anobiit)
|
||||||
|
|
|
@ -230,6 +230,7 @@ final class MultiFinderPatternFinder extends FinderPatternFinder {
|
||||||
|
|
||||||
public FinderPatternInfo[] findMulti(Map<DecodeHintType,?> hints) throws NotFoundException {
|
public FinderPatternInfo[] findMulti(Map<DecodeHintType,?> hints) throws NotFoundException {
|
||||||
boolean tryHarder = hints != null && hints.containsKey(DecodeHintType.TRY_HARDER);
|
boolean tryHarder = hints != null && hints.containsKey(DecodeHintType.TRY_HARDER);
|
||||||
|
boolean pureBarcode = hints != null && hints.containsKey(DecodeHintType.PURE_BARCODE);
|
||||||
BitMatrix image = getImage();
|
BitMatrix image = getImage();
|
||||||
int maxI = image.getHeight();
|
int maxI = image.getHeight();
|
||||||
int maxJ = image.getWidth();
|
int maxJ = image.getWidth();
|
||||||
|
@ -264,7 +265,7 @@ final class MultiFinderPatternFinder extends FinderPatternFinder {
|
||||||
} else { // White pixel
|
} else { // White pixel
|
||||||
if ((currentState & 1) == 0) { // Counting black pixels
|
if ((currentState & 1) == 0) { // Counting black pixels
|
||||||
if (currentState == 4) { // A winner?
|
if (currentState == 4) { // A winner?
|
||||||
if (foundPatternCross(stateCount) && handlePossibleCenter(stateCount, i, j)) { // Yes
|
if (foundPatternCross(stateCount) && handlePossibleCenter(stateCount, i, j, pureBarcode)) { // Yes
|
||||||
// Clear state to start looking again
|
// Clear state to start looking again
|
||||||
currentState = 0;
|
currentState = 0;
|
||||||
stateCount[0] = 0;
|
stateCount[0] = 0;
|
||||||
|
@ -290,7 +291,7 @@ final class MultiFinderPatternFinder extends FinderPatternFinder {
|
||||||
} // for j=...
|
} // for j=...
|
||||||
|
|
||||||
if (foundPatternCross(stateCount)) {
|
if (foundPatternCross(stateCount)) {
|
||||||
handlePossibleCenter(stateCount, i, maxJ);
|
handlePossibleCenter(stateCount, i, maxJ, pureBarcode);
|
||||||
} // end if foundPatternCross
|
} // end if foundPatternCross
|
||||||
} // for i=iSkip-1 ...
|
} // for i=iSkip-1 ...
|
||||||
FinderPattern[][] patternInfo = selectMutipleBestPatterns();
|
FinderPattern[][] patternInfo = selectMutipleBestPatterns();
|
||||||
|
|
|
@ -76,6 +76,7 @@ public class FinderPatternFinder {
|
||||||
|
|
||||||
final FinderPatternInfo find(Map<DecodeHintType,?> hints) throws NotFoundException {
|
final FinderPatternInfo find(Map<DecodeHintType,?> hints) throws NotFoundException {
|
||||||
boolean tryHarder = hints != null && hints.containsKey(DecodeHintType.TRY_HARDER);
|
boolean tryHarder = hints != null && hints.containsKey(DecodeHintType.TRY_HARDER);
|
||||||
|
boolean pureBarcode = hints != null && hints.containsKey(DecodeHintType.PURE_BARCODE);
|
||||||
int maxI = image.getHeight();
|
int maxI = image.getHeight();
|
||||||
int maxJ = image.getWidth();
|
int maxJ = image.getWidth();
|
||||||
// We are looking for black/white/black/white/black modules in
|
// We are looking for black/white/black/white/black modules in
|
||||||
|
@ -111,7 +112,7 @@ public class FinderPatternFinder {
|
||||||
if ((currentState & 1) == 0) { // Counting black pixels
|
if ((currentState & 1) == 0) { // Counting black pixels
|
||||||
if (currentState == 4) { // A winner?
|
if (currentState == 4) { // A winner?
|
||||||
if (foundPatternCross(stateCount)) { // Yes
|
if (foundPatternCross(stateCount)) { // Yes
|
||||||
boolean confirmed = handlePossibleCenter(stateCount, i, j);
|
boolean confirmed = handlePossibleCenter(stateCount, i, j, pureBarcode);
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
// Start examining every other line. Checking each line turned out to be too
|
// Start examining every other line. Checking each line turned out to be too
|
||||||
// expensive and didn't improve performance.
|
// expensive and didn't improve performance.
|
||||||
|
@ -166,7 +167,7 @@ public class FinderPatternFinder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (foundPatternCross(stateCount)) {
|
if (foundPatternCross(stateCount)) {
|
||||||
boolean confirmed = handlePossibleCenter(stateCount, i, maxJ);
|
boolean confirmed = handlePossibleCenter(stateCount, i, maxJ, pureBarcode);
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
iSkip = stateCount[0];
|
iSkip = stateCount[0];
|
||||||
if (hasSkipped) {
|
if (hasSkipped) {
|
||||||
|
@ -227,6 +228,92 @@ public class FinderPatternFinder {
|
||||||
return crossCheckStateCount;
|
return crossCheckStateCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* After a vertical and horizontal scan finds a potential finder pattern, this method
|
||||||
|
* "cross-cross-cross-checks" by scanning down diagonally through the center of the possible
|
||||||
|
* finder pattern to see if the same proportion is detected.
|
||||||
|
*
|
||||||
|
* @param startI row where a finder pattern was detected
|
||||||
|
* @param centerJ center of the section that appears to cross a finder pattern
|
||||||
|
* @param maxCount maximum reasonable number of modules that should be
|
||||||
|
* observed in any reading state, based on the results of the horizontal scan
|
||||||
|
* @param originalStateCountTotal The original state count total.
|
||||||
|
* @return true if proportions are withing expected limits
|
||||||
|
*/
|
||||||
|
private boolean crossCheckDiagonal(int startI, int centerJ, int maxCount, int originalStateCountTotal) {
|
||||||
|
int maxI = image.getHeight();
|
||||||
|
int maxJ = image.getWidth();
|
||||||
|
int[] stateCount = getCrossCheckStateCount();
|
||||||
|
|
||||||
|
// Start counting up, left from center finding black center mass
|
||||||
|
int i = 0;
|
||||||
|
while (startI - i >= 0 && image.get(centerJ - i, startI - i)) {
|
||||||
|
stateCount[2]++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((startI - i < 0) || (centerJ - i < 0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue up, left finding white space
|
||||||
|
while ((startI - i >= 0) && (centerJ - i >= 0) && !image.get(centerJ - i, startI - i) && stateCount[1] <= maxCount) {
|
||||||
|
stateCount[1]++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If already too many modules in this state or ran off the edge:
|
||||||
|
if ((startI - i < 0) || (centerJ - i < 0) || stateCount[1] > maxCount) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue up, left finding black border
|
||||||
|
while ((startI - i >= 0) && (centerJ - i >= 0) && image.get(centerJ - i, startI - i) && stateCount[0] <= maxCount) {
|
||||||
|
stateCount[0]++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (stateCount[0] > maxCount) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now also count down, right from center
|
||||||
|
i = 1;
|
||||||
|
while ((startI + i < maxI) && (centerJ + i < maxJ) && image.get(centerJ + i, startI + i)) {
|
||||||
|
stateCount[2]++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ran off the edge?
|
||||||
|
if ((startI + i >= maxI) || (centerJ + i >= maxJ)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((startI + i < maxI) && (centerJ + i < maxJ) && !image.get(centerJ + i, startI + i) && stateCount[3] < maxCount) {
|
||||||
|
stateCount[3]++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((startI + i >= maxI) || (centerJ + i >= maxJ) || stateCount[3] >= maxCount) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((startI + i < maxI) && (centerJ + i < maxJ) && image.get(centerJ + i, startI + i) && stateCount[4] < maxCount) {
|
||||||
|
stateCount[4]++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stateCount[4] >= maxCount) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we found a finder-pattern-like section, but its size is more than 100% different than
|
||||||
|
// the original, assume it's a false positive
|
||||||
|
int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4];
|
||||||
|
return
|
||||||
|
Math.abs(stateCountTotal - originalStateCountTotal) < 2 * originalStateCountTotal &&
|
||||||
|
foundPatternCross(stateCount);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>After a horizontal scan finds a potential finder pattern, this method
|
* <p>After a horizontal scan finds a potential finder pattern, this method
|
||||||
* "cross-checks" by scanning down vertically through the center of the possible
|
* "cross-checks" by scanning down vertically through the center of the possible
|
||||||
|
@ -378,7 +465,8 @@ public class FinderPatternFinder {
|
||||||
* <p>This is called when a horizontal scan finds a possible alignment pattern. It will
|
* <p>This is called when a horizontal scan finds a possible alignment pattern. It will
|
||||||
* cross check with a vertical scan, and if successful, will, ah, cross-cross-check
|
* cross check with a vertical scan, and if successful, will, ah, cross-cross-check
|
||||||
* with another horizontal scan. This is needed primarily to locate the real horizontal
|
* with another horizontal scan. This is needed primarily to locate the real horizontal
|
||||||
* center of the pattern in cases of extreme skew.</p>
|
* center of the pattern in cases of extreme skew.
|
||||||
|
* And then we cross-cross-cross check with another diagonal scan.</p>
|
||||||
*
|
*
|
||||||
* <p>If that succeeds the finder pattern location is added to a list that tracks
|
* <p>If that succeeds the finder pattern location is added to a list that tracks
|
||||||
* the number of times each location has been nearly-matched as a finder pattern.
|
* the number of times each location has been nearly-matched as a finder pattern.
|
||||||
|
@ -390,7 +478,7 @@ public class FinderPatternFinder {
|
||||||
* @param j end of possible finder pattern in row
|
* @param j end of possible finder pattern in row
|
||||||
* @return true if a finder pattern candidate was found this time
|
* @return true if a finder pattern candidate was found this time
|
||||||
*/
|
*/
|
||||||
protected final boolean handlePossibleCenter(int[] stateCount, int i, int j) {
|
protected final boolean handlePossibleCenter(int[] stateCount, int i, int j, boolean pureBarcode) {
|
||||||
int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] +
|
int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] +
|
||||||
stateCount[4];
|
stateCount[4];
|
||||||
float centerJ = centerFromEnd(stateCount, j);
|
float centerJ = centerFromEnd(stateCount, j);
|
||||||
|
@ -398,7 +486,8 @@ public class FinderPatternFinder {
|
||||||
if (!Float.isNaN(centerI)) {
|
if (!Float.isNaN(centerI)) {
|
||||||
// Re-cross check
|
// Re-cross check
|
||||||
centerJ = crossCheckHorizontal((int) centerJ, (int) centerI, stateCount[2], stateCountTotal);
|
centerJ = crossCheckHorizontal((int) centerJ, (int) centerI, stateCount[2], stateCountTotal);
|
||||||
if (!Float.isNaN(centerJ)) {
|
if (!Float.isNaN(centerJ) &&
|
||||||
|
(!pureBarcode || crossCheckDiagonal((int) centerI, (int) centerJ, stateCount[2], stateCountTotal))) {
|
||||||
float estimatedModuleSize = (float) stateCountTotal / 7.0f;
|
float estimatedModuleSize = (float) stateCountTotal / 7.0f;
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
for (int index = 0; index < possibleCenters.size(); index++) {
|
for (int index = 0; index < possibleCenters.size(); index++) {
|
||||||
|
|
Loading…
Reference in a new issue