X-Git-Url: http://git.rot13.org/?p=zxing.git;a=blobdiff_plain;f=core%2Fsrc%2Fcom%2Fgoogle%2Fzxing%2Fqrcode%2Fdetector%2FDetector.java;h=b0eba53d3564b8f97aad6a019536bbf8e457568b;hp=0f28ec9bcd54af0a9f3aac81fbfbed243865d236;hb=22db33e76ba58134f2dbcfae660267a4062136ac;hpb=1f22643c43df9eb536e99ec536551a8d5ce846fb diff --git a/core/src/com/google/zxing/qrcode/detector/Detector.java b/core/src/com/google/zxing/qrcode/detector/Detector.java index 0f28ec9b..b0eba53d 100644 --- a/core/src/com/google/zxing/qrcode/detector/Detector.java +++ b/core/src/com/google/zxing/qrcode/detector/Detector.java @@ -16,13 +16,15 @@ package com.google.zxing.qrcode.detector; -import com.google.zxing.BlackPointEstimationMethod; -import com.google.zxing.MonochromeBitmapSource; -import com.google.zxing.ReaderException; +import com.google.zxing.DecodeHintType; +import com.google.zxing.FormatException; +import com.google.zxing.NotFoundException; import com.google.zxing.ResultPoint; +import com.google.zxing.ResultPointCallback; import com.google.zxing.common.BitMatrix; import com.google.zxing.common.DetectorResult; import com.google.zxing.common.GridSampler; +import com.google.zxing.common.PerspectiveTransform; import com.google.zxing.qrcode.decoder.Version; import java.util.Hashtable; @@ -35,23 +37,28 @@ import java.util.Hashtable; */ public class Detector { - private final MonochromeBitmapSource image; + private final BitMatrix image; + private ResultPointCallback resultPointCallback; - public Detector(MonochromeBitmapSource image) { + public Detector(BitMatrix image) { this.image = image; } - protected MonochromeBitmapSource getImage() { + protected BitMatrix getImage() { return image; } + protected ResultPointCallback getResultPointCallback() { + return resultPointCallback; + } + /** *

Detects a QR Code in an image, simply.

* * @return {@link DetectorResult} encapsulating results of detecting a QR Code - * @throws ReaderException if no QR Code can be found + * @throws NotFoundException if no QR Code can be found */ - public DetectorResult detect() throws ReaderException { + public DetectorResult detect() throws NotFoundException, FormatException { return detect(null); } @@ -59,23 +66,23 @@ public class Detector { *

Detects a QR Code in an image, simply.

* * @param hints optional hints to detector - * @return {@link DetectorResult} encapsulating results of detecting a QR Code - * @throws ReaderException if no QR Code can be found + * @return {@link NotFoundException} encapsulating results of detecting a QR Code + * @throws NotFoundException if QR Code cannot be found + * @throws FormatException if a QR Code cannot be decoded */ - public DetectorResult detect(Hashtable hints) throws ReaderException { + public DetectorResult detect(Hashtable hints) throws NotFoundException, FormatException { - MonochromeBitmapSource image = this.image; - if (!BlackPointEstimationMethod.TWO_D_SAMPLING.equals(image.getLastEstimationMethod())) { - image.estimateBlackPoint(BlackPointEstimationMethod.TWO_D_SAMPLING, 0); - } + resultPointCallback = hints == null ? null : + (ResultPointCallback) hints.get(DecodeHintType.NEED_RESULT_POINT_CALLBACK); - FinderPatternFinder finder = new FinderPatternFinder(image); + FinderPatternFinder finder = new FinderPatternFinder(image, resultPointCallback); FinderPatternInfo info = finder.find(hints); return processFinderPatternInfo(info); } - protected DetectorResult processFinderPatternInfo(FinderPatternInfo info) throws ReaderException { + protected DetectorResult processFinderPatternInfo(FinderPatternInfo info) + throws NotFoundException, FormatException { FinderPattern topLeft = info.getTopLeft(); FinderPattern topRight = info.getTopRight(); @@ -83,7 +90,7 @@ public class Detector { float moduleSize = calculateModuleSize(topLeft, topRight, bottomLeft); if (moduleSize < 1.0f) { - throw ReaderException.getInstance(); + throw NotFoundException.getNotFoundInstance(); } int dimension = computeDimension(topLeft, topRight, bottomLeft, moduleSize); Version provisionalVersion = Version.getProvisionalVersionForDimension(dimension); @@ -111,14 +118,17 @@ public class Detector { estAlignmentY, (float) i); break; - } catch (ReaderException re) { + } catch (NotFoundException re) { // try next round } } // If we didn't find alignment pattern... well try anyway without it } - BitMatrix bits = sampleGrid(image, topLeft, topRight, bottomLeft, alignmentPattern, dimension); + PerspectiveTransform transform = + createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension); + + BitMatrix bits = sampleGrid(image, transform, dimension); ResultPoint[] points; if (alignmentPattern == null) { @@ -129,12 +139,11 @@ public class Detector { return new DetectorResult(bits, points); } - private static BitMatrix sampleGrid(MonochromeBitmapSource image, - ResultPoint topLeft, - ResultPoint topRight, - ResultPoint bottomLeft, - ResultPoint alignmentPattern, - int dimension) throws ReaderException { + public PerspectiveTransform createTransform(ResultPoint topLeft, + ResultPoint topRight, + ResultPoint bottomLeft, + ResultPoint alignmentPattern, + int dimension) { float dimMinusThree = (float) dimension - 3.5f; float bottomRightX; float bottomRightY; @@ -151,10 +160,7 @@ public class Detector { sourceBottomRightX = sourceBottomRightY = dimMinusThree; } - GridSampler sampler = GridSampler.getInstance(); - return sampler.sampleGrid( - image, - dimension, + return PerspectiveTransform.quadrilateralToQuadrilateral( 3.5f, 3.5f, dimMinusThree, @@ -173,14 +179,22 @@ public class Detector { bottomLeft.getY()); } + private static BitMatrix sampleGrid(BitMatrix image, + PerspectiveTransform transform, + int dimension) throws NotFoundException { + + GridSampler sampler = GridSampler.getInstance(); + return sampler.sampleGrid(image, dimension, dimension, transform); + } + /** *

Computes the dimension (number of modules on a size) of the QR Code based on the position * of the finder patterns and estimated module size.

*/ - private static int computeDimension(ResultPoint topLeft, - ResultPoint topRight, - ResultPoint bottomLeft, - float moduleSize) throws ReaderException { + protected static int computeDimension(ResultPoint topLeft, + ResultPoint topRight, + ResultPoint bottomLeft, + float moduleSize) throws NotFoundException { int tltrCentersDimension = round(ResultPoint.distance(topLeft, topRight) / moduleSize); int tlblCentersDimension = round(ResultPoint.distance(topLeft, bottomLeft) / moduleSize); int dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) + 7; @@ -193,7 +207,7 @@ public class Detector { dimension--; break; case 3: - throw ReaderException.getInstance(); + throw NotFoundException.getNotFoundInstance(); } return dimension; } @@ -202,7 +216,9 @@ public class Detector { *

Computes an average estimated module size based on estimated derived from the positions * of the three finder patterns.

*/ - private float calculateModuleSize(ResultPoint topLeft, ResultPoint topRight, ResultPoint bottomLeft) { + protected float calculateModuleSize(ResultPoint topLeft, + ResultPoint topRight, + ResultPoint bottomLeft) { // Take the average return (calculateModuleSizeOneWay(topLeft, topRight) + calculateModuleSizeOneWay(topLeft, bottomLeft)) / 2.0f; @@ -223,10 +239,10 @@ public class Detector { (int) pattern.getX(), (int) pattern.getY()); if (Float.isNaN(moduleSizeEst1)) { - return moduleSizeEst2; + return moduleSizeEst2 / 7.0f; } if (Float.isNaN(moduleSizeEst2)) { - return moduleSizeEst1; + return moduleSizeEst1 / 7.0f; } // Average them, and divide by 7 since we've counted the width of 3 black modules, // and 1 white and 1 black module on either side. Ergo, divide sum by 14. @@ -240,26 +256,33 @@ public class Detector { */ private float sizeOfBlackWhiteBlackRunBothWays(int fromX, int fromY, int toX, int toY) { - float result = sizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY); - - // Now count other way -- don't run off image though of course - int otherToX = fromX - (toX - fromX); - if (otherToX < 0) { - // "to" should the be the first value not included, so, the first value off - // the edge is -1 - otherToX = -1; - } else if (otherToX >= image.getWidth()) { - otherToX = image.getWidth(); - } - int otherToY = fromY - (toY - fromY); - if (otherToY < 0) { - otherToY = -1; - } else if (otherToY >= image.getHeight()) { - otherToY = image.getHeight(); - } - result += sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY); - return result - 1.0f; // -1 because we counted the middle pixel twice - } + float result = sizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY); + + // Now count other way -- don't run off image though of course + float scale = 1.0f; + int otherToX = fromX - (toX - fromX); + if (otherToX < 0) { + scale = (float) fromX / (float) (fromX - otherToX); + otherToX = 0; + } else if (otherToX > image.getWidth()) { + scale = (float) (image.getWidth() - fromX) / (float) (otherToX - fromX); + otherToX = image.getWidth(); + } + int otherToY = (int) (fromY - (toY - fromY) * scale); + + scale = 1.0f; + if (otherToY < 0) { + scale = (float) fromY / (float) (fromY - otherToY); + otherToY = 0; + } else if (otherToY > image.getHeight()) { + scale = (float) (image.getHeight() - fromY) / (float) (otherToY - fromY); + otherToY = image.getHeight(); + } + otherToX = (int) (fromX + (otherToX - fromX) * scale); + + result += sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY); + return result; + } /** *

This method traces a line from a point in the image, in the direction towards another point. @@ -293,11 +316,11 @@ public class Detector { int realX = steep ? y : x; int realY = steep ? x : y; if (state == 1) { // In white pixels, looking for black - if (image.isBlack(realX, realY)) { + if (image.get(realX, realY)) { state++; } } else { - if (!image.isBlack(realX, realY)) { + if (!image.get(realX, realY)) { state++; } } @@ -305,10 +328,16 @@ public class Detector { if (state == 3) { // Found black, white, black, and stumbled back onto white; done int diffX = x - fromX; int diffY = y - fromY; + if (xstep < 0) { + diffX++; + } return (float) Math.sqrt((double) (diffX * diffX + diffY * diffY)); } error += dy; if (error > 0) { + if (y == toY) { + break; + } y += ystep; error -= dx; } @@ -325,26 +354,29 @@ public class Detector { * @param overallEstModuleSize estimated module size so far * @param estAlignmentX x coordinate of center of area probably containing alignment pattern * @param estAlignmentY y coordinate of above - * @param allowanceFactor number of pixels in all directons to search from the center + * @param allowanceFactor number of pixels in all directions to search from the center * @return {@link AlignmentPattern} if found, or null otherwise - * @throws ReaderException if an unexpected error occurs during detection + * @throws NotFoundException if an unexpected error occurs during detection */ - private AlignmentPattern findAlignmentInRegion(float overallEstModuleSize, - int estAlignmentX, - int estAlignmentY, - float allowanceFactor) - throws ReaderException { + protected AlignmentPattern findAlignmentInRegion(float overallEstModuleSize, + int estAlignmentX, + int estAlignmentY, + float allowanceFactor) + throws NotFoundException { // Look for an alignment pattern (3 modules in size) around where it // should be int allowance = (int) (allowanceFactor * overallEstModuleSize); int alignmentAreaLeftX = Math.max(0, estAlignmentX - allowance); int alignmentAreaRightX = Math.min(image.getWidth() - 1, estAlignmentX + allowance); if (alignmentAreaRightX - alignmentAreaLeftX < overallEstModuleSize * 3) { - throw ReaderException.getInstance(); + throw NotFoundException.getNotFoundInstance(); } int alignmentAreaTopY = Math.max(0, estAlignmentY - allowance); int alignmentAreaBottomY = Math.min(image.getHeight() - 1, estAlignmentY + allowance); + if (alignmentAreaBottomY - alignmentAreaTopY < overallEstModuleSize * 3) { + throw NotFoundException.getNotFoundInstance(); + } AlignmentPatternFinder alignmentFinder = new AlignmentPatternFinder( @@ -353,7 +385,8 @@ public class Detector { alignmentAreaTopY, alignmentAreaRightX - alignmentAreaLeftX, alignmentAreaBottomY - alignmentAreaTopY, - overallEstModuleSize); + overallEstModuleSize, + resultPointCallback); return alignmentFinder.find(); } @@ -364,5 +397,4 @@ public class Detector { private static int round(float d) { return (int) (d + 0.5f); } - }