diff --git a/cpp/core/src/zxing/qrcode/detector/Detector.cpp b/cpp/core/src/zxing/qrcode/detector/Detector.cpp index e872c3a05..2ba6846de 100644 --- a/cpp/core/src/zxing/qrcode/detector/Detector.cpp +++ b/cpp/core/src/zxing/qrcode/detector/Detector.cpp @@ -1,304 +1,304 @@ -// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- -/* - * Detector.cpp - * zxing - * - * Created by Christian Brunschen on 14/05/2008. - * Copyright 2008 ZXing authors All rights reserved. - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace math_utils = zxing::common::detector::math_utils; - -namespace zxing { -namespace qrcode { - -using namespace std; - -Detector::Detector(Ref image) : - image_(image) { -} - -Ref Detector::getImage() const { - return image_; -} - -Ref Detector::getResultPointCallback() const { - return callback_; -} - -Ref Detector::detect(DecodeHints const& hints) { - callback_ = hints.getResultPointCallback(); - FinderPatternFinder finder(image_, hints.getResultPointCallback()); - Ref info(finder.find(hints)); - return processFinderPatternInfo(info); -} - -Ref Detector::processFinderPatternInfo(Ref info){ - Ref topLeft(info->getTopLeft()); - Ref topRight(info->getTopRight()); - Ref bottomLeft(info->getBottomLeft()); - - float moduleSize = calculateModuleSize(topLeft, topRight, bottomLeft); - if (moduleSize < 1.0f) { - throw zxing::ReaderException("bad module size"); - } - int dimension = computeDimension(topLeft, topRight, bottomLeft, moduleSize); - Version *provisionalVersion = Version::getProvisionalVersionForDimension(dimension); - int modulesBetweenFPCenters = provisionalVersion->getDimensionForVersion() - 7; - - Ref alignmentPattern; - // Anything above version 1 has an alignment pattern - if (provisionalVersion->getAlignmentPatternCenters().size() > 0) { - - - // Guess where a "bottom right" finder pattern would have been - float bottomRightX = topRight->getX() - topLeft->getX() + bottomLeft->getX(); - float bottomRightY = topRight->getY() - topLeft->getY() + bottomLeft->getY(); - - - // Estimate that alignment pattern is closer by 3 modules - // from "bottom right" to known top left location - float correctionToTopLeft = 1.0f - 3.0f / (float)modulesBetweenFPCenters; - int estAlignmentX = (int)(topLeft->getX() + correctionToTopLeft * (bottomRightX - topLeft->getX())); - int estAlignmentY = (int)(topLeft->getY() + correctionToTopLeft * (bottomRightY - topLeft->getY())); - - - // Kind of arbitrary -- expand search radius before giving up - for (int i = 4; i <= 16; i <<= 1) { - try { - alignmentPattern = findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, (float)i); - break; - } catch (zxing::ReaderException const& re) { - // try next round - } - } - if (alignmentPattern == 0) { - // Try anyway - } - - } - - Ref transform = createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension); - Ref bits(sampleGrid(image_, dimension, transform)); - std::vector > points(alignmentPattern == 0 ? 3 : 4); - points[0].reset(bottomLeft); - points[1].reset(topLeft); - points[2].reset(topRight); - if (alignmentPattern != 0) { - points[3].reset(alignmentPattern); - } - - Ref result(new DetectorResult(bits, points)); - return result; -} - -Ref Detector::createTransform(Ref topLeft, Ref topRight, Ref < - ResultPoint > bottomLeft, Ref alignmentPattern, int dimension) { - - float dimMinusThree = (float)dimension - 3.5f; - float bottomRightX; - float bottomRightY; - float sourceBottomRightX; - float sourceBottomRightY; - if (alignmentPattern != 0) { - bottomRightX = alignmentPattern->getX(); - bottomRightY = alignmentPattern->getY(); - sourceBottomRightX = dimMinusThree - 3.0f; - sourceBottomRightY = sourceBottomRightX; - } else { - // Don't have an alignment pattern, just make up the bottom-right point - bottomRightX = (topRight->getX() - topLeft->getX()) + bottomLeft->getX(); - bottomRightY = (topRight->getY() - topLeft->getY()) + bottomLeft->getY(); - sourceBottomRightX = dimMinusThree; - sourceBottomRightY = dimMinusThree; - } - - Ref transform(PerspectiveTransform::quadrilateralToQuadrilateral(3.5f, 3.5f, dimMinusThree, 3.5f, sourceBottomRightX, - sourceBottomRightY, 3.5f, dimMinusThree, topLeft->getX(), topLeft->getY(), topRight->getX(), - topRight->getY(), bottomRightX, bottomRightY, bottomLeft->getX(), bottomLeft->getY())); - - return transform; -} - -Ref Detector::sampleGrid(Ref image, int dimension, Ref transform) { - GridSampler &sampler = GridSampler::getInstance(); - return sampler.sampleGrid(image, dimension, transform); -} - -int Detector::computeDimension(Ref topLeft, Ref topRight, Ref bottomLeft, - float moduleSize) { - int tltrCentersDimension = - math_utils::round(ResultPoint::distance(topLeft, topRight) / moduleSize); - int tlblCentersDimension = - math_utils::round(ResultPoint::distance(topLeft, bottomLeft) / moduleSize); - int dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) + 7; - switch (dimension & 0x03) { // mod 4 - case 0: - dimension++; - break; - // 1? do nothing - case 2: - dimension--; - break; - case 3: - ostringstream s; - s << "Bad dimension: " << dimension; - throw zxing::ReaderException(s.str().c_str()); - } - return dimension; -} - -float Detector::calculateModuleSize(Ref topLeft, Ref topRight, Ref bottomLeft) { - // Take the average - return (calculateModuleSizeOneWay(topLeft, topRight) + calculateModuleSizeOneWay(topLeft, bottomLeft)) / 2.0f; -} - -float Detector::calculateModuleSizeOneWay(Ref pattern, Ref otherPattern) { - float moduleSizeEst1 = sizeOfBlackWhiteBlackRunBothWays((int)pattern->getX(), (int)pattern->getY(), - (int)otherPattern->getX(), (int)otherPattern->getY()); - float moduleSizeEst2 = sizeOfBlackWhiteBlackRunBothWays((int)otherPattern->getX(), (int)otherPattern->getY(), - (int)pattern->getX(), (int)pattern->getY()); - if (isnan(moduleSizeEst1)) { - return moduleSizeEst2; - } - if (isnan(moduleSizeEst2)) { - return moduleSizeEst1; - } - // 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. - return (moduleSizeEst1 + moduleSizeEst2) / 14.0f; -} - -float Detector::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 - float scale = 1.0f; - int otherToX = fromX - (toX - fromX); - if (otherToX < 0) { - scale = (float) fromX / (float) (fromX - otherToX); - otherToX = 0; - } else if (otherToX >= (int)image_->getWidth()) { - scale = (float) (image_->getWidth() - 1 - fromX) / (float) (otherToX - fromX); - otherToX = image_->getWidth() - 1; - } - int otherToY = (int) (fromY - (toY - fromY) * scale); - - scale = 1.0f; - if (otherToY < 0) { - scale = (float) fromY / (float) (fromY - otherToY); - otherToY = 0; - } else if (otherToY >= (int)image_->getHeight()) { - scale = (float) (image_->getHeight() - 1 - fromY) / (float) (otherToY - fromY); - otherToY = image_->getHeight() - 1; - } - otherToX = (int) (fromX + (otherToX - fromX) * scale); - - result += sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY); - - // Middle pixel is double-counted this way; subtract 1 - return result - 1.0f; -} - -float Detector::sizeOfBlackWhiteBlackRun(int fromX, int fromY, int toX, int toY) { - // Mild variant of Bresenham's algorithm; - // see http://en.wikipedia.org/wiki/Bresenham's_line_algorithm - bool steep = abs(toY - fromY) > abs(toX - fromX); - if (steep) { - int temp = fromX; - fromX = fromY; - fromY = temp; - temp = toX; - toX = toY; - toY = temp; - } - - int dx = abs(toX - fromX); - int dy = abs(toY - fromY); - int error = -dx >> 1; - int xstep = fromX < toX ? 1 : -1; - int ystep = fromY < toY ? 1 : -1; - - // In black pixels, looking for white, first or second time. - int state = 0; - // Loop up until x == toX, but not beyond - int xLimit = toX + xstep; - for (int x = fromX, y = fromY; x != xLimit; x += xstep) { - int realX = steep ? y : x; - int realY = steep ? x : y; - - // Does current pixel mean we have moved white to black or vice versa? - if (!((state == 1) ^ image_->get(realX, realY))) { - if (state == 2) { - return math_utils::distance(x, y, fromX, fromY); - } - state++; - } - - error += dy; - if (error > 0) { - if (y == toY) { - break; - } - y += ystep; - error -= dx; - } - } - // Found black-white-black; give the benefit of the doubt that the next pixel outside the image - // is "white" so this last point at (toX+xStep,toY) is the right ending. This is really a - // small approximation; (toX+xStep,toY+yStep) might be really correct. Ignore this. - if (state == 2) { - return math_utils::distance(toX + xstep, toY, fromX, fromY); - } - // else we didn't find even black-white-black; no estimate is really possible - return NAN; -} - -Ref Detector::findAlignmentInRegion(float overallEstModuleSize, int estAlignmentX, int estAlignmentY, - float allowanceFactor) { - // Look for an alignment pattern (3 modules in size) around where it - // should be - int allowance = (int)(allowanceFactor * overallEstModuleSize); - int alignmentAreaLeftX = max(0, estAlignmentX - allowance); - int alignmentAreaRightX = min((int)(image_->getWidth() - 1), estAlignmentX + allowance); - if (alignmentAreaRightX - alignmentAreaLeftX < overallEstModuleSize * 3) { - throw zxing::ReaderException("region too small to hold alignment pattern"); - } - int alignmentAreaTopY = max(0, estAlignmentY - allowance); - int alignmentAreaBottomY = min((int)(image_->getHeight() - 1), estAlignmentY + allowance); - if (alignmentAreaBottomY - alignmentAreaTopY < overallEstModuleSize * 3) { - throw zxing::ReaderException("region too small to hold alignment pattern"); - } - - AlignmentPatternFinder alignmentFinder(image_, alignmentAreaLeftX, alignmentAreaTopY, alignmentAreaRightX - - alignmentAreaLeftX, alignmentAreaBottomY - alignmentAreaTopY, overallEstModuleSize, callback_); - return alignmentFinder.find(); -} - -} -} +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * Detector.cpp + * zxing + * + * Created by Christian Brunschen on 14/05/2008. + * Copyright 2008 ZXing authors All rights reserved. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace math_utils = zxing::common::detector::math_utils; + +namespace zxing { +namespace qrcode { + +using namespace std; + +Detector::Detector(Ref image) : + image_(image) { +} + +Ref Detector::getImage() const { + return image_; +} + +Ref Detector::getResultPointCallback() const { + return callback_; +} + +Ref Detector::detect(DecodeHints const& hints) { + callback_ = hints.getResultPointCallback(); + FinderPatternFinder finder(image_, hints.getResultPointCallback()); + Ref info(finder.find(hints)); + return processFinderPatternInfo(info); +} + +Ref Detector::processFinderPatternInfo(Ref info){ + Ref topLeft(info->getTopLeft()); + Ref topRight(info->getTopRight()); + Ref bottomLeft(info->getBottomLeft()); + + float moduleSize = calculateModuleSize(topLeft, topRight, bottomLeft); + if (moduleSize < 1.0f) { + throw zxing::ReaderException("bad module size"); + } + int dimension = computeDimension(topLeft, topRight, bottomLeft, moduleSize); + Version *provisionalVersion = Version::getProvisionalVersionForDimension(dimension); + int modulesBetweenFPCenters = provisionalVersion->getDimensionForVersion() - 7; + + Ref alignmentPattern; + // Anything above version 1 has an alignment pattern + if (provisionalVersion->getAlignmentPatternCenters().size() > 0) { + + + // Guess where a "bottom right" finder pattern would have been + float bottomRightX = topRight->getX() - topLeft->getX() + bottomLeft->getX(); + float bottomRightY = topRight->getY() - topLeft->getY() + bottomLeft->getY(); + + + // Estimate that alignment pattern is closer by 3 modules + // from "bottom right" to known top left location + float correctionToTopLeft = 1.0f - 3.0f / (float)modulesBetweenFPCenters; + int estAlignmentX = (int)(topLeft->getX() + correctionToTopLeft * (bottomRightX - topLeft->getX())); + int estAlignmentY = (int)(topLeft->getY() + correctionToTopLeft * (bottomRightY - topLeft->getY())); + + + // Kind of arbitrary -- expand search radius before giving up + for (int i = 4; i <= 16; i <<= 1) { + try { + alignmentPattern = findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, (float)i); + break; + } catch (zxing::ReaderException const& re) { + // try next round + } + } + if (alignmentPattern == 0) { + // Try anyway + } + + } + + Ref transform = createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension); + Ref bits(sampleGrid(image_, dimension, transform)); + std::vector > points(alignmentPattern == 0 ? 3 : 4); + points[0].reset(bottomLeft); + points[1].reset(topLeft); + points[2].reset(topRight); + if (alignmentPattern != 0) { + points[3].reset(alignmentPattern); + } + + Ref result(new DetectorResult(bits, points)); + return result; +} + +Ref Detector::createTransform(Ref topLeft, Ref topRight, Ref < + ResultPoint > bottomLeft, Ref alignmentPattern, int dimension) { + + float dimMinusThree = (float)dimension - 3.5f; + float bottomRightX; + float bottomRightY; + float sourceBottomRightX; + float sourceBottomRightY; + if (alignmentPattern != 0) { + bottomRightX = alignmentPattern->getX(); + bottomRightY = alignmentPattern->getY(); + sourceBottomRightX = dimMinusThree - 3.0f; + sourceBottomRightY = sourceBottomRightX; + } else { + // Don't have an alignment pattern, just make up the bottom-right point + bottomRightX = (topRight->getX() - topLeft->getX()) + bottomLeft->getX(); + bottomRightY = (topRight->getY() - topLeft->getY()) + bottomLeft->getY(); + sourceBottomRightX = dimMinusThree; + sourceBottomRightY = dimMinusThree; + } + + Ref transform(PerspectiveTransform::quadrilateralToQuadrilateral(3.5f, 3.5f, dimMinusThree, 3.5f, sourceBottomRightX, + sourceBottomRightY, 3.5f, dimMinusThree, topLeft->getX(), topLeft->getY(), topRight->getX(), + topRight->getY(), bottomRightX, bottomRightY, bottomLeft->getX(), bottomLeft->getY())); + + return transform; +} + +Ref Detector::sampleGrid(Ref image, int dimension, Ref transform) { + GridSampler &sampler = GridSampler::getInstance(); + return sampler.sampleGrid(image, dimension, transform); +} + +int Detector::computeDimension(Ref topLeft, Ref topRight, Ref bottomLeft, + float moduleSize) { + int tltrCentersDimension = + math_utils::round(ResultPoint::distance(topLeft, topRight) / moduleSize); + int tlblCentersDimension = + math_utils::round(ResultPoint::distance(topLeft, bottomLeft) / moduleSize); + int dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) + 7; + switch (dimension & 0x03) { // mod 4 + case 0: + dimension++; + break; + // 1? do nothing + case 2: + dimension--; + break; + case 3: + ostringstream s; + s << "Bad dimension: " << dimension; + throw zxing::ReaderException(s.str().c_str()); + } + return dimension; +} + +float Detector::calculateModuleSize(Ref topLeft, Ref topRight, Ref bottomLeft) { + // Take the average + return (calculateModuleSizeOneWay(topLeft, topRight) + calculateModuleSizeOneWay(topLeft, bottomLeft)) / 2.0f; +} + +float Detector::calculateModuleSizeOneWay(Ref pattern, Ref otherPattern) { + float moduleSizeEst1 = sizeOfBlackWhiteBlackRunBothWays((int)pattern->getX(), (int)pattern->getY(), + (int)otherPattern->getX(), (int)otherPattern->getY()); + float moduleSizeEst2 = sizeOfBlackWhiteBlackRunBothWays((int)otherPattern->getX(), (int)otherPattern->getY(), + (int)pattern->getX(), (int)pattern->getY()); + if (isnan(moduleSizeEst1)) { + return moduleSizeEst2; + } + if (isnan(moduleSizeEst2)) { + return moduleSizeEst1; + } + // 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. + return (moduleSizeEst1 + moduleSizeEst2) / 14.0f; +} + +float Detector::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 + float scale = 1.0f; + int otherToX = fromX - (toX - fromX); + if (otherToX < 0) { + scale = (float) fromX / (float) (fromX - otherToX); + otherToX = 0; + } else if (otherToX >= (int)image_->getWidth()) { + scale = (float) (image_->getWidth() - 1 - fromX) / (float) (otherToX - fromX); + otherToX = image_->getWidth() - 1; + } + int otherToY = (int) (fromY - (toY - fromY) * scale); + + scale = 1.0f; + if (otherToY < 0) { + scale = (float) fromY / (float) (fromY - otherToY); + otherToY = 0; + } else if (otherToY >= (int)image_->getHeight()) { + scale = (float) (image_->getHeight() - 1 - fromY) / (float) (otherToY - fromY); + otherToY = image_->getHeight() - 1; + } + otherToX = (int) (fromX + (otherToX - fromX) * scale); + + result += sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY); + + // Middle pixel is double-counted this way; subtract 1 + return result - 1.0f; +} + +float Detector::sizeOfBlackWhiteBlackRun(int fromX, int fromY, int toX, int toY) { + // Mild variant of Bresenham's algorithm; + // see http://en.wikipedia.org/wiki/Bresenham's_line_algorithm + bool steep = abs(toY - fromY) > abs(toX - fromX); + if (steep) { + int temp = fromX; + fromX = fromY; + fromY = temp; + temp = toX; + toX = toY; + toY = temp; + } + + int dx = abs(toX - fromX); + int dy = abs(toY - fromY); + int error = -dx >> 1; + int xstep = fromX < toX ? 1 : -1; + int ystep = fromY < toY ? 1 : -1; + + // In black pixels, looking for white, first or second time. + int state = 0; + // Loop up until x == toX, but not beyond + int xLimit = toX + xstep; + for (int x = fromX, y = fromY; x != xLimit; x += xstep) { + int realX = steep ? y : x; + int realY = steep ? x : y; + + // Does current pixel mean we have moved white to black or vice versa? + if (!((state == 1) ^ image_->get(realX, realY))) { + if (state == 2) { + return math_utils::distance(x, y, fromX, fromY); + } + state++; + } + + error += dy; + if (error > 0) { + if (y == toY) { + break; + } + y += ystep; + error -= dx; + } + } + // Found black-white-black; give the benefit of the doubt that the next pixel outside the image + // is "white" so this last point at (toX+xStep,toY) is the right ending. This is really a + // small approximation; (toX+xStep,toY+yStep) might be really correct. Ignore this. + if (state == 2) { + return math_utils::distance(toX + xstep, toY, fromX, fromY); + } + // else we didn't find even black-white-black; no estimate is really possible + return NAN; +} + +Ref Detector::findAlignmentInRegion(float overallEstModuleSize, int estAlignmentX, int estAlignmentY, + float allowanceFactor) { + // Look for an alignment pattern (3 modules in size) around where it + // should be + int allowance = (int)(allowanceFactor * overallEstModuleSize); + int alignmentAreaLeftX = max(0, estAlignmentX - allowance); + int alignmentAreaRightX = min((int)(image_->getWidth() - 1), estAlignmentX + allowance); + if (alignmentAreaRightX - alignmentAreaLeftX < overallEstModuleSize * 3) { + throw zxing::ReaderException("region too small to hold alignment pattern"); + } + int alignmentAreaTopY = max(0, estAlignmentY - allowance); + int alignmentAreaBottomY = min((int)(image_->getHeight() - 1), estAlignmentY + allowance); + if (alignmentAreaBottomY - alignmentAreaTopY < overallEstModuleSize * 3) { + throw zxing::ReaderException("region too small to hold alignment pattern"); + } + + AlignmentPatternFinder alignmentFinder(image_, alignmentAreaLeftX, alignmentAreaTopY, alignmentAreaRightX + - alignmentAreaLeftX, alignmentAreaBottomY - alignmentAreaTopY, overallEstModuleSize, callback_); + return alignmentFinder.find(); +} + +} +} diff --git a/cpp/core/src/zxing/qrcode/detector/Detector.h b/cpp/core/src/zxing/qrcode/detector/Detector.h index 383d5c250..05ef04456 100644 --- a/cpp/core/src/zxing/qrcode/detector/Detector.h +++ b/cpp/core/src/zxing/qrcode/detector/Detector.h @@ -1,69 +1,69 @@ -// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- -#ifndef __DETECTOR_H__ -#define __DETECTOR_H__ - -/* - * Detector.h - * zxing - * - * Copyright 2010 ZXing authors All rights reserved. - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include - -namespace zxing { - -class DecodeHints; - -namespace qrcode { - -class Detector : public Counted { -private: - Ref image_; - Ref callback_; - -protected: - Ref getImage() const; - Ref getResultPointCallback() const; - - static Ref sampleGrid(Ref image, int dimension, Ref); - static int computeDimension(Ref topLeft, Ref topRight, Ref bottomLeft, - float moduleSize); - float calculateModuleSize(Ref topLeft, Ref topRight, Ref bottomLeft); - float calculateModuleSizeOneWay(Ref pattern, Ref otherPattern); - float sizeOfBlackWhiteBlackRunBothWays(int fromX, int fromY, int toX, int toY); - float sizeOfBlackWhiteBlackRun(int fromX, int fromY, int toX, int toY); - Ref findAlignmentInRegion(float overallEstModuleSize, int estAlignmentX, int estAlignmentY, - float allowanceFactor); - Ref processFinderPatternInfo(Ref info); -public: - virtual Ref createTransform(Ref topLeft, Ref topRight, Ref < - ResultPoint > bottomLeft, Ref alignmentPattern, int dimension); - - Detector(Ref image); - Ref detect(DecodeHints const& hints); - - -}; -} -} - -#endif // __DETECTOR_H__ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +#ifndef __DETECTOR_H__ +#define __DETECTOR_H__ + +/* + * Detector.h + * zxing + * + * Copyright 2010 ZXing authors All rights reserved. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +namespace zxing { + +class DecodeHints; + +namespace qrcode { + +class Detector : public Counted { +private: + Ref image_; + Ref callback_; + +protected: + Ref getImage() const; + Ref getResultPointCallback() const; + + static Ref sampleGrid(Ref image, int dimension, Ref); + static int computeDimension(Ref topLeft, Ref topRight, Ref bottomLeft, + float moduleSize); + float calculateModuleSize(Ref topLeft, Ref topRight, Ref bottomLeft); + float calculateModuleSizeOneWay(Ref pattern, Ref otherPattern); + float sizeOfBlackWhiteBlackRunBothWays(int fromX, int fromY, int toX, int toY); + float sizeOfBlackWhiteBlackRun(int fromX, int fromY, int toX, int toY); + Ref findAlignmentInRegion(float overallEstModuleSize, int estAlignmentX, int estAlignmentY, + float allowanceFactor); + Ref processFinderPatternInfo(Ref info); +public: + virtual Ref createTransform(Ref topLeft, Ref topRight, Ref < + ResultPoint > bottomLeft, Ref alignmentPattern, int dimension); + + Detector(Ref image); + Ref detect(DecodeHints const& hints); + + +}; +} +} + +#endif // __DETECTOR_H__ diff --git a/cpp/core/src/zxing/qrcode/detector/QREdgeDetector.cpp b/cpp/core/src/zxing/qrcode/detector/QREdgeDetector.cpp index 211f5daf0..c24a072bf 100644 --- a/cpp/core/src/zxing/qrcode/detector/QREdgeDetector.cpp +++ b/cpp/core/src/zxing/qrcode/detector/QREdgeDetector.cpp @@ -1,168 +1,168 @@ -// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- -/* - * Created by Ralf Kistner on 7/12/2009. - * Copyright 2008 ZXing authors All rights reserved. - * - * 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. - */ - -#include -#include -#include - -using namespace std; - -namespace zxing { -namespace qrcode { - -static const float patternEdgeThreshold = 2; -static const int patternEdgeWidth = 3; -static const float patternEdgeSearchRatio = 1.1; -static const int patternEdgeSkip = 2; - -static const float accurateEdgeThreshold = 3.3; -static const int accurateEdgeWidth = 7; -static const int accurateEdgeSkip = 2; - -static Point guessLastPattern(Point topLeft, Point topRight, Point bottomLeft) { - return Point(topRight.x - topLeft.x + bottomLeft.x, topRight.y - topLeft.y + bottomLeft.y); -} - -static Point rp(Ref rp) { - return Point(rp->getX(), rp->getY()); -} - -QREdgeDetector::QREdgeDetector(Ref image) : Detector(image) { } - -Ref QREdgeDetector::createTransform(Ref topLeft, Ref topRight, Ref < - ResultPoint > bottomLeft, Ref alignmentPattern, int dimension) { - - if(alignmentPattern == NULL) { - Point corner = findCorner(*Detector::getImage(), rp(topLeft), rp(topRight), rp(bottomLeft), dimension); - return get1CornerTransform(rp(topLeft), rp(topRight), rp(bottomLeft), corner, dimension); - } else { - return Detector::createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension); - } -} - - - - -Point QREdgeDetector::findCorner(const BitMatrix& image, Point topLeft, Point topRight, Point bottomLeft, int dimension) { - (void)dimension; - Point bottomRight = guessLastPattern(topLeft, topRight, bottomLeft); - - Line bottomEst = findPatternEdge(image, bottomLeft, topLeft, bottomRight, false); - Line rightEst = findPatternEdge(image, topRight, topLeft, bottomRight, true); - - //return EdgeDetector::intersection(bottomEst, rightEst); - - Line bottom = EdgeDetector::findLine(image, bottomEst, false, accurateEdgeWidth, accurateEdgeThreshold, accurateEdgeSkip); - Line right = EdgeDetector::findLine(image, rightEst, true, accurateEdgeWidth, accurateEdgeThreshold, accurateEdgeSkip); - - - return EdgeDetector::intersection(bottom, right); -} - -Line QREdgeDetector::findPatternEdge(const BitMatrix& image, Point pattern, Point opposite, Point direction, bool invert) { - Point start = endOfReverseBlackWhiteBlackRun(image, pattern, opposite); - - float dx = pattern.x - start.x; - float dy = pattern.y - start.y; - float dist = sqrt(dx*dx + dy*dy); - - float dirX = direction.x - pattern.x; - float dirY = direction.y - pattern.y; - float dirSize = sqrt(dirX*dirX + dirY*dirY); - - float nx = dirX/dirSize; - float ny = dirY/dirSize; - - float search = dist * patternEdgeSearchRatio; - Point a(start.x + nx*search, start.y + ny*search); - Point b(start.x - nx*search, start.y - ny*search); - - return EdgeDetector::findLine(image, Line(a, b), invert, patternEdgeWidth, patternEdgeThreshold, patternEdgeSkip); -} - - -Ref QREdgeDetector::get1CornerTransform(Point topLeft, Point topRight, Point bottomLeft, Point corner, int dimension) { - float dimMinusThree = (float) dimension - 3.5f; - - Ref transform(PerspectiveTransform::quadrilateralToQuadrilateral(3.5f, 3.5f, dimMinusThree, 3.5f, dimension, - dimension, 3.5f, dimMinusThree, topLeft.x, topLeft.y, topRight.x, - topRight.y, corner.x, corner.y, bottomLeft.x, bottomLeft.y)); - - return transform; -} - -// Adapted from "sizeOfBlackWhiteBlackRun" in zxing::qrcode::Detector -Point QREdgeDetector::endOfReverseBlackWhiteBlackRun(const BitMatrix& image, Point from, Point to) { - int fromX = (int)from.x; - int fromY = (int)from.y; - int toX = (int)to.x; - int toY = (int)to.y; - - bool steep = abs(toY - fromY) > abs(toX - fromX); - if (steep) { - int temp = fromX; - fromX = fromY; - fromY = temp; - temp = toX; - toX = toY; - toY = temp; - } - - int dx = abs(toX - fromX); - int dy = abs(toY - fromY); - int error = -dx >> 1; - int ystep = fromY < toY ? -1 : 1; - int xstep = fromX < toX ? -1 : 1; - int state = 0; // In black pixels, looking for white, first or second time - - // In case there are no points, prepopulate to from - int realX = fromX; - int realY = fromY; - for (int x = fromX, y = fromY; x != toX; x += xstep) { - realX = steep ? y : x; - realY = steep ? x : y; - - if(realX < 0 || realY < 0 || realX >= (int)image.getWidth() || realY >= (int)image.getHeight()) - break; - - if (state == 1) { // In white pixels, looking for black - if (image.get(realX, realY)) { - state++; - } - } else { - if (!image.get(realX, realY)) { - state++; - } - } - - if (state == 3) { // Found black, white, black, and stumbled back onto white; done - return Point(realX, realY); - } - error += dy; - if (error > 0) { - y += ystep; - error -= dx; - } - } - - // B-W-B run not found, return the last point visited. - return Point(realX, realY); -} - -} // namespace qrcode -} // namespace zxing +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * Created by Ralf Kistner on 7/12/2009. + * Copyright 2008 ZXing authors All rights reserved. + * + * 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. + */ + +#include +#include +#include + +using namespace std; + +namespace zxing { +namespace qrcode { + +static const float patternEdgeThreshold = 2; +static const int patternEdgeWidth = 3; +static const float patternEdgeSearchRatio = 1.1; +static const int patternEdgeSkip = 2; + +static const float accurateEdgeThreshold = 3.3; +static const int accurateEdgeWidth = 7; +static const int accurateEdgeSkip = 2; + +static Point guessLastPattern(Point topLeft, Point topRight, Point bottomLeft) { + return Point(topRight.x - topLeft.x + bottomLeft.x, topRight.y - topLeft.y + bottomLeft.y); +} + +static Point rp(Ref rp) { + return Point(rp->getX(), rp->getY()); +} + +QREdgeDetector::QREdgeDetector(Ref image) : Detector(image) { } + +Ref QREdgeDetector::createTransform(Ref topLeft, Ref topRight, Ref < + ResultPoint > bottomLeft, Ref alignmentPattern, int dimension) { + + if(alignmentPattern == NULL) { + Point corner = findCorner(*Detector::getImage(), rp(topLeft), rp(topRight), rp(bottomLeft), dimension); + return get1CornerTransform(rp(topLeft), rp(topRight), rp(bottomLeft), corner, dimension); + } else { + return Detector::createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension); + } +} + + + + +Point QREdgeDetector::findCorner(const BitMatrix& image, Point topLeft, Point topRight, Point bottomLeft, int dimension) { + (void)dimension; + Point bottomRight = guessLastPattern(topLeft, topRight, bottomLeft); + + Line bottomEst = findPatternEdge(image, bottomLeft, topLeft, bottomRight, false); + Line rightEst = findPatternEdge(image, topRight, topLeft, bottomRight, true); + + //return EdgeDetector::intersection(bottomEst, rightEst); + + Line bottom = EdgeDetector::findLine(image, bottomEst, false, accurateEdgeWidth, accurateEdgeThreshold, accurateEdgeSkip); + Line right = EdgeDetector::findLine(image, rightEst, true, accurateEdgeWidth, accurateEdgeThreshold, accurateEdgeSkip); + + + return EdgeDetector::intersection(bottom, right); +} + +Line QREdgeDetector::findPatternEdge(const BitMatrix& image, Point pattern, Point opposite, Point direction, bool invert) { + Point start = endOfReverseBlackWhiteBlackRun(image, pattern, opposite); + + float dx = pattern.x - start.x; + float dy = pattern.y - start.y; + float dist = sqrt(dx*dx + dy*dy); + + float dirX = direction.x - pattern.x; + float dirY = direction.y - pattern.y; + float dirSize = sqrt(dirX*dirX + dirY*dirY); + + float nx = dirX/dirSize; + float ny = dirY/dirSize; + + float search = dist * patternEdgeSearchRatio; + Point a(start.x + nx*search, start.y + ny*search); + Point b(start.x - nx*search, start.y - ny*search); + + return EdgeDetector::findLine(image, Line(a, b), invert, patternEdgeWidth, patternEdgeThreshold, patternEdgeSkip); +} + + +Ref QREdgeDetector::get1CornerTransform(Point topLeft, Point topRight, Point bottomLeft, Point corner, int dimension) { + float dimMinusThree = (float) dimension - 3.5f; + + Ref transform(PerspectiveTransform::quadrilateralToQuadrilateral(3.5f, 3.5f, dimMinusThree, 3.5f, dimension, + dimension, 3.5f, dimMinusThree, topLeft.x, topLeft.y, topRight.x, + topRight.y, corner.x, corner.y, bottomLeft.x, bottomLeft.y)); + + return transform; +} + +// Adapted from "sizeOfBlackWhiteBlackRun" in zxing::qrcode::Detector +Point QREdgeDetector::endOfReverseBlackWhiteBlackRun(const BitMatrix& image, Point from, Point to) { + int fromX = (int)from.x; + int fromY = (int)from.y; + int toX = (int)to.x; + int toY = (int)to.y; + + bool steep = abs(toY - fromY) > abs(toX - fromX); + if (steep) { + int temp = fromX; + fromX = fromY; + fromY = temp; + temp = toX; + toX = toY; + toY = temp; + } + + int dx = abs(toX - fromX); + int dy = abs(toY - fromY); + int error = -dx >> 1; + int ystep = fromY < toY ? -1 : 1; + int xstep = fromX < toX ? -1 : 1; + int state = 0; // In black pixels, looking for white, first or second time + + // In case there are no points, prepopulate to from + int realX = fromX; + int realY = fromY; + for (int x = fromX, y = fromY; x != toX; x += xstep) { + realX = steep ? y : x; + realY = steep ? x : y; + + if(realX < 0 || realY < 0 || realX >= (int)image.getWidth() || realY >= (int)image.getHeight()) + break; + + if (state == 1) { // In white pixels, looking for black + if (image.get(realX, realY)) { + state++; + } + } else { + if (!image.get(realX, realY)) { + state++; + } + } + + if (state == 3) { // Found black, white, black, and stumbled back onto white; done + return Point(realX, realY); + } + error += dy; + if (error > 0) { + y += ystep; + error -= dx; + } + } + + // B-W-B run not found, return the last point visited. + return Point(realX, realY); +} + +} // namespace qrcode +} // namespace zxing diff --git a/cpp/core/src/zxing/qrcode/detector/QREdgeDetector.h b/cpp/core/src/zxing/qrcode/detector/QREdgeDetector.h index 898a6df59..d2f3fe162 100644 --- a/cpp/core/src/zxing/qrcode/detector/QREdgeDetector.h +++ b/cpp/core/src/zxing/qrcode/detector/QREdgeDetector.h @@ -1,5 +1,5 @@ -#ifndef __QREDGEDETECTOR_H__ -#define __QREDGEDETECTOR_H__ +#ifndef __QREDGEDETECTOR_H__ +#define __QREDGEDETECTOR_H__ /* * QREdgeDetector.h * zxing @@ -19,7 +19,7 @@ * limitations under the License. */ - + #include #include @@ -44,5 +44,5 @@ private: }; } -} -#endif // QREDGEDETECTOR_H_ +} +#endif // QREDGEDETECTOR_H_