mirror of
https://github.com/zxing/zxing.git
synced 2025-03-05 20:48:51 -08:00
Add QRCode lenient diagonal check (#906)
* Add QRCode lenient diagonal check Adding diagonal check to solve #897 to prevent false positives for centers * update tests to expect the increased number of successes
This commit is contained in:
parent
ce98de83bd
commit
72a21d158b
|
@ -218,6 +218,34 @@ public class FinderPatternFinder {
|
|||
Math.abs(moduleSize - stateCount[4]) < maxVariance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param stateCount count of black/white/black/white/black pixels just read
|
||||
* @return true iff the proportions of the counts is close enough to the 1/1/3/1/1 ratios
|
||||
* used by finder patterns to be considered a match
|
||||
*/
|
||||
protected static boolean foundPatternDiagonal(int[] stateCount) {
|
||||
int totalModuleSize = 0;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
int count = stateCount[i];
|
||||
if (count == 0) {
|
||||
return false;
|
||||
}
|
||||
totalModuleSize += count;
|
||||
}
|
||||
if (totalModuleSize < 7) {
|
||||
return false;
|
||||
}
|
||||
float moduleSize = totalModuleSize / 7.0f;
|
||||
float maxVariance = moduleSize / 1.333f;
|
||||
// Allow less than 75% variance from 1-1-3-1-1 proportions
|
||||
return
|
||||
Math.abs(moduleSize - stateCount[0]) < maxVariance &&
|
||||
Math.abs(moduleSize - stateCount[1]) < maxVariance &&
|
||||
Math.abs(3.0f * moduleSize - stateCount[2]) < 3 * maxVariance &&
|
||||
Math.abs(moduleSize - stateCount[3]) < maxVariance &&
|
||||
Math.abs(moduleSize - stateCount[4]) < maxVariance;
|
||||
}
|
||||
|
||||
private int[] getCrossCheckStateCount() {
|
||||
crossCheckStateCount[0] = 0;
|
||||
crossCheckStateCount[1] = 0;
|
||||
|
@ -227,6 +255,78 @@ 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 centerI 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 centerI, int centerJ) {
|
||||
int[] stateCount = getCrossCheckStateCount();
|
||||
|
||||
// Start counting up, left from center finding black center mass
|
||||
int i = 0;
|
||||
while (centerI >= i && centerJ >= i && image.get(centerJ - i, centerI - i)) {
|
||||
stateCount[2]++;
|
||||
i++;
|
||||
}
|
||||
if (stateCount[2] == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Continue up, left finding white space
|
||||
while (centerI >= i && centerJ >= i && !image.get(centerJ - i, centerI - i)) {
|
||||
stateCount[1]++;
|
||||
i++;
|
||||
}
|
||||
if (stateCount[1] == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Continue up, left finding black border
|
||||
while (centerI >= i && centerJ >= i && image.get(centerJ - i, centerI - i)) {
|
||||
stateCount[0]++;
|
||||
i++;
|
||||
}
|
||||
if (stateCount[0] == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int maxI = image.getHeight();
|
||||
int maxJ = image.getWidth();
|
||||
|
||||
// Now also count down, right from center
|
||||
i = 1;
|
||||
while (centerI + i < maxI && centerJ + i < maxJ && image.get(centerJ + i, centerI + i)) {
|
||||
stateCount[2]++;
|
||||
i++;
|
||||
}
|
||||
|
||||
while (centerI + i < maxI && centerJ + i < maxJ && !image.get(centerJ + i, centerI + i)) {
|
||||
stateCount[3]++;
|
||||
i++;
|
||||
}
|
||||
if (stateCount[3] == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (centerI + i < maxI && centerJ + i < maxJ && image.get(centerJ + i, centerI + i)) {
|
||||
stateCount[4]++;
|
||||
i++;
|
||||
}
|
||||
if (stateCount[4] == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return foundPatternDiagonal(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
|
||||
|
@ -408,7 +508,7 @@ 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) && crossCheckDiagonal((int) centerI, (int) centerJ)) {
|
||||
float estimatedModuleSize = stateCountTotal / 7.0f;
|
||||
boolean found = false;
|
||||
for (int index = 0; index < possibleCenters.size(); index++) {
|
||||
|
|
|
@ -30,7 +30,7 @@ public final class QRCodeBlackBox2TestCase extends AbstractBlackBoxTestCase {
|
|||
addTest(31, 31, 0.0f);
|
||||
addTest(29, 29, 90.0f);
|
||||
addTest(30, 30, 180.0f);
|
||||
addTest(29, 29, 270.0f);
|
||||
addTest(30, 30, 270.0f);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ public final class QRCodeBlackBox3TestCase extends AbstractBlackBoxTestCase {
|
|||
public QRCodeBlackBox3TestCase() {
|
||||
super("src/test/resources/blackbox/qrcode-3", new MultiFormatReader(), BarcodeFormat.QR_CODE);
|
||||
addTest(38, 38, 0.0f);
|
||||
addTest(38, 38, 90.0f);
|
||||
addTest(39, 39, 90.0f);
|
||||
addTest(36, 36, 180.0f);
|
||||
addTest(39, 39, 270.0f);
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ public final class QRCodeBlackBox5TestCase extends AbstractBlackBoxTestCase {
|
|||
addTest(19, 19, 0.0f);
|
||||
addTest(19, 19, 90.0f);
|
||||
addTest(19, 19, 180.0f);
|
||||
addTest(18, 18, 270.0f);
|
||||
addTest(19, 19, 270.0f);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue