mirror of
https://github.com/zxing/zxing.git
synced 2025-03-05 20:48:51 -08:00
David Olivier's Data Matrix improvements
git-svn-id: https://zxing.googlecode.com/svn/trunk@1573 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
14a03f40b1
commit
47d2f3c798
1
AUTHORS
1
AUTHORS
|
@ -15,6 +15,7 @@ Daniel Switkin (Google)
|
||||||
Dave MacLachlan (Google)
|
Dave MacLachlan (Google)
|
||||||
David Phillip Oster (Google)
|
David Phillip Oster (Google)
|
||||||
David Albert (Bug Labs)
|
David Albert (Bug Labs)
|
||||||
|
David Olivier
|
||||||
Diego Pierotto
|
Diego Pierotto
|
||||||
Eduardo Castillejo (University of Deusto)
|
Eduardo Castillejo (University of Deusto)
|
||||||
Eric Kobrin (Velocitude)
|
Eric Kobrin (Velocitude)
|
||||||
|
|
|
@ -0,0 +1,317 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2010 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.common.detector;
|
||||||
|
|
||||||
|
import com.google.zxing.NotFoundException;
|
||||||
|
import com.google.zxing.ResultPoint;
|
||||||
|
import com.google.zxing.common.BitMatrix;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Detects a candidate barcode-like rectangular region within an image. It
|
||||||
|
* starts around the center of the image, increases the size of the candidate
|
||||||
|
* region until it finds a white rectangular region. By keeping track of the
|
||||||
|
* last black points it encountered, it determines the corners of the barcode.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author David Olivier
|
||||||
|
*/
|
||||||
|
public final class WhiteRectangleDetector {
|
||||||
|
|
||||||
|
private static final int INIT_SIZE = 40;
|
||||||
|
private static final int MIN_SIZE = 20;
|
||||||
|
|
||||||
|
private final BitMatrix image;
|
||||||
|
private final int height;
|
||||||
|
private final int width;
|
||||||
|
|
||||||
|
public WhiteRectangleDetector(BitMatrix image) {
|
||||||
|
this.image = image;
|
||||||
|
height = image.getHeight();
|
||||||
|
width = image.getWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Detects a candidate barcode-like rectangular region within an image. It
|
||||||
|
* starts around the center of the image, increases the size of the candidate
|
||||||
|
* region until it finds a white rectangular region.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @return {@link ResultPoint}[] describing the corners of the rectangular
|
||||||
|
* region. The first and last points are opposed on the diagonal, as
|
||||||
|
* are the second and third. The first point will be the topmost
|
||||||
|
* point and the last, the bottommost. The second point will be
|
||||||
|
* leftmost and the third, the rightmost
|
||||||
|
* @throws NotFoundException if no Data Matrix Code can be found
|
||||||
|
*/
|
||||||
|
public ResultPoint[] detect() throws NotFoundException {
|
||||||
|
|
||||||
|
int left = (width - INIT_SIZE) / 2;
|
||||||
|
int right = (width + INIT_SIZE) / 2;
|
||||||
|
int up = (height - INIT_SIZE) / 2;
|
||||||
|
int down = (height + INIT_SIZE) / 2;
|
||||||
|
boolean sizeExceeded = false;
|
||||||
|
boolean aBlackPointFoundOnBorder = true;
|
||||||
|
boolean atLeastOneBlackPointFoundOnBorder = false;
|
||||||
|
|
||||||
|
while (aBlackPointFoundOnBorder) {
|
||||||
|
|
||||||
|
aBlackPointFoundOnBorder = false;
|
||||||
|
|
||||||
|
// .....
|
||||||
|
// . |
|
||||||
|
// .....
|
||||||
|
boolean rightBorderNotWhite = true;
|
||||||
|
while (rightBorderNotWhite && right < width) {
|
||||||
|
rightBorderNotWhite = containsBlackPoint(up, down, right, false);
|
||||||
|
if (rightBorderNotWhite) {
|
||||||
|
right++;
|
||||||
|
aBlackPointFoundOnBorder = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// .....
|
||||||
|
// . .
|
||||||
|
// .___.
|
||||||
|
boolean bottomBorderNotWhite = true;
|
||||||
|
while (bottomBorderNotWhite && down < height) {
|
||||||
|
bottomBorderNotWhite = containsBlackPoint(left, right, down, true);
|
||||||
|
if (bottomBorderNotWhite) {
|
||||||
|
down++;
|
||||||
|
aBlackPointFoundOnBorder = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// .....
|
||||||
|
// | .
|
||||||
|
// .....
|
||||||
|
boolean leftBorderNotWhite = true;
|
||||||
|
while (leftBorderNotWhite && left >= 0) {
|
||||||
|
leftBorderNotWhite = containsBlackPoint(up, down, left, false);
|
||||||
|
if (leftBorderNotWhite) {
|
||||||
|
left--;
|
||||||
|
aBlackPointFoundOnBorder = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// .___.
|
||||||
|
// . .
|
||||||
|
// .....
|
||||||
|
boolean topBorderNotWhite = true;
|
||||||
|
while (topBorderNotWhite && up >= 0) {
|
||||||
|
topBorderNotWhite = containsBlackPoint(left, right, up, true);
|
||||||
|
if (topBorderNotWhite) {
|
||||||
|
up--;
|
||||||
|
aBlackPointFoundOnBorder = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (right >= width || down >= height || up < 0 || left < 0) {
|
||||||
|
sizeExceeded = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aBlackPointFoundOnBorder) {
|
||||||
|
atLeastOneBlackPointFoundOnBorder = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sizeExceeded && atLeastOneBlackPointFoundOnBorder) {
|
||||||
|
|
||||||
|
// t t
|
||||||
|
//z x
|
||||||
|
// x OR z
|
||||||
|
// y y
|
||||||
|
|
||||||
|
ResultPoint x = getBlackPoint(up, down, right - 1, false);
|
||||||
|
ResultPoint y = getBlackPoint(left, right, down - 1, true);
|
||||||
|
ResultPoint z = getBlackPoint(up, down, left + 1, false);
|
||||||
|
ResultPoint t = getBlackPoint(left, right, up + 1, true);
|
||||||
|
|
||||||
|
// if the rectangle if perfectly horizontal (mostly in test cases)
|
||||||
|
// then we end up with:
|
||||||
|
// zt x
|
||||||
|
//
|
||||||
|
// y
|
||||||
|
|
||||||
|
if (distance(z, t) < MIN_SIZE) {
|
||||||
|
ResultPoint u = getBlackPointInverted(up, down, right - 1, false);
|
||||||
|
t = x;
|
||||||
|
x = u;
|
||||||
|
}
|
||||||
|
|
||||||
|
return centerEdges(y, z, x, t);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw NotFoundException.getNotFoundInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* recenters the points of a constant distance towards the center
|
||||||
|
*
|
||||||
|
* @param y bottom most point
|
||||||
|
* @param z left most point
|
||||||
|
* @param x right most point
|
||||||
|
* @param t top most point
|
||||||
|
* @return {@link ResultPoint}[] describing the corners of the rectangular
|
||||||
|
* region. The first and last points are opposed on the diagonal, as
|
||||||
|
* are the second and third. The first point will be the topmost
|
||||||
|
* point and the last, the bottommost. The second point will be
|
||||||
|
* leftmost and the third, the rightmost
|
||||||
|
*/
|
||||||
|
private ResultPoint[] centerEdges(ResultPoint y, ResultPoint z,
|
||||||
|
ResultPoint x, ResultPoint t) {
|
||||||
|
|
||||||
|
//
|
||||||
|
// t t
|
||||||
|
// z x
|
||||||
|
// x OR z
|
||||||
|
// y y
|
||||||
|
//
|
||||||
|
|
||||||
|
float yi = y.getX(), yj = y.getY(), zi = z.getX(), zj = z.getY(), xi = x
|
||||||
|
.getX(), xj = x.getY(), ti = t.getX(), tj = t.getY();
|
||||||
|
|
||||||
|
final int corr = 1;
|
||||||
|
if (yi < width / 2) {
|
||||||
|
return new ResultPoint[]{new ResultPoint(ti - corr, tj + corr),
|
||||||
|
new ResultPoint(zi + corr, zj + corr),
|
||||||
|
new ResultPoint(xi - corr, xj - corr),
|
||||||
|
new ResultPoint(yi + corr, yj - corr)};
|
||||||
|
} else {
|
||||||
|
return new ResultPoint[]{new ResultPoint(ti + corr, tj + corr),
|
||||||
|
new ResultPoint(zi + corr, zj - corr),
|
||||||
|
new ResultPoint(xi - corr, xj + corr),
|
||||||
|
new ResultPoint(yi - corr, yj - corr)};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// L1 distance (metropolitan distance)
|
||||||
|
private static float distance(ResultPoint a, ResultPoint b) {
|
||||||
|
return Math.abs(a.getX() - b.getX()) + Math.abs(a.getY() - b.getY());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the coordinate of an extreme black point of a segment
|
||||||
|
*
|
||||||
|
* @param a min value of the scanned coordinate
|
||||||
|
* @param b max value of the scanned coordinate
|
||||||
|
* @param fixed value of fixed coordinate
|
||||||
|
* @param horizontal set to true if scan must be horizontal, false if vertical
|
||||||
|
* @return {@link ResultPoint} describing the black point. If scan is horizontal,
|
||||||
|
* the returned point is the first encountered if it is on the left of the image,
|
||||||
|
* else the last one. If scan is vertical, the returned point is the first encountered
|
||||||
|
* if it is on the top of the image, else the last one.
|
||||||
|
* {@link ResultPoint} is null if not black point has been found
|
||||||
|
*/
|
||||||
|
private ResultPoint getBlackPoint(int a, int b, int fixed, boolean horizontal) {
|
||||||
|
|
||||||
|
ResultPoint last = null;
|
||||||
|
|
||||||
|
if (horizontal) {
|
||||||
|
for (int x = a; x < b; x++) {
|
||||||
|
if (image.get(x, fixed)) {
|
||||||
|
if (x < width / 2) {
|
||||||
|
return new ResultPoint(x, fixed);
|
||||||
|
} else {
|
||||||
|
while (x < width && image.get(x, fixed)) {
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
x--;
|
||||||
|
last = new ResultPoint(x, fixed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int y = a; y < b; y++) {
|
||||||
|
if (image.get(fixed, y)) {
|
||||||
|
if (y < height / 2) {
|
||||||
|
return new ResultPoint(fixed, y);
|
||||||
|
} else {
|
||||||
|
while (y < height && image.get(fixed, y)) {
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
y--;
|
||||||
|
last = new ResultPoint(fixed, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return last;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as getBlackPoint, but returned point is the last one found.
|
||||||
|
*
|
||||||
|
* @param a min value of the scanned coordinate
|
||||||
|
* @param b max value of the scanned coordinate
|
||||||
|
* @param fixed value of fixed coordinate
|
||||||
|
* @param horizontal set to true if scan must be horizontal, false if vertical
|
||||||
|
* @return {@link ResultPoint} describing the black point.
|
||||||
|
*/
|
||||||
|
private ResultPoint getBlackPointInverted(int a, int b, int fixed, boolean horizontal) {
|
||||||
|
|
||||||
|
if (horizontal) {
|
||||||
|
for (int x = b + 1; x >= a; x--) {
|
||||||
|
if (image.get(x, fixed)) {
|
||||||
|
return new ResultPoint(x, fixed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int y = b + 1; y >= a; y--) {
|
||||||
|
if (image.get(fixed, y)) {
|
||||||
|
return new ResultPoint(fixed, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether a segment contains a black point
|
||||||
|
*
|
||||||
|
* @param a min value of the scanned coordinate
|
||||||
|
* @param b max value of the scanned coordinate
|
||||||
|
* @param fixed value of fixed coordinate
|
||||||
|
* @param horizontal set to true if scan must be horizontal, false if vertical
|
||||||
|
* @return true if a black point has been found, else false.
|
||||||
|
*/
|
||||||
|
private boolean containsBlackPoint(int a, int b, int fixed, boolean horizontal) {
|
||||||
|
|
||||||
|
if (horizontal) {
|
||||||
|
for (int x = a; x < b; x++) {
|
||||||
|
if (image.get(x, fixed)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int y = a; y < b; y++) {
|
||||||
|
if (image.get(fixed, y)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -23,7 +23,7 @@ import com.google.zxing.common.Collections;
|
||||||
import com.google.zxing.common.Comparator;
|
import com.google.zxing.common.Comparator;
|
||||||
import com.google.zxing.common.DetectorResult;
|
import com.google.zxing.common.DetectorResult;
|
||||||
import com.google.zxing.common.GridSampler;
|
import com.google.zxing.common.GridSampler;
|
||||||
import com.google.zxing.common.detector.MonochromeRectangleDetector;
|
import com.google.zxing.common.detector.WhiteRectangleDetector;
|
||||||
|
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
|
@ -37,7 +37,7 @@ import java.util.Vector;
|
||||||
*/
|
*/
|
||||||
public final class Detector {
|
public final class Detector {
|
||||||
|
|
||||||
//private static final int MAX_MODULES = 32;
|
private static final int MIN_GIVEUP_THRESHOLD = 3;
|
||||||
|
|
||||||
// Trick to avoid creating new Integer objects below -- a sort of crude copy of
|
// Trick to avoid creating new Integer objects below -- a sort of crude copy of
|
||||||
// the Integer.valueOf(int) optimization added in Java 5, not in J2ME
|
// the Integer.valueOf(int) optimization added in Java 5, not in J2ME
|
||||||
|
@ -46,17 +46,17 @@ public final class Detector {
|
||||||
// No, can't use valueOf()
|
// No, can't use valueOf()
|
||||||
|
|
||||||
private final BitMatrix image;
|
private final BitMatrix image;
|
||||||
private final MonochromeRectangleDetector rectangleDetector;
|
private final WhiteRectangleDetector rectangleDetector;
|
||||||
|
|
||||||
public Detector(BitMatrix image) {
|
public Detector(BitMatrix image) {
|
||||||
this.image = image;
|
this.image = image;
|
||||||
rectangleDetector = new MonochromeRectangleDetector(image);
|
rectangleDetector = new WhiteRectangleDetector(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Detects a Data Matrix Code in an image.</p>
|
* <p>Detects a Data Matrix Code in an image.</p>
|
||||||
*
|
*
|
||||||
* @return {@link DetectorResult} encapsulating results of detecting a QR Code
|
* @return {@link DetectorResult} encapsulating results of detecting a Data Matrix Code
|
||||||
* @throws NotFoundException if no Data Matrix Code can be found
|
* @throws NotFoundException if no Data Matrix Code can be found
|
||||||
*/
|
*/
|
||||||
public DetectorResult detect() throws NotFoundException {
|
public DetectorResult detect() throws NotFoundException {
|
||||||
|
@ -82,6 +82,12 @@ public final class Detector {
|
||||||
ResultPointsAndTransitions lSideOne = (ResultPointsAndTransitions) transitions.elementAt(0);
|
ResultPointsAndTransitions lSideOne = (ResultPointsAndTransitions) transitions.elementAt(0);
|
||||||
ResultPointsAndTransitions lSideTwo = (ResultPointsAndTransitions) transitions.elementAt(1);
|
ResultPointsAndTransitions lSideTwo = (ResultPointsAndTransitions) transitions.elementAt(1);
|
||||||
|
|
||||||
|
//give up if there is no chance we'll decode something...
|
||||||
|
if (lSideOne.transitions > MIN_GIVEUP_THRESHOLD ||
|
||||||
|
lSideTwo.transitions > MIN_GIVEUP_THRESHOLD) {
|
||||||
|
throw NotFoundException.getNotFoundInstance();
|
||||||
|
}
|
||||||
|
|
||||||
// Figure out which point is their intersection by tallying up the number of times we see the
|
// Figure out which point is their intersection by tallying up the number of times we see the
|
||||||
// endpoints in the four endpoints. One will show up twice.
|
// endpoints in the four endpoints. One will show up twice.
|
||||||
Hashtable pointCount = new Hashtable();
|
Hashtable pointCount = new Hashtable();
|
||||||
|
@ -142,10 +148,8 @@ public final class Detector {
|
||||||
|
|
||||||
// The top right point is actually the corner of a module, which is one of the two black modules
|
// The top right point is actually the corner of a module, which is one of the two black modules
|
||||||
// adjacent to the white module at the top right. Tracing to that corner from either the top left
|
// adjacent to the white module at the top right. Tracing to that corner from either the top left
|
||||||
// or bottom right should work here. The number of transitions could be higher than it should be
|
// or bottom right should work here.
|
||||||
// due to noise. So we try both and take the min.
|
int dimension = Math.max(transitionsBetween(topLeft, topRight).getTransitions(),
|
||||||
|
|
||||||
int dimension = Math.min(transitionsBetween(topLeft, topRight).getTransitions(),
|
|
||||||
transitionsBetween(bottomRight, topRight).getTransitions());
|
transitionsBetween(bottomRight, topRight).getTransitions());
|
||||||
if ((dimension & 0x01) == 1) {
|
if ((dimension & 0x01) == 1) {
|
||||||
// it can't be odd, so, round... up?
|
// it can't be odd, so, round... up?
|
||||||
|
@ -153,8 +157,79 @@ public final class Detector {
|
||||||
}
|
}
|
||||||
dimension += 2;
|
dimension += 2;
|
||||||
|
|
||||||
BitMatrix bits = sampleGrid(image, topLeft, bottomLeft, bottomRight, dimension);
|
//correct top right point to match the white module
|
||||||
return new DetectorResult(bits, new ResultPoint[] {pointA, pointB, pointC, pointD});
|
ResultPoint correctedTopRight = correctTopRight(bottomLeft, bottomRight, topLeft, topRight, dimension);
|
||||||
|
|
||||||
|
//We redetermine the dimension using the corrected top right point
|
||||||
|
int dimension2 = Math.min(transitionsBetween(topLeft, correctedTopRight).getTransitions(),
|
||||||
|
transitionsBetween(bottomRight, correctedTopRight).getTransitions());
|
||||||
|
dimension2++;
|
||||||
|
if ((dimension2 & 0x01) == 1) {
|
||||||
|
dimension2++;
|
||||||
|
}
|
||||||
|
|
||||||
|
BitMatrix bits = sampleGrid(image, topLeft, bottomLeft, bottomRight, correctedTopRight, dimension2);
|
||||||
|
|
||||||
|
return new DetectorResult(bits, new ResultPoint[]{topLeft, bottomLeft, bottomRight, correctedTopRight});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the position of the white top right module using the output of the rectangle detector
|
||||||
|
*/
|
||||||
|
private ResultPoint correctTopRight(ResultPoint bottomLeft,
|
||||||
|
ResultPoint bottomRight,
|
||||||
|
ResultPoint topLeft,
|
||||||
|
ResultPoint topRight,
|
||||||
|
int dimension) {
|
||||||
|
float corr = distance(bottomLeft, bottomRight) / (float) dimension;
|
||||||
|
float corrx = 0.0f;
|
||||||
|
float corry = 0.0f;
|
||||||
|
int norm = distance(topLeft, topRight);
|
||||||
|
float cos = (topRight.getX() - topLeft.getX()) / norm;
|
||||||
|
float sin = -(topRight.getY() - topLeft.getY()) / norm;
|
||||||
|
|
||||||
|
if (cos > 0.0f && sin > 0.0f) {
|
||||||
|
if (cos > sin) {
|
||||||
|
corrx = corr * cos;
|
||||||
|
corry = -corr * sin;
|
||||||
|
} else {
|
||||||
|
corrx = -corr * sin;
|
||||||
|
corry = -corr * cos;
|
||||||
|
}
|
||||||
|
} else if (cos > 0.0f && sin < 0.0f) {
|
||||||
|
if (cos > -sin) {
|
||||||
|
corrx = -corr * sin;
|
||||||
|
corry = -corr * cos;
|
||||||
|
} else {
|
||||||
|
corrx = corr * cos;
|
||||||
|
corry = -corr * sin;
|
||||||
|
}
|
||||||
|
} else if (cos < 0.0f && sin < 0.0f) {
|
||||||
|
if (-cos > -sin) {
|
||||||
|
corrx = corr * cos;
|
||||||
|
corry = -corr * sin;
|
||||||
|
} else {
|
||||||
|
corrx = -corr * sin;
|
||||||
|
corry = -corr * cos;
|
||||||
|
}
|
||||||
|
} else if (cos < 0.0f && sin > 0.0f) {
|
||||||
|
if (-cos > sin) {
|
||||||
|
corrx = -corr * sin;
|
||||||
|
corry = -corr * cos;
|
||||||
|
} else {
|
||||||
|
corrx = corr * cos;
|
||||||
|
corry = -corr * sin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ResultPoint(topRight.getX() + corrx, topRight.getY() + corry);
|
||||||
|
}
|
||||||
|
|
||||||
|
// L2 distance
|
||||||
|
private static int distance(ResultPoint a, ResultPoint b) {
|
||||||
|
return (int) Math.round(Math.sqrt((a.getX() - b.getX())
|
||||||
|
* (a.getX() - b.getX()) + (a.getY() - b.getY())
|
||||||
|
* (a.getY() - b.getY())));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -169,36 +244,29 @@ public final class Detector {
|
||||||
ResultPoint topLeft,
|
ResultPoint topLeft,
|
||||||
ResultPoint bottomLeft,
|
ResultPoint bottomLeft,
|
||||||
ResultPoint bottomRight,
|
ResultPoint bottomRight,
|
||||||
|
ResultPoint topRight,
|
||||||
int dimension) throws NotFoundException {
|
int dimension) throws NotFoundException {
|
||||||
|
|
||||||
// We make up the top right point for now, based on the others.
|
|
||||||
// TODO: we actually found a fourth corner above and figured out which of two modules
|
|
||||||
// it was the corner of. We could use that here and adjust for perspective distortion.
|
|
||||||
float topRightX = (bottomRight.getX() - bottomLeft.getX()) + topLeft.getX();
|
|
||||||
float topRightY = (bottomRight.getY() - bottomLeft.getY()) + topLeft.getY();
|
|
||||||
|
|
||||||
// Note that unlike in the QR Code sampler, we didn't find the center of modules, but the
|
|
||||||
// very corners. So there is no 0.5f here; 0.0f is right.
|
|
||||||
GridSampler sampler = GridSampler.getInstance();
|
GridSampler sampler = GridSampler.getInstance();
|
||||||
return sampler.sampleGrid(
|
|
||||||
image,
|
return sampler.sampleGrid(image,
|
||||||
dimension,
|
dimension,
|
||||||
0.0f,
|
0.5f,
|
||||||
0.0f,
|
0.5f,
|
||||||
dimension,
|
dimension - 0.5f,
|
||||||
0.0f,
|
0.5f,
|
||||||
dimension,
|
dimension - 0.5f,
|
||||||
dimension,
|
dimension - 0.5f,
|
||||||
0.0f,
|
0.5f,
|
||||||
dimension,
|
dimension - 0.5f,
|
||||||
topLeft.getX(),
|
topLeft.getX(),
|
||||||
topLeft.getY(),
|
topLeft.getY(),
|
||||||
topRightX,
|
topRight.getX(),
|
||||||
topRightY,
|
topRight.getY(),
|
||||||
bottomRight.getX(),
|
bottomRight.getX(),
|
||||||
bottomRight.getY(),
|
bottomRight.getY(),
|
||||||
bottomLeft.getX(),
|
bottomLeft.getX(),
|
||||||
bottomLeft.getY());
|
bottomLeft.getY());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -28,9 +28,9 @@ public final class DataMatrixBlackBox1TestCase extends AbstractBlackBoxTestCase
|
||||||
// TODO use MultiFormatReader here once Data Matrix decoder is done
|
// TODO use MultiFormatReader here once Data Matrix decoder is done
|
||||||
super("test/data/blackbox/datamatrix-1", new DataMatrixReader(), BarcodeFormat.DATA_MATRIX);
|
super("test/data/blackbox/datamatrix-1", new DataMatrixReader(), BarcodeFormat.DATA_MATRIX);
|
||||||
addTest(7, 7, 0.0f);
|
addTest(7, 7, 0.0f);
|
||||||
addTest(7, 7, 90.0f);
|
addTest(4, 4, 90.0f);
|
||||||
addTest(6, 6, 180.0f);
|
addTest(6, 6, 180.0f);
|
||||||
addTest(4, 4, 270.0f);
|
addTest(6, 6, 270.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -27,10 +27,10 @@ public final class DataMatrixBlackBox2TestCase extends AbstractBlackBoxTestCase
|
||||||
public DataMatrixBlackBox2TestCase() {
|
public DataMatrixBlackBox2TestCase() {
|
||||||
// TODO use MultiFormatReader here once Data Matrix decoder is done
|
// TODO use MultiFormatReader here once Data Matrix decoder is done
|
||||||
super("test/data/blackbox/datamatrix-2", new DataMatrixReader(), BarcodeFormat.DATA_MATRIX);
|
super("test/data/blackbox/datamatrix-2", new DataMatrixReader(), BarcodeFormat.DATA_MATRIX);
|
||||||
addTest(4, 4, 0.0f);
|
addTest(5, 5, 0.0f);
|
||||||
addTest(1, 1, 90.0f);
|
addTest(6, 6, 90.0f);
|
||||||
addTest(3, 3, 180.0f);
|
addTest(7, 7, 180.0f);
|
||||||
addTest(1, 1, 270.0f);
|
addTest(7, 7, 270.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue