diff --git a/core/src/com/google/zxing/qrcode/detector/DefaultGridSampler.java b/core/src/com/google/zxing/qrcode/detector/DefaultGridSampler.java index 4b71ece06..5223d7f16 100644 --- a/core/src/com/google/zxing/qrcode/detector/DefaultGridSampler.java +++ b/core/src/com/google/zxing/qrcode/detector/DefaultGridSampler.java @@ -77,7 +77,7 @@ public final class DefaultGridSampler extends GridSampler { for (int j = 0; j < max; j += 2) { if (image.isBlack((int) points[j], (int) points[j + 1])) { // Black(-ish) pixel - bits.set(i, j); + bits.set(i, j >> 1); } } } diff --git a/core/src/com/google/zxing/qrcode/detector/PerspectiveTransform.java b/core/src/com/google/zxing/qrcode/detector/PerspectiveTransform.java index f07f09744..5a55d3458 100644 --- a/core/src/com/google/zxing/qrcode/detector/PerspectiveTransform.java +++ b/core/src/com/google/zxing/qrcode/detector/PerspectiveTransform.java @@ -49,9 +49,11 @@ final class PerspectiveTransform { float x1p, float y1p, float x2p, float y2p, float x3p, float y3p) { - return - quadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3).times( - squareToQuadrilateral(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p)); + + PerspectiveTransform qToS = quadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3); + PerspectiveTransform sToQ = squareToQuadrilateral(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p); + PerspectiveTransform product = sToQ.times(qToS); + return product; } void transformPoints(float[] points) { @@ -74,32 +76,31 @@ final class PerspectiveTransform { } } - private static PerspectiveTransform squareToQuadrilateral(float x0, float y0, + static PerspectiveTransform squareToQuadrilateral(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3) { - float dx1 = x1 - x2; - float dx2 = x3 - x2; - float dx3 = x0 - x1 + x2 - x3; - float dy1 = y1 - y2; float dy2 = y3 - y2; float dy3 = y0 - y1 + y2 - y3; - float denominator = dx1*dy2 - dx2*dy1; - float a13 = (dx3*dy2 - dx2*dy3) / denominator; - float a23 = (dx1*dy3 - dx3*dy1) / denominator; - - return new PerspectiveTransform(x1 - x0 + a13*x1, - x3 - x0 + a23*x3, - x0, - y1 - y0 + a13*y1, - y3 - y0 + a23*y3, - y0, - a13, - a23, - 1.0f); + if (dy2 == 0.0f && dy3 == 0.0f) { + return new PerspectiveTransform(x1 - x0, x2 - x1, x0, + y1 - y0, y2 - y1, y0, + 0.0f, 0.0f, 1.0f); + } else { + float dx1 = x1 - x2; + float dx2 = x3 - x2; + float dx3 = x0 - x1 + x2 - x3; + float dy1 = y1 - y2; + float denominator = dx1*dy2 - dx2*dy1; + float a13 = (dx3*dy2 - dx2*dy3) / denominator; + float a23 = (dx1*dy3 - dx3*dy1) / denominator; + return new PerspectiveTransform(x1 - x0 + a13*x1, x3 - x0 + a23*x3, x0, + y1 - y0 + a13*y1, y3 - y0 + a23*y3, y0, + a13, a23, 1.0f); + } } - private static PerspectiveTransform quadrilateralToSquare(float x0, float y0, + static PerspectiveTransform quadrilateralToSquare(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3) { @@ -107,7 +108,7 @@ final class PerspectiveTransform { return squareToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3).buildAdjoint(); } - private PerspectiveTransform buildAdjoint() { + PerspectiveTransform buildAdjoint() { // Adjoint is the transpose of the cofactor matrix: return new PerspectiveTransform(a22*a33 - a23*a32, a23*a31 - a21*a33, @@ -120,16 +121,17 @@ final class PerspectiveTransform { a11*a22 - a12*a21); } - private PerspectiveTransform times(PerspectiveTransform other) { + PerspectiveTransform times(PerspectiveTransform other) { return new PerspectiveTransform(a11*other.a11 + a21*other.a12 + a31*other.a13, - a11*other.a12 + a12*other.a22 + a13*other.a32, - a11*other.a13 + a12*other.a23 + a13*other.a33, - a21*other.a11 + a22*other.a21 + a23*other.a31, - a21*other.a12 + a22*other.a22 + a23*other.a32, - a21*other.a13 + a22*other.a23 + a23*other.a33, - a31*other.a11 + a32*other.a21 + a33*other.a31, - a31*other.a12 + a32*other.a22 + a33*other.a33, - a31*other.a13 + a32*other.a23 + a33*other.a33); + a11*other.a21 + a21*other.a22 + a31*other.a23, + a11*other.a31 + a21*other.a32 + a31*other.a33, + a12*other.a11 + a22*other.a12 + a32*other.a13, + a12*other.a21 + a22*other.a22 + a32*other.a23, + a12*other.a31 + a22*other.a32 + a32*other.a33, + a13*other.a11 + a23*other.a12 + a33*other.a13, + a13*other.a21 + a23*other.a22 + a33*other.a23, + a13*other.a31 + a23*other.a32 + a33*other.a33); + } } diff --git a/core/test/src/com/google/zxing/qrcode/detector/PerspectiveTransformTestCase.java b/core/test/src/com/google/zxing/qrcode/detector/PerspectiveTransformTestCase.java new file mode 100644 index 000000000..451cd2a2b --- /dev/null +++ b/core/test/src/com/google/zxing/qrcode/detector/PerspectiveTransformTestCase.java @@ -0,0 +1,58 @@ +/* + * Copyright 2007 Google Inc. + * + * 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.detector; + +import junit.framework.TestCase; + +/** + * @author srowen@google.com (Sean Owen) + */ +public final class PerspectiveTransformTestCase extends TestCase { + + private static final float EPSILON = 0.0001f; + + public void testSquareToQuadrilateral() { + PerspectiveTransform pt = PerspectiveTransform.squareToQuadrilateral( + 2.0f, 3.0f, 10.0f, 4.0f, 16.0f, 15.0f, 4.0f, 9.0f); + assertPointEquals(2.0f, 3.0f, 0.0f, 0.0f, pt); + assertPointEquals(10.0f, 4.0f, 1.0f, 0.0f, pt); + assertPointEquals(4.0f, 9.0f, 0.0f, 1.0f, pt); + assertPointEquals(16.0f, 15.0f, 1.0f, 1.0f, pt); + assertPointEquals(6.535211f, 6.8873234f, 0.5f, 0.5f, pt); + assertPointEquals(48.0f, 42.42857f, 1.5f, 1.5f, pt); + } + + public void testQuadrilateralToQuadrilateral() { + PerspectiveTransform pt = PerspectiveTransform.quadrilateralToQuadrilateral( + 2.0f, 3.0f, 10.0f, 4.0f, 16.0f, 15.0f, 4.0f, 9.0f, + 103.0f, 110.0f, 300.0f, 120.0f, 290.0f, 270.0f, 150.0f, 280.0f); + assertPointEquals(103.0f, 110.0f, 2.0f, 3.0f, pt); + assertPointEquals(300.0f, 120.0f, 10.0f, 4.0f, pt); + assertPointEquals(290.0f, 270.0f, 16.0f, 15.0f, pt); + assertPointEquals(150.0f, 280.0f, 4.0f, 9.0f, pt); + assertPointEquals(7.1516876f, -64.60185f, 0.5f, 0.5f, pt); + assertPointEquals(328.09116f, 334.16385f,50.0f, 50.0f, pt); + } + + private static void assertPointEquals(float expectedX, float expectedY, float sourceX, float sourceY, PerspectiveTransform pt) { + float[] points = new float[] { sourceX, sourceY }; + pt.transformPoints(points); + assertEquals(expectedX, points[0], EPSILON); + assertEquals(expectedY, points[1], EPSILON); + } + +} \ No newline at end of file