diff --git a/core/src/com/google/zxing/qrcode/detector/AlignmentPatternFinder.java b/core/src/com/google/zxing/qrcode/detector/AlignmentPatternFinder.java index 2f48fa819..88c2caf48 100644 --- a/core/src/com/google/zxing/qrcode/detector/AlignmentPatternFinder.java +++ b/core/src/com/google/zxing/qrcode/detector/AlignmentPatternFinder.java @@ -164,7 +164,7 @@ final class AlignmentPatternFinder { */ private boolean foundPatternCross(int[] stateCount) { float moduleSize = this.moduleSize; - float maxVariance = moduleSize / 2.5f; + float maxVariance = moduleSize / 2.0f; for (int i = 0; i < 3; i++) { if (Math.abs(moduleSize - stateCount[i]) >= maxVariance) { return false; @@ -184,7 +184,7 @@ final class AlignmentPatternFinder { * observed in any reading state, based on the results of the horizontal scan * @return vertical center of alignment pattern, or {@link Float#NaN} if not found */ - private float crossCheckVertical(int startI, int centerJ, int maxCount) { + private float crossCheckVertical(int startI, int centerJ, int maxCount, int originalStateCountTotal) { MonochromeBitmapSource image = this.image; int maxI = image.getHeight(); @@ -225,6 +225,11 @@ final class AlignmentPatternFinder { return Float.NaN; } + int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; + if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= originalStateCountTotal) { + return Float.NaN; + } + return foundPatternCross(stateCount) ? centerFromEnd(stateCount, i) : Float.NaN; } @@ -240,8 +245,9 @@ final class AlignmentPatternFinder { * @return {@link AlignmentPattern} if we have found the same pattern twice, or null if not */ private AlignmentPattern handlePossibleCenter(int[] stateCount, int i, int j) { + int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; float centerJ = centerFromEnd(stateCount, j); - float centerI = crossCheckVertical(i, (int) centerJ, 2 * stateCount[1]); + float centerI = crossCheckVertical(i, (int) centerJ, 2 * stateCount[1], stateCountTotal); if (!Float.isNaN(centerI)) { float estimatedModuleSize = (float) (stateCount[0] + stateCount[1] + stateCount[2]) / 3.0f; int max = possibleCenters.size(); diff --git a/core/src/com/google/zxing/qrcode/detector/Detector.java b/core/src/com/google/zxing/qrcode/detector/Detector.java index 87a08fbaf..940476b4a 100644 --- a/core/src/com/google/zxing/qrcode/detector/Detector.java +++ b/core/src/com/google/zxing/qrcode/detector/Detector.java @@ -62,14 +62,14 @@ public final class Detector { Version provisionalVersion = Version.getProvisionalVersionForDimension(dimension); int modulesBetweenFPCenters = provisionalVersion.getDimensionForVersion() - 7; - // Guess where a "bottom right" finder pattern would have been - float bottomRightX = topRight.getX() - topLeft.getX() + bottomLeft.getX(); - float bottomRightY = topRight.getY() - topLeft.getY() + bottomLeft.getY(); - AlignmentPattern alignmentPattern = null; // Anything above version 1 has an alignment pattern if (provisionalVersion.getAlignmentPatternCenters().length > 0) { + // Guess where a "bottom right" finder pattern would have been + float bottomRightX = topRight.getX() - topLeft.getX() + bottomLeft.getX(); + float bottomRightY = topRight.getY() - topLeft.getY() + bottomLeft.getY(); + // Estimate that alignment pattern is closer by 3 modules // from "bottom right" to known top left location float correctionToTopLeft = 1.0f - 3.0f / (float) modulesBetweenFPCenters; diff --git a/core/src/com/google/zxing/qrcode/detector/FinderPatternFinder.java b/core/src/com/google/zxing/qrcode/detector/FinderPatternFinder.java index c97e8f82f..8b4d99684 100755 --- a/core/src/com/google/zxing/qrcode/detector/FinderPatternFinder.java +++ b/core/src/com/google/zxing/qrcode/detector/FinderPatternFinder.java @@ -179,8 +179,8 @@ final class FinderPatternFinder { return false; } float moduleSize = (float) totalModuleSize / 7.0f; - float maxVariance = moduleSize / 2.5f; - // Allow less than 40% variance from 1-1-3-1-1 proportions + float maxVariance = moduleSize / 2.0f; + // Allow less than 50% 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.0f * maxVariance && @@ -199,7 +199,7 @@ final class FinderPatternFinder { * observed in any reading state, based on the results of the horizontal scan * @return vertical center of finder pattern, or {@link Float#NaN} if not found */ - private float crossCheckVertical(int startI, int centerJ, int maxCount) { + private float crossCheckVertical(int startI, int centerJ, int maxCount, int originalStateCountTotal) { MonochromeBitmapSource image = this.image; int maxI = image.getHeight(); @@ -254,15 +254,22 @@ final class FinderPatternFinder { return Float.NaN; } + // If we found a finder-pattern-like section, but its size is more than 20% different than + // the original, assume it's a false positive + int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; + if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= originalStateCountTotal) { + return Float.NaN; + } + return foundPatternCross(stateCount) ? centerFromEnd(stateCount, i) : Float.NaN; } /** - *

Like {@link #crossCheckVertical(int, int, int)}, and in fact is basically identical, + *

Like {@link #crossCheckVertical(int, int, int, int)}, and in fact is basically identical, * except it reads horizontally instead of vertically. This is used to cross-cross * check a vertical cross check and locate the real center of the alignment pattern.

*/ - private float crossCheckHorizontal(int startJ, int centerI, int maxCount) { + private float crossCheckHorizontal(int startJ, int centerI, int maxCount, int originalStateCountTotal) { MonochromeBitmapSource image = this.image; int maxJ = image.getWidth(); @@ -314,6 +321,13 @@ final class FinderPatternFinder { return Float.NaN; } + // If we found a finder-pattern-like section, but its size is significantly different than + // the original, assume it's a false positive + int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; + if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= originalStateCountTotal) { + return Float.NaN; + } + return foundPatternCross(stateCount) ? centerFromEnd(stateCount, j) : Float.NaN; } @@ -336,14 +350,14 @@ final class FinderPatternFinder { private boolean handlePossibleCenter(int[] stateCount, int i, int j) { + int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; float centerJ = centerFromEnd(stateCount, j); - float centerI = crossCheckVertical(i, (int) centerJ, stateCount[2]); + float centerI = crossCheckVertical(i, (int) centerJ, stateCount[2], stateCountTotal); if (!Float.isNaN(centerI)) { // Re-cross check - centerJ = crossCheckHorizontal((int) centerJ, (int) centerI, stateCount[2]); + centerJ = crossCheckHorizontal((int) centerJ, (int) centerI, stateCount[2], stateCountTotal); if (!Float.isNaN(centerJ)) { - float estimatedModuleSize = - (float) (stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]) / 7.0f; + float estimatedModuleSize = (float) stateCountTotal / 7.0f; boolean found = false; int max = possibleCenters.size(); for (int index = 0; index < max; index++) {