Improvement to finder/alignment pattern detection in low-res situations: use averages. It makes it much better on images of this sort, decreasing failure rate by about 60%. (It makes one old image fail, but looks like a fluke)

git-svn-id: https://zxing.googlecode.com/svn/trunk@1875 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
srowen 2011-08-02 16:20:59 +00:00
parent b151a85c7e
commit 869ddc1dbf
35 changed files with 87 additions and 7 deletions

View file

@ -68,6 +68,7 @@ Steven Parkes
Suraj Supekar Suraj Supekar
Sven Klinkhamer Sven Klinkhamer
Thomas Gerbet Thomas Gerbet
Tim Gernat
v.anestis v.anestis
Vince Francis (LifeMarks) Vince Francis (LifeMarks)
Wolfgang Jung Wolfgang Jung

View file

@ -40,9 +40,20 @@ public final class AlignmentPattern extends ResultPoint {
boolean aboutEquals(float moduleSize, float i, float j) { boolean aboutEquals(float moduleSize, float i, float j) {
if (Math.abs(i - getY()) <= moduleSize && Math.abs(j - getX()) <= moduleSize) { if (Math.abs(i - getY()) <= moduleSize && Math.abs(j - getX()) <= moduleSize) {
float moduleSizeDiff = Math.abs(moduleSize - estimatedModuleSize); float moduleSizeDiff = Math.abs(moduleSize - estimatedModuleSize);
return moduleSizeDiff <= 1.0f || moduleSizeDiff / estimatedModuleSize <= 1.0f; return moduleSizeDiff <= 1.0f || moduleSizeDiff <= estimatedModuleSize;
} }
return false; return false;
} }
/**
* Combines this object's current estimate of a finder pattern position and module size
* with a new estimate. It returns a new {@code FinderPattern} containing an average of the two.
*/
AlignmentPattern combineEstimate(float i, float j, float newModuleSize) {
float combinedX = (getX() + j) / 2.0f;
float combinedY = (getY() + i) / 2.0f;
float combinedModuleSize = (estimatedModuleSize + newModuleSize) / 2.0f;
return new AlignmentPattern(combinedX, combinedY, combinedModuleSize);
}
} }

View file

@ -263,7 +263,7 @@ final class AlignmentPatternFinder {
AlignmentPattern center = (AlignmentPattern) possibleCenters.elementAt(index); AlignmentPattern center = (AlignmentPattern) possibleCenters.elementAt(index);
// Look for about the same center and module size: // Look for about the same center and module size:
if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) { if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) {
return new AlignmentPattern(centerJ, centerI, estimatedModuleSize); return center.combineEstimate(centerI, centerJ, estimatedModuleSize);
} }
} }
// Hadn't found this before; save it // Hadn't found this before; save it

View file

@ -31,9 +31,13 @@ public final class FinderPattern extends ResultPoint {
private int count; private int count;
FinderPattern(float posX, float posY, float estimatedModuleSize) { FinderPattern(float posX, float posY, float estimatedModuleSize) {
this(posX, posY, estimatedModuleSize, 1);
}
FinderPattern(float posX, float posY, float estimatedModuleSize, int count) {
super(posX, posY); super(posX, posY);
this.estimatedModuleSize = estimatedModuleSize; this.estimatedModuleSize = estimatedModuleSize;
this.count = 1; this.count = count;
} }
public float getEstimatedModuleSize() { public float getEstimatedModuleSize() {
@ -55,9 +59,22 @@ public final class FinderPattern extends ResultPoint {
boolean aboutEquals(float moduleSize, float i, float j) { boolean aboutEquals(float moduleSize, float i, float j) {
if (Math.abs(i - getY()) <= moduleSize && Math.abs(j - getX()) <= moduleSize) { if (Math.abs(i - getY()) <= moduleSize && Math.abs(j - getX()) <= moduleSize) {
float moduleSizeDiff = Math.abs(moduleSize - estimatedModuleSize); float moduleSizeDiff = Math.abs(moduleSize - estimatedModuleSize);
return moduleSizeDiff <= 1.0f || moduleSizeDiff / estimatedModuleSize <= 1.0f; return moduleSizeDiff <= 1.0f || moduleSizeDiff <= estimatedModuleSize;
} }
return false; return false;
} }
/**
* Combines this object's current estimate of a finder pattern position and module size
* with a new estimate. It returns a new {@code FinderPattern} containing a weighted average
* based on count.
*/
FinderPattern combineEstimate(float i, float j, float newModuleSize) {
int combinedCount = count + 1;
float combinedX = (count * getX() + j) / combinedCount;
float combinedY = (count * getY() + i) / combinedCount;
float combinedModuleSize = (count * getEstimatedModuleSize() + newModuleSize) / combinedCount;
return new FinderPattern(combinedX, combinedY, combinedModuleSize, combinedCount);
}
} }

View file

@ -404,7 +404,7 @@ public class FinderPatternFinder {
FinderPattern center = (FinderPattern) possibleCenters.elementAt(index); FinderPattern center = (FinderPattern) possibleCenters.elementAt(index);
// Look for about the same center and module size: // Look for about the same center and module size:
if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) { if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) {
center.incrementCount(); possibleCenters.setElementAt(center.combineEstimate(centerI, centerJ, estimatedModuleSize), index);
found = true; found = true;
break; break;
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -0,0 +1 @@
1234567890

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -0,0 +1 @@
1234567890

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -0,0 +1 @@
1234567890

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View file

@ -0,0 +1 @@
1234567890

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View file

@ -0,0 +1 @@
1234567890

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -0,0 +1 @@
1234567890

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View file

@ -0,0 +1 @@
1234567890

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -0,0 +1 @@
1234567890

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -0,0 +1 @@
1234567890

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -0,0 +1 @@
1234567890

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View file

@ -0,0 +1 @@
1234567890

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -0,0 +1 @@
1234567890

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -0,0 +1 @@
1234567890

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -0,0 +1 @@
1234567890

View file

@ -30,9 +30,9 @@ public final class QRCodeBlackBox4TestCase extends AbstractBlackBoxTestCase {
public QRCodeBlackBox4TestCase() { public QRCodeBlackBox4TestCase() {
super("test/data/blackbox/qrcode-4", new MultiFormatReader(), BarcodeFormat.QR_CODE); super("test/data/blackbox/qrcode-4", new MultiFormatReader(), BarcodeFormat.QR_CODE);
addTest(36, 36, 0.0f); addTest(36, 36, 0.0f);
addTest(36, 36, 90.0f); addTest(35, 35, 90.0f);
addTest(35, 35, 180.0f); addTest(35, 35, 180.0f);
addTest(35, 35, 270.0f); addTest(34, 34, 270.0f);
} }
} }

View file

@ -0,0 +1,37 @@
/*
* Copyright 2009 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.qrcode;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.common.AbstractBlackBoxTestCase;
/**
* These tests are supplied by Tim Gernat and test finder pattern detection at small size and under
* rotation, which was a weak spot.
*/
public final class QRCodeBlackBox6TestCase extends AbstractBlackBoxTestCase {
public QRCodeBlackBox6TestCase() {
super("test/data/blackbox/qrcode-6", new MultiFormatReader(), BarcodeFormat.QR_CODE);
addTest(14, 14, 0.0f);
addTest(13, 13, 90.0f);
addTest(11, 12, 180.0f);
addTest(13, 13, 270.0f);
}
}