mirror of
https://github.com/zxing/zxing.git
synced 2024-11-10 04:54:04 -08:00
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:
parent
b980bd71b6
commit
1b0aed9c09
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue