diff --git a/cpp/core/src/zxing/common/DecoderResult.cpp b/cpp/core/src/zxing/common/DecoderResult.cpp index a28ce7c77..86b11f810 100644 --- a/cpp/core/src/zxing/common/DecoderResult.cpp +++ b/cpp/core/src/zxing/common/DecoderResult.cpp @@ -1,37 +1,37 @@ -/* - * DecoderResult.cpp - * zxing - * - * Created by Christian Brunschen on 20/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 - -namespace zxing { - -DecoderResult::DecoderResult(ArrayRef rawBytes, Ref text) : - rawBytes_(rawBytes), text_(text) { -} - -ArrayRef DecoderResult::getRawBytes() { - return rawBytes_; -} - -Ref DecoderResult::getText() { - return text_; -} - -} \ No newline at end of file +/* + * DecoderResult.cpp + * zxing + * + * Created by Christian Brunschen on 20/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 + +namespace zxing { + +DecoderResult::DecoderResult(ArrayRef rawBytes, Ref text) : + rawBytes_(rawBytes), text_(text) { +} + +ArrayRef DecoderResult::getRawBytes() { + return rawBytes_; +} + +Ref DecoderResult::getText() { + return text_; +} + +} diff --git a/cpp/core/src/zxing/qrcode/detector/Detector.cpp b/cpp/core/src/zxing/qrcode/detector/Detector.cpp index 1fa16f66d..9dbc29754 100644 --- a/cpp/core/src/zxing/qrcode/detector/Detector.cpp +++ b/cpp/core/src/zxing/qrcode/detector/Detector.cpp @@ -1,261 +1,265 @@ -/* - * 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 - -namespace zxing { -namespace qrcode { - -using namespace std; - -Detector::Detector(Ref image) : - image_(image) { -} - -Ref Detector::detect() { - FinderPatternFinder finder(image_); - Ref info(finder.find()); - - Ref topLeft(info->getTopLeft()); - Ref topRight(info->getTopRight()); - Ref bottomLeft(info->getBottomLeft()); - - float moduleSize = calculateModuleSize(topLeft, topRight, bottomLeft); - 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 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, transform)); - 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 = sourceBottomRightY = dimMinusThree - 3.0f; - } 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 = 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 = lround(FinderPatternFinder::distance(topLeft, topRight) / moduleSize); - int tlblCentersDimension = lround(FinderPatternFinder::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 - 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 >= (int)image_->getWidth()) { - otherToX = image_->getWidth(); - } - int otherToY = fromY - (toY - fromY); - if (otherToY < 0) { - otherToY = -1; - } else if (otherToY >= (int)image_->getHeight()) { - otherToY = image_->getHeight(); - } - result += sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY); - return result - 1.0f; // -1 because we counted the middle pixel twice -} - -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 ystep = fromY < toY ? 1 : -1; - int xstep = fromX < toX ? 1 : -1; - int state = 0; // In black pixels, looking for white, first or second time - for (int x = fromX, y = fromY; x != toX; x += xstep) { - - int realX = steep ? y : x; - int realY = steep ? x : y; - 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 - int diffX = x - fromX; - int diffY = y - fromY; - return (float)sqrt((double)(diffX * diffX + diffY * diffY)); - } - error += dy; - if (error > 0) { - y += ystep; - error -= dx; - } - } - int diffX = toX - fromX; - int diffY = toY - fromY; - return (float)sqrt((double)(diffX * diffX + diffY * diffY)); -} - -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); - int alignmentAreaTopY = max(0, estAlignmentY - allowance); - int alignmentAreaBottomY = min((int)(image_->getHeight() - 1), estAlignmentY + allowance); - - AlignmentPatternFinder alignmentFinder(image_, alignmentAreaLeftX, alignmentAreaTopY, alignmentAreaRightX - - alignmentAreaLeftX, alignmentAreaBottomY - alignmentAreaTopY, overallEstModuleSize); - return alignmentFinder.find(); -} - -} -} +/* + * 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 + +namespace zxing { +namespace qrcode { + +using namespace std; + +Detector::Detector(Ref image) : + image_(image) { +} + +Ref Detector::getImage() { + return image_; +} + +Ref Detector::detect() { + FinderPatternFinder finder(image_); + Ref info(finder.find()); + + Ref topLeft(info->getTopLeft()); + Ref topRight(info->getTopRight()); + Ref bottomLeft(info->getBottomLeft()); + + float moduleSize = calculateModuleSize(topLeft, topRight, bottomLeft); + 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 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, transform)); + 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 = sourceBottomRightY = dimMinusThree - 3.0f; + } 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 = 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 = lround(FinderPatternFinder::distance(topLeft, topRight) / moduleSize); + int tlblCentersDimension = lround(FinderPatternFinder::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 + 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 >= (int)image_->getWidth()) { + otherToX = image_->getWidth(); + } + int otherToY = fromY - (toY - fromY); + if (otherToY < 0) { + otherToY = -1; + } else if (otherToY >= (int)image_->getHeight()) { + otherToY = image_->getHeight(); + } + result += sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY); + return result - 1.0f; // -1 because we counted the middle pixel twice +} + +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 ystep = fromY < toY ? 1 : -1; + int xstep = fromX < toX ? 1 : -1; + int state = 0; // In black pixels, looking for white, first or second time + for (int x = fromX, y = fromY; x != toX; x += xstep) { + + int realX = steep ? y : x; + int realY = steep ? x : y; + 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 + int diffX = x - fromX; + int diffY = y - fromY; + return (float)sqrt((double)(diffX * diffX + diffY * diffY)); + } + error += dy; + if (error > 0) { + y += ystep; + error -= dx; + } + } + int diffX = toX - fromX; + int diffY = toY - fromY; + return (float)sqrt((double)(diffX * diffX + diffY * diffY)); +} + +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); + int alignmentAreaTopY = max(0, estAlignmentY - allowance); + int alignmentAreaBottomY = min((int)(image_->getHeight() - 1), estAlignmentY + allowance); + + AlignmentPatternFinder alignmentFinder(image_, alignmentAreaLeftX, alignmentAreaTopY, alignmentAreaRightX + - alignmentAreaLeftX, alignmentAreaBottomY - alignmentAreaTopY, overallEstModuleSize); + return alignmentFinder.find(); +} + +} +} diff --git a/cpp/core/src/zxing/qrcode/detector/Detector.h b/cpp/core/src/zxing/qrcode/detector/Detector.h index aa3703ed3..98eed51e9 100644 --- a/cpp/core/src/zxing/qrcode/detector/Detector.h +++ b/cpp/core/src/zxing/qrcode/detector/Detector.h @@ -1,58 +1,60 @@ -#ifndef __DETECTOR_H__ -#define __DETECTOR_H__ - -/* - * Detector.h - * 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 - -namespace zxing { -namespace qrcode { - -class Detector : public Counted { -protected: - Ref image_; - - - 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); -public: - - virtual Ref createTransform(Ref topLeft, Ref topRight, Ref < - ResultPoint > bottomLeft, Ref alignmentPattern, int dimension); - - Detector(Ref image); - Ref detect(); -}; -} -} - -#endif // __DETECTOR_H__ +#ifndef __DETECTOR_H__ +#define __DETECTOR_H__ + +/* + * Detector.h + * 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 + +namespace zxing { +namespace qrcode { + +class Detector : public Counted { +private: + Ref image_; + +protected: + Ref getImage(); + + 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); +public: + + virtual Ref createTransform(Ref topLeft, Ref topRight, Ref < + ResultPoint > bottomLeft, Ref alignmentPattern, int dimension); + + Detector(Ref image); + Ref detect(); +}; +} +} + +#endif // __DETECTOR_H__ diff --git a/cpp/core/src/zxing/qrcode/detector/QREdgeDetector.cpp b/cpp/core/src/zxing/qrcode/detector/QREdgeDetector.cpp index 739a739af..18affe6e1 100644 --- a/cpp/core/src/zxing/qrcode/detector/QREdgeDetector.cpp +++ b/cpp/core/src/zxing/qrcode/detector/QREdgeDetector.cpp @@ -1,168 +1,168 @@ -/* - * QREdgeDetector.cpp - * zxing - * - * 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 - -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(*image_.object_, 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) { - 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) { - float fromX = from.x; - float fromY = from.y; - float toX = to.x; - float toY = 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 = from.x; - int realY = from.y; - 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 +/* + * QREdgeDetector.cpp + * zxing + * + * 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 + +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) { + 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