p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY,
p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY);
- return sampleGrid(image, dimension, transform);
+ return sampleGrid(image, dimension, dimension, transform);
}
-
+
public BitMatrix sampleGrid(BitMatrix image,
- int dimension,
- PerspectiveTransform transform) throws NotFoundException {
- BitMatrix bits = new BitMatrix(dimension);
- float[] points = new float[dimension << 1];
- for (int y = 0; y < dimension; y++) {
- int max = points.length;
- float iValue = (float) y + 0.5f;
- for (int x = 0; x < max; x += 2) {
- points[x] = (float) (x >> 1) + 0.5f;
- points[x + 1] = iValue;
- }
- transform.transformPoints(points);
- // Quick check to see if points transformed to something inside the image;
- // sufficient to check the endpoints
- checkAndNudgePoints(image, points);
- try {
- for (int x = 0; x < max; x += 2) {
- if (image.get((int) points[x], (int) points[x + 1])) {
- // Black(-ish) pixel
- bits.set(x >> 1, y);
- }
- }
- } catch (ArrayIndexOutOfBoundsException aioobe) {
- // This feels wrong, but, sometimes if the finder patterns are misidentified, the resulting
- // transform gets "twisted" such that it maps a straight line of points to a set of points
- // whose endpoints are in bounds, but others are not. There is probably some mathematical
- // way to detect this about the transformation that I don't know yet.
- // This results in an ugly runtime exception despite our clever checks above -- can't have
- // that. We could check each point's coordinates but that feels duplicative. We settle for
- // catching and wrapping ArrayIndexOutOfBoundsException.
- throw NotFoundException.getNotFoundInstance();
- }
- }
- return bits;
- }
+ int dimensionX,
+ int dimensionY,
+ float p1ToX, float p1ToY,
+ float p2ToX, float p2ToY,
+ float p3ToX, float p3ToY,
+ float p4ToX, float p4ToY,
+ float p1FromX, float p1FromY,
+ float p2FromX, float p2FromY,
+ float p3FromX, float p3FromY,
+ float p4FromX, float p4FromY) throws NotFoundException {
+
+PerspectiveTransform transform = PerspectiveTransform.quadrilateralToQuadrilateral(
+p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY,
+p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY);
+return sampleGrid(image, dimensionX, dimensionY, transform);
+}
+
+ public BitMatrix sampleGrid(BitMatrix image,
+ int dimensionX, int dimensionY,
+ PerspectiveTransform transform) throws NotFoundException {
+BitMatrix bits = new BitMatrix(dimensionX, dimensionY);
+float[] points = new float[dimensionX << 1];
+for (int y = 0; y < dimensionY; y++) {
+int max = points.length;
+float iValue = (float) y + 0.5f;
+for (int x = 0; x < max; x += 2) {
+points[x] = (float) (x >> 1) + 0.5f;
+points[x + 1] = iValue;
+}
+transform.transformPoints(points);
+// Quick check to see if points transformed to something inside the image;
+// sufficient to check the endpoints
+checkAndNudgePoints(image, points);
+try {
+for (int x = 0; x < max; x += 2) {
+if (image.get((int) points[x], (int) points[x + 1])) {
+// Black(-ish) pixel
+bits.set(x >> 1, y);
+}
+}
+} catch (ArrayIndexOutOfBoundsException aioobe) {
+// This feels wrong, but, sometimes if the finder patterns are misidentified, the resulting
+// transform gets "twisted" such that it maps a straight line of points to a set of points
+// whose endpoints are in bounds, but others are not. There is probably some mathematical
+// way to detect this about the transformation that I don't know yet.
+// This results in an ugly runtime exception despite our clever checks above -- can't have
+// that. We could check each point's coordinates but that feels duplicative. We settle for
+// catching and wrapping ArrayIndexOutOfBoundsException.
+throw NotFoundException.getNotFoundInstance();
+}
+}
+return bits;
+}
+
}
float p3FromX, float p3FromY,
float p4FromX, float p4FromY) throws NotFoundException;
+ /**
+ * Samples an image for a rectangular matrix of bits of the given dimension.
+ * @param image image to sample
+ * @param dimensionX width of {@link BitMatrix} to sample from image
+ * @param dimensionY height of {@link BitMatrix} to sample from image
+ * @return {@link BitMatrix} representing a grid of points sampled from the image within a region
+ * defined by the "from" parameters
+ * @throws NotFoundException if image can't be sampled, for example, if the transformation defined
+ * by the given points is invalid or results in sampling outside the image boundaries
+ */
+ public abstract BitMatrix sampleGrid(BitMatrix image,
+ int dimensionX,
+ int dimensionY,
+ float p1ToX, float p1ToY,
+ float p2ToX, float p2ToY,
+ float p3ToX, float p3ToY,
+ float p4ToX, float p4ToY,
+ float p1FromX, float p1FromY,
+ float p2FromX, float p2FromY,
+ float p3FromX, float p3FromY,
+ float p4FromX, float p4FromY) throws NotFoundException;
+
public BitMatrix sampleGrid(BitMatrix image,
int dimension,
PerspectiveTransform transform) throws NotFoundException {
\r
/**\r
* @param bitMatrix {@link BitMatrix} to parse\r
- * @throws FormatException if dimension is < 10 or > 144 or not 0 mod 2\r
+ * @throws FormatException if dimension is < 8 or > 144 or not 0 mod 2\r
*/\r
BitMatrixParser(BitMatrix bitMatrix) throws FormatException {\r
int dimension = bitMatrix.getHeight();\r
- if (dimension < 10 || dimension > 144 || (dimension & 0x01) != 0) {\r
+ if (dimension < 8 || dimension > 144 || (dimension & 0x01) != 0) {\r
throw FormatException.getFormatInstance();\r
}\r
\r
version = readVersion(bitMatrix);\r
this.mappingBitMatrix = extractDataRegion(bitMatrix);\r
- // TODO(bbrown): Make this work for rectangular symbols\r
- this.readMappingMatrix = new BitMatrix(this.mappingBitMatrix.getHeight());\r
+ this.readMappingMatrix = new BitMatrix(this.mappingBitMatrix.getWidth(), this.mappingBitMatrix.getHeight());\r
}\r
\r
/**\r
return version;\r
}\r
\r
- // TODO(bbrown): make this work for rectangular dimensions as well.\r
int numRows = bitMatrix.getHeight();\r
- int numColumns = numRows;\r
+ int numColumns = bitMatrix.getWidth();\r
\r
return Version.getVersionForDimensions(numRows, numColumns);\r
}\r
\r
int row = 4;\r
int column = 0;\r
- // TODO(bbrown): Data Matrix can be rectangular, assuming square for now\r
+\r
int numRows = mappingBitMatrix.getHeight();\r
- int numColumns = numRows;\r
+ int numColumns = mappingBitMatrix.getWidth();\r
\r
boolean corner1Read = false;\r
boolean corner2Read = false;\r
int symbolSizeRows = version.getSymbolSizeRows();\r
int symbolSizeColumns = version.getSymbolSizeColumns();\r
\r
- // TODO(bbrown): Make this work with rectangular codes\r
if (bitMatrix.getHeight() != symbolSizeRows) {\r
throw new IllegalArgumentException("Dimension of bitMarix must match the version size");\r
}\r
int numDataRegionsColumn = symbolSizeColumns / dataRegionSizeColumns;\r
\r
int sizeDataRegionRow = numDataRegionsRow * dataRegionSizeRows;\r
- //int sizeDataRegionColumn = numDataRegionsColumn * dataRegionSizeColumns;\r
+ int sizeDataRegionColumn = numDataRegionsColumn * dataRegionSizeColumns;\r
\r
// TODO(bbrown): Make this work with rectangular codes\r
- BitMatrix bitMatrixWithoutAlignment = new BitMatrix(sizeDataRegionRow);\r
+ BitMatrix bitMatrixWithoutAlignment = new BitMatrix(sizeDataRegionColumn, sizeDataRegionRow);\r
for (int dataRegionRow = 0; dataRegionRow < numDataRegionsRow; ++dataRegionRow) {\r
int dataRegionRowOffset = dataRegionRow * dataRegionSizeRows;\r
for (int dataRegionColumn = 0; dataRegionColumn < numDataRegionsColumn; ++dataRegionColumn) {\r
new ECBlocks(14, new ECB(1, 16))),\r
new Version(28, 12, 36, 10, 16,\r
new ECBlocks(18, new ECB(1, 22))),\r
- new Version(29, 16, 36, 10, 16,\r
+ new Version(29, 16, 36, 14, 16,\r
new ECBlocks(24, new ECB(1, 32))),\r
new Version(30, 16, 48, 14, 22,\r
new ECBlocks(28, new ECB(1, 49)))\r
// 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
// or bottom right should work here.
- int dimension = Math.min(transitionsBetween(topLeft, topRight).getTransitions(),
- transitionsBetween(bottomRight, topRight).getTransitions());
- if ((dimension & 0x01) == 1) {
+
+
+ int dimensionTop = transitionsBetween(topLeft, topRight).getTransitions();
+ int dimensionRight = transitionsBetween(bottomRight, topRight).getTransitions();
+
+ if ((dimensionTop & 0x01) == 1) {
// it can't be odd, so, round... up?
- dimension++;
+ dimensionTop++;
}
- dimension += 2;
+ dimensionTop += 2;
+
+ if ((dimensionRight & 0x01) == 1) {
+ // it can't be odd, so, round... up?
+ dimensionRight++;
+ }
+ dimensionRight += 2;
+
+ BitMatrix bits = null;
+ ResultPoint correctedTopRight = null;
+
+ if (dimensionTop >= dimensionRight * 2 || dimensionRight >= dimensionTop * 2){
+ //The matrix is rectangular
+
+ correctedTopRight = correctTopRightRectangular(bottomLeft, bottomRight, topLeft, topRight, dimensionTop, dimensionRight);
+ if (correctedTopRight == null){
+ correctedTopRight = topRight;
+ }
+
+ dimensionTop = transitionsBetween(topLeft, correctedTopRight).getTransitions();
+ dimensionRight = transitionsBetween(bottomRight, correctedTopRight).getTransitions();
+
+ if ((dimensionTop & 0x01) == 1) {
+ // it can't be odd, so, round... up?
+ dimensionTop++;
+ }
+
+ if ((dimensionRight & 0x01) == 1) {
+ // it can't be odd, so, round... up?
+ dimensionRight++;
+ }
+
+ bits = sampleGrid(image, topLeft, bottomLeft, bottomRight, correctedTopRight, dimensionTop, dimensionRight);
+
+ } else {
+ //The matrix is square
+
+ int dimension = Math.min(dimensionRight, dimensionTop);
+ //correct top right point to match the white module
+ correctedTopRight = correctTopRight(bottomLeft, bottomRight, topLeft, topRight, dimension);
+ if (correctedTopRight == null){
+ correctedTopRight = topRight;
+ }
- //correct top right point to match the white module
- ResultPoint correctedTopRight = correctTopRight(bottomLeft, bottomRight, topLeft, topRight, dimension);
- if (correctedTopRight == null){
- correctedTopRight = topRight;
- }
+ //We redetermine the dimension using the corrected top right point
+ int dimensionCorrected = Math.max(transitionsBetween(topLeft, correctedTopRight).getTransitions(),
+ transitionsBetween(bottomRight, correctedTopRight).getTransitions());
+ dimensionCorrected++;
+ if ((dimensionCorrected & 0x01) == 1) {
+ dimensionCorrected++;
+ }
- //We redetermine the dimension using the corrected top right point
- int dimension2 = Math.max(transitionsBetween(topLeft, correctedTopRight).getTransitions(),
- transitionsBetween(bottomRight, correctedTopRight).getTransitions());
- dimension2++;
- if ((dimension2 & 0x01) == 1) {
- dimension2++;
+ bits = sampleGrid(image, topLeft, bottomLeft, bottomRight, correctedTopRight, dimensionCorrected, dimensionCorrected);
}
- 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
+ * Calculates the position of the white top right module using the output of the rectangle detector for a rectangular matrix
+ */
+ private ResultPoint correctTopRightRectangular(ResultPoint bottomLeft,
+ ResultPoint bottomRight, ResultPoint topLeft, ResultPoint topRight,
+ int dimensionTop, int dimensionRight) {
+
+ float corr = distance(bottomLeft, bottomRight) / (float)dimensionTop;
+ int norm = distance(topLeft, topRight);
+ float cos = (topRight.getX() - topLeft.getX()) / norm;
+ float sin = (topRight.getY() - topLeft.getY()) / norm;
+
+ ResultPoint c1 = new ResultPoint(topRight.getX()+corr*cos, topRight.getY()+corr*sin);
+
+ corr = distance(bottomLeft, topLeft) / (float)dimensionRight;
+ norm = distance(bottomRight, topRight);
+ cos = (topRight.getX() - bottomRight.getX()) / norm;
+ sin = (topRight.getY() - bottomRight.getY()) / norm;
+
+ ResultPoint c2 = new ResultPoint(topRight.getX()+corr*cos, topRight.getY()+corr*sin);
+
+ if (!isValid(c1)){
+ if (isValid(c2)){
+ return c2;
+ }
+ return null;
+ } else if (!isValid(c2)){
+ return c1;
+ }
+
+ int l1 = Math.abs(dimensionTop - transitionsBetween(topLeft, c1).getTransitions()) +
+ Math.abs(dimensionRight - transitionsBetween(bottomRight, c1).getTransitions());
+ int l2 = Math.abs(dimensionTop - transitionsBetween(topLeft, c2).getTransitions()) +
+ Math.abs(dimensionRight - transitionsBetween(bottomRight, c2).getTransitions());
+
+ if (l1 <= l2){
+ return c1;
+ }
+
+ return c2;
+}
+
+/**
+ * Calculates the position of the white top right module using the output of the rectangle detector for a square matrix
*/
private ResultPoint correctTopRight(ResultPoint bottomLeft,
ResultPoint bottomRight,
ResultPoint bottomLeft,
ResultPoint bottomRight,
ResultPoint topRight,
- int dimension) throws NotFoundException {
+ int dimensionX,
+ int dimensionY) throws NotFoundException {
GridSampler sampler = GridSampler.getInstance();
return sampler.sampleGrid(image,
- dimension,
+ dimensionX,
+ dimensionY,
0.5f,
0.5f,
- dimension - 0.5f,
+ dimensionX - 0.5f,
0.5f,
- dimension - 0.5f,
- dimension - 0.5f,
+ dimensionX - 0.5f,
+ dimensionY - 0.5f,
0.5f,
- dimension - 0.5f,
+ dimensionY - 0.5f,
topLeft.getX(),
topLeft.getY(),
topRight.getX(),
--- /dev/null
+abcde
\ No newline at end of file
--- /dev/null
+abcdefghijklm
\ No newline at end of file
--- /dev/null
+abcdef
\ No newline at end of file
--- /dev/null
+abcdefghijklmnopq
\ No newline at end of file
--- /dev/null
+abcdefghijklmnopqrstuvwxyz
\ No newline at end of file
--- /dev/null
+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVW
\ No newline at end of file
public DataMatrixBlackBox1TestCase() {
// TODO use MultiFormatReader here once Data Matrix decoder is done
super("test/data/blackbox/datamatrix-1", new DataMatrixReader(), BarcodeFormat.DATA_MATRIX);
- addTest(7, 7, 0.0f);
- addTest(7, 7, 90.0f);
- addTest(7, 7, 180.0f);
- addTest(7, 7, 270.0f);
+ addTest(13, 13, 0.0f);
+ addTest(13, 13, 90.0f);
+ addTest(13, 13, 180.0f);
+ addTest(13, 13, 270.0f);
}
}
\ No newline at end of file
addTest(10, 10, 0.0f);
addTest(13, 13, 90.0f);
addTest(16, 16, 180.0f);
- addTest(12, 12, 270.0f);
+ addTest(13, 13, 270.0f);
}
}