Improve detection especially under rotation

git-svn-id: https://zxing.googlecode.com/svn/trunk@2233 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
srowen 2012-03-23 18:18:38 +00:00
parent b980bd71b6
commit 1b0aed9c09
2 changed files with 71 additions and 48 deletions

View file

@ -36,9 +36,11 @@ import java.util.Map;
*/
public final class Detector {
private static final int MAX_AVG_VARIANCE = (int) ((1 << 8) * 0.42f);
private static final int MAX_INDIVIDUAL_VARIANCE = (int) ((1 << 8) * 0.8f);
private static final int SKEW_THRESHOLD = 2;
private static final int INTEGER_MATH_SHIFT = 8;
private static final int PATTERN_MATCH_RESULT_SCALE_FACTOR = 1 << INTEGER_MATH_SHIFT;
private static final int MAX_AVG_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.42f);
private static final int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.8f);
private static final int SKEW_THRESHOLD = 3;
// B S B S B S B S Bar/Space pattern
// 11111111 0 1 0 1 0 1 000
@ -81,11 +83,13 @@ public final class Detector {
// Fetch the 1 bit matrix once up front.
BitMatrix matrix = image.getBlackMatrix();
boolean tryHarder = hints != null && hints.containsKey(DecodeHintType.TRY_HARDER);
// Try to find the vertices assuming the image is upright.
ResultPoint[] vertices = findVertices(matrix);
ResultPoint[] vertices = findVertices(matrix, tryHarder);
if (vertices == null) {
// Maybe the image is rotated 180 degrees?
vertices = findVertices180(matrix);
vertices = findVertices180(matrix, tryHarder);
if (vertices != null) {
correctCodeWordVertices(vertices, true);
}
@ -109,16 +113,13 @@ public final class Detector {
}
// Deskew and sample image.
BitMatrix bits = sampleGrid(matrix, vertices[4], vertices[5],
vertices[6], vertices[7], dimension);
return new DetectorResult(bits, new ResultPoint[]{vertices[5],
vertices[4], vertices[6], vertices[7]});
BitMatrix bits = sampleGrid(matrix, vertices[4], vertices[5], vertices[6], vertices[7], dimension);
return new DetectorResult(bits, new ResultPoint[]{vertices[5], vertices[4], vertices[6], vertices[7]});
}
/**
* Locate the vertices and the codewords area of a black blob using the Start
* and Stop patterns as locators.
* TODO: Scanning every row is very expensive. We should only do this for TRY_HARDER.
*
* @param matrix the scanned barcode image.
* @return an array containing the vertices:
@ -131,7 +132,7 @@ public final class Detector {
* vertices[6] x, y top right codeword area
* vertices[7] x, y bottom right codeword area
*/
private static ResultPoint[] findVertices(BitMatrix matrix) {
private static ResultPoint[] findVertices(BitMatrix matrix, boolean tryHarder) {
int height = matrix.getHeight();
int width = matrix.getWidth();
@ -140,8 +141,10 @@ public final class Detector {
int[] counters = new int[START_PATTERN.length];
int rowStep = Math.max(1, height >> (tryHarder ? 9 : 7));
// Top Left
for (int i = 0; i < height; i++) {
for (int i = 0; i < height; i += rowStep) {
int[] loc = findGuardPattern(matrix, 0, i, width, false, START_PATTERN, counters);
if (loc != null) {
result[0] = new ResultPoint(loc[0], i);
@ -153,7 +156,7 @@ public final class Detector {
// Bottom left
if (found) { // Found the Top Left vertex
found = false;
for (int i = height - 1; i > 0; i--) {
for (int i = height - 1; i > 0; i -= rowStep) {
int[] loc = findGuardPattern(matrix, 0, i, width, false, START_PATTERN, counters);
if (loc != null) {
result[1] = new ResultPoint(loc[0], i);
@ -169,7 +172,7 @@ public final class Detector {
// Top right
if (found) { // Found the Bottom Left vertex
found = false;
for (int i = 0; i < height; i++) {
for (int i = 0; i < height; i += rowStep) {
int[] loc = findGuardPattern(matrix, 0, i, width, false, STOP_PATTERN, counters);
if (loc != null) {
result[2] = new ResultPoint(loc[1], i);
@ -182,7 +185,7 @@ public final class Detector {
// Bottom right
if (found) { // Found the Top right vertex
found = false;
for (int i = height - 1; i > 0; i--) {
for (int i = height - 1; i > 0; i -= rowStep) {
int[] loc = findGuardPattern(matrix, 0, i, width, false, STOP_PATTERN, counters);
if (loc != null) {
result[3] = new ResultPoint(loc[1], i);
@ -201,7 +204,6 @@ public final class Detector {
* degrees and if it locates the start and stop patterns at it will re-map
* the vertices for a 0 degree rotation.
* TODO: Change assumption about barcode location.
* TODO: Scanning every row is very expensive. We should only do this for TRY_HARDER.
*
* @param matrix the scanned barcode image.
* @return an array containing the vertices:
@ -214,7 +216,7 @@ public final class Detector {
* vertices[6] x, y top right codeword area
* vertices[7] x, y bottom right codeword area
*/
private static ResultPoint[] findVertices180(BitMatrix matrix) {
private static ResultPoint[] findVertices180(BitMatrix matrix, boolean tryHarder) {
int height = matrix.getHeight();
int width = matrix.getWidth();
int halfWidth = width >> 1;
@ -223,9 +225,11 @@ public final class Detector {
boolean found = false;
int[] counters = new int[START_PATTERN_REVERSE.length];
int rowStep = Math.max(1, height >> (tryHarder ? 9 : 7));
// Top Left
for (int i = height - 1; i > 0; i--) {
for (int i = height - 1; i > 0; i -= rowStep) {
int[] loc = findGuardPattern(matrix, halfWidth, i, halfWidth, true, START_PATTERN_REVERSE, counters);
if (loc != null) {
result[0] = new ResultPoint(loc[1], i);
@ -237,7 +241,7 @@ public final class Detector {
// Bottom Left
if (found) { // Found the Top Left vertex
found = false;
for (int i = 0; i < height; i++) {
for (int i = 0; i < height; i += rowStep) {
int[] loc = findGuardPattern(matrix, halfWidth, i, halfWidth, true, START_PATTERN_REVERSE, counters);
if (loc != null) {
result[1] = new ResultPoint(loc[1], i);
@ -253,7 +257,7 @@ public final class Detector {
// Top Right
if (found) { // Found the Bottom Left vertex
found = false;
for (int i = height - 1; i > 0; i--) {
for (int i = height - 1; i > 0; i -= rowStep) {
int[] loc = findGuardPattern(matrix, 0, i, halfWidth, false, STOP_PATTERN_REVERSE, counters);
if (loc != null) {
result[2] = new ResultPoint(loc[0], i);
@ -266,7 +270,7 @@ public final class Detector {
// Bottom Right
if (found) { // Found the Top Right vertex
found = false;
for (int i = 0; i < height; i++) {
for (int i = 0; i < height; i += rowStep) {
int[] loc = findGuardPattern(matrix, 0, i, halfWidth, false, STOP_PATTERN_REVERSE, counters);
if (loc != null) {
result[3] = new ResultPoint(loc[0], i);
@ -288,44 +292,63 @@ public final class Detector {
* @param vertices The eight vertices located by findVertices().
*/
private static void correctCodeWordVertices(ResultPoint[] vertices, boolean upsideDown) {
float skew = vertices[4].getY() - vertices[6].getY();
float v0x = vertices[0].getX();
float v0y = vertices[0].getY();
float v2x = vertices[2].getX();
float v2y = vertices[2].getY();
float v4x = vertices[4].getX();
float v4y = vertices[4].getY();
float v6x = vertices[6].getX();
float v6y = vertices[6].getY();
float skew = v4y - v6y;
if (upsideDown) {
skew = -skew;
}
if (skew > SKEW_THRESHOLD) {
// Fix v4
float length = vertices[4].getX() - vertices[0].getX();
float deltax = vertices[6].getX() - vertices[0].getX();
float deltay = vertices[6].getY() - vertices[0].getY();
float correction = length * deltay / deltax;
vertices[4] = new ResultPoint(vertices[4].getX(), vertices[4].getY() + correction);
float deltax = v6x - v0x;
float deltay = v6y - v0y;
float delta2 = deltax * deltax + deltay * deltay;
float correction = (v4x - v0x) * deltax / delta2;
vertices[4] = new ResultPoint(v0x + correction * deltax, v0y + correction * deltay);
} else if (-skew > SKEW_THRESHOLD) {
// Fix v6
float length = vertices[2].getX() - vertices[6].getX();
float deltax = vertices[2].getX() - vertices[4].getX();
float deltay = vertices[2].getY() - vertices[4].getY();
float correction = length * deltay / deltax;
vertices[6] = new ResultPoint(vertices[6].getX(), vertices[6].getY() - correction);
float deltax = v2x - v4x;
float deltay = v2y - v4y;
float delta2 = deltax * deltax + deltay * deltay;
float correction = (v2x - v6x) * deltax / delta2;
vertices[6] = new ResultPoint(v2x - correction * deltax, v2y - correction * deltay);
}
skew = vertices[7].getY() - vertices[5].getY();
float v1x = vertices[1].getX();
float v1y = vertices[1].getY();
float v3x = vertices[3].getX();
float v3y = vertices[3].getY();
float v5x = vertices[5].getX();
float v5y = vertices[5].getY();
float v7x = vertices[7].getX();
float v7y = vertices[7].getY();
skew = v7y - v5y;
if (upsideDown) {
skew = -skew;
}
if (skew > SKEW_THRESHOLD) {
// Fix v5
float length = vertices[5].getX() - vertices[1].getX();
float deltax = vertices[7].getX() - vertices[1].getX();
float deltay = vertices[7].getY() - vertices[1].getY();
float correction = length * deltay / deltax;
vertices[5] = new ResultPoint(vertices[5].getX(), vertices[5].getY() + correction);
float deltax = v7x - v1x;
float deltay = v7y - v1y;
float delta2 = deltax * deltax + deltay * deltay;
float correction = (v5x - v1x) * deltax / delta2;
vertices[5] = new ResultPoint(v1x + correction * deltax, v1y + correction * deltay);
} else if (-skew > SKEW_THRESHOLD) {
// Fix v7
float length = vertices[3].getX() - vertices[7].getX();
float deltax = vertices[3].getX() - vertices[5].getX();
float deltay = vertices[3].getY() - vertices[5].getY();
float correction = length * deltay / deltax;
vertices[7] = new ResultPoint(vertices[7].getX(), vertices[7].getY() - correction);
float deltax = v3x - v5x;
float deltay = v3y - v5y;
float delta2 = deltax * deltax + deltay * deltay;
float correction = (v3x - v7x) * deltax / delta2;
vertices[7] = new ResultPoint(v3x - correction * deltax, v3y - correction * deltay);
}
}
@ -493,12 +516,12 @@ public final class Detector {
// We're going to fake floating-point math in integers. We just need to use more bits.
// Scale up patternLength so that intermediate values below like scaledCounter will have
// more "significant digits".
int unitBarWidth = (total << 8) / patternLength;
int unitBarWidth = (total << INTEGER_MATH_SHIFT) / patternLength;
maxIndividualVariance = (maxIndividualVariance * unitBarWidth) >> 8;
int totalVariance = 0;
for (int x = 0; x < numCounters; x++) {
int counter = counters[x] << 8;
int counter = counters[x] << INTEGER_MATH_SHIFT;
int scaledPattern = pattern[x] * unitBarWidth;
int variance = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter;
if (variance > maxIndividualVariance) {

View file

@ -29,8 +29,8 @@ public final class PDF417BlackBox2TestCase extends AbstractBlackBoxTestCase {
public PDF417BlackBox2TestCase() {
super("test/data/blackbox/pdf417-2", new MultiFormatReader(), BarcodeFormat.PDF_417);
addTest(11, 11, 0, 0, 0.0f);
addTest(13, 13, 0, 0, 180.0f);
addTest(12, 12, 0, 0, 0.0f);
addTest(16, 16, 0, 0, 180.0f);
}
}