mirror of
https://github.com/zxing/zxing.git
synced 2025-03-05 20:48:51 -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)
|
||||
evansepdx
|
||||
Erik Barbara
|
||||
fics.danmark
|
||||
Francois B. (Google)
|
||||
Frank Yellin
|
||||
Fred Lin (Anobiit)
|
||||
|
|
|
@ -230,6 +230,7 @@ final class MultiFinderPatternFinder extends FinderPatternFinder {
|
|||
|
||||
public FinderPatternInfo[] findMulti(Map<DecodeHintType,?> hints) throws NotFoundException {
|
||||
boolean tryHarder = hints != null && hints.containsKey(DecodeHintType.TRY_HARDER);
|
||||
boolean pureBarcode = hints != null && hints.containsKey(DecodeHintType.PURE_BARCODE);
|
||||
BitMatrix image = getImage();
|
||||
int maxI = image.getHeight();
|
||||
int maxJ = image.getWidth();
|
||||
|
@ -264,7 +265,7 @@ final class MultiFinderPatternFinder extends FinderPatternFinder {
|
|||
} else { // White pixel
|
||||
if ((currentState & 1) == 0) { // Counting black pixels
|
||||
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
|
||||
currentState = 0;
|
||||
stateCount[0] = 0;
|
||||
|
@ -290,7 +291,7 @@ final class MultiFinderPatternFinder extends FinderPatternFinder {
|
|||
} // for j=...
|
||||
|
||||
if (foundPatternCross(stateCount)) {
|
||||
handlePossibleCenter(stateCount, i, maxJ);
|
||||
handlePossibleCenter(stateCount, i, maxJ, pureBarcode);
|
||||
} // end if foundPatternCross
|
||||
} // for i=iSkip-1 ...
|
||||
FinderPattern[][] patternInfo = selectMutipleBestPatterns();
|
||||
|
|
|
@ -76,6 +76,7 @@ public class FinderPatternFinder {
|
|||
|
||||
final FinderPatternInfo find(Map<DecodeHintType,?> hints) throws NotFoundException {
|
||||
boolean tryHarder = hints != null && hints.containsKey(DecodeHintType.TRY_HARDER);
|
||||
boolean pureBarcode = hints != null && hints.containsKey(DecodeHintType.PURE_BARCODE);
|
||||
int maxI = image.getHeight();
|
||||
int maxJ = image.getWidth();
|
||||
// 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 == 4) { // A winner?
|
||||
if (foundPatternCross(stateCount)) { // Yes
|
||||
boolean confirmed = handlePossibleCenter(stateCount, i, j);
|
||||
boolean confirmed = handlePossibleCenter(stateCount, i, j, pureBarcode);
|
||||
if (confirmed) {
|
||||
// Start examining every other line. Checking each line turned out to be too
|
||||
// expensive and didn't improve performance.
|
||||
|
@ -166,7 +167,7 @@ public class FinderPatternFinder {
|
|||
}
|
||||
}
|
||||
if (foundPatternCross(stateCount)) {
|
||||
boolean confirmed = handlePossibleCenter(stateCount, i, maxJ);
|
||||
boolean confirmed = handlePossibleCenter(stateCount, i, maxJ, pureBarcode);
|
||||
if (confirmed) {
|
||||
iSkip = stateCount[0];
|
||||
if (hasSkipped) {
|
||||
|
@ -227,6 +228,92 @@ public class FinderPatternFinder {
|
|||
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
|
||||
* "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
|
||||
* 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
|
||||
* 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
|
||||
* 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
|
||||
* @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] +
|
||||
stateCount[4];
|
||||
float centerJ = centerFromEnd(stateCount, j);
|
||||
|
@ -398,7 +486,8 @@ public class FinderPatternFinder {
|
|||
if (!Float.isNaN(centerI)) {
|
||||
// Re-cross check
|
||||
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;
|
||||
boolean found = false;
|
||||
for (int index = 0; index < possibleCenters.size(); index++) {
|
||||
|
|
Loading…
Reference in a new issue