From c8e2721f7d50f350186d0e2ad2d74ae7e7a5cd1e Mon Sep 17 00:00:00 2001 From: "smparkes@smparkes.net" Date: Tue, 30 Oct 2012 21:03:31 +0000 Subject: [PATCH] Bring C++ datamatrix to parity w/Java wrt to the blackbox test Plus a little whitespace cleanup and make resultpoint immutable. git-svn-id: https://zxing.googlecode.com/svn/trunk@2490 59b500cc-1b3d-0410-9834-0bbf25fbcc57 --- cpp/core/src/zxing/NotFoundException.cpp | 58 ++++--- cpp/core/src/zxing/NotFoundException.h | 67 +++---- cpp/core/src/zxing/ResultPoint.h | 4 +- .../zxing/datamatrix/detector/Detector.cpp | 164 ++++++++++-------- 4 files changed, 155 insertions(+), 138 deletions(-) diff --git a/cpp/core/src/zxing/NotFoundException.cpp b/cpp/core/src/zxing/NotFoundException.cpp index 985043a44..8adc51420 100644 --- a/cpp/core/src/zxing/NotFoundException.cpp +++ b/cpp/core/src/zxing/NotFoundException.cpp @@ -1,28 +1,30 @@ -// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- -/* - * Copyright 20011 ZXing authors - * - * 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 { - - NotFoundException::NotFoundException(const char *msg) - : ReaderException(msg) {} - - NotFoundException::~NotFoundException() throw() { - } - -} +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- +/* + * Copyright 20011 ZXing authors + * + * 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 { + + NotFoundException::NotFoundException() {} + + NotFoundException::NotFoundException(const char *msg) + : ReaderException(msg) {} + + NotFoundException::~NotFoundException() throw() { + } + +} diff --git a/cpp/core/src/zxing/NotFoundException.h b/cpp/core/src/zxing/NotFoundException.h index 407caa9a3..1ef9609ed 100644 --- a/cpp/core/src/zxing/NotFoundException.h +++ b/cpp/core/src/zxing/NotFoundException.h @@ -1,33 +1,34 @@ -// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- - -#ifndef __NOT_FOUND_EXCEPTION_H__ -#define __NOT_FOUND_EXCEPTION_H__ - -/* - * Copyright 20011 ZXing authors - * - * 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 { - - class NotFoundException : public ReaderException { - public: - NotFoundException(const char *msg); - ~NotFoundException() throw(); - }; - -} -#endif // __NOT_FOUND_EXCEPTION_H__ +// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*- + +#ifndef __NOT_FOUND_EXCEPTION_H__ +#define __NOT_FOUND_EXCEPTION_H__ + +/* + * Copyright 20011 ZXing authors + * + * 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 { + + class NotFoundException : public ReaderException { + public: + NotFoundException(); + NotFoundException(const char *msg); + ~NotFoundException() throw(); + }; + +} +#endif // __NOT_FOUND_EXCEPTION_H__ diff --git a/cpp/core/src/zxing/ResultPoint.h b/cpp/core/src/zxing/ResultPoint.h index ae48b8434..e4e08fa38 100644 --- a/cpp/core/src/zxing/ResultPoint.h +++ b/cpp/core/src/zxing/ResultPoint.h @@ -28,8 +28,8 @@ namespace zxing { class ResultPoint : public Counted { protected: - float posX_; - float posY_; + const float posX_; + const float posY_; public: ResultPoint(); diff --git a/cpp/core/src/zxing/datamatrix/detector/Detector.cpp b/cpp/core/src/zxing/datamatrix/detector/Detector.cpp index b8f2768bd..a53a31ce2 100644 --- a/cpp/core/src/zxing/datamatrix/detector/Detector.cpp +++ b/cpp/core/src/zxing/datamatrix/detector/Detector.cpp @@ -19,19 +19,33 @@ * limitations under the License. */ +#include #include #include #include #include +#include #include #include namespace math_utils = zxing::common::detector::math_utils; -namespace zxing { -namespace datamatrix { +using zxing::Ref; +using zxing::BitMatrix; +using zxing::ResultPoint; +using zxing::DetectorResult; +using zxing::PerspectiveTransform; +using zxing::NotFoundException; +using zxing::datamatrix::Detector; +using zxing::datamatrix::ResultPointsAndTransitions; -using namespace std; +namespace { + typedef std::map, int> PointMap; + void increment(PointMap& table, Ref const& key) { + int& value = table[key]; + value += 1; + } +} ResultPointsAndTransitions::ResultPointsAndTransitions() { Ref ref(new ResultPoint(0, 0)); @@ -41,8 +55,8 @@ ResultPointsAndTransitions::ResultPointsAndTransitions() { } ResultPointsAndTransitions::ResultPointsAndTransitions(Ref from, Ref to, - int transitions) - : to_(to), from_(from), transitions_(transitions) { + int transitions) + : to_(to), from_(from), transitions_(transitions) { } Ref ResultPointsAndTransitions::getFrom() { @@ -58,7 +72,7 @@ int ResultPointsAndTransitions::getTransitions() { } Detector::Detector(Ref image) - : image_(image) { + : image_(image) { } Ref Detector::getImage() { @@ -88,35 +102,37 @@ Ref Detector::detect() { Ref lSideOne(transitions[0]); Ref lSideTwo(transitions[1]); + // Figure out which point is their intersection by tallying up the number of times we see the + // endpoints in the four endpoints. One will show up twice. + typedef std::map, int> PointMap; + PointMap pointCount; + increment(pointCount, lSideOne->getFrom()); + increment(pointCount, lSideOne->getTo()); + increment(pointCount, lSideTwo->getFrom()); + increment(pointCount, lSideTwo->getTo()); + // Figure out which point is their intersection by tallying up the number of times we see the // endpoints in the four endpoints. One will show up twice. Ref maybeTopLeft; Ref bottomLeft; Ref maybeBottomRight; - if (lSideOne->getFrom()->equals(lSideOne->getTo())) { - bottomLeft = lSideOne->getFrom(); - maybeTopLeft = lSideTwo->getFrom(); - maybeBottomRight = lSideTwo->getTo(); - } else if (lSideOne->getFrom()->equals(lSideTwo->getFrom())) { - bottomLeft = lSideOne->getFrom(); - maybeTopLeft = lSideOne->getTo(); - maybeBottomRight = lSideTwo->getTo(); - } else if (lSideOne->getFrom()->equals(lSideTwo->getTo())) { - bottomLeft = lSideOne->getFrom(); - maybeTopLeft = lSideOne->getTo(); - maybeBottomRight = lSideTwo->getFrom(); - } else if (lSideOne->getTo()->equals(lSideTwo->getFrom())) { - bottomLeft = lSideOne->getTo(); - maybeTopLeft = lSideOne->getFrom(); - maybeBottomRight = lSideTwo->getTo(); - } else if (lSideOne->getTo()->equals(lSideTwo->getTo())) { - bottomLeft = lSideOne->getTo(); - maybeTopLeft = lSideOne->getFrom(); - maybeBottomRight = lSideTwo->getFrom(); - } else { - bottomLeft = lSideTwo->getFrom(); - maybeTopLeft = lSideOne->getTo(); - maybeBottomRight = lSideOne->getFrom(); + for (PointMap::const_iterator entry = pointCount.begin(), end = pointCount.end(); entry != end; ++entry) { + Ref const& point = entry->first; + int value = entry->second; + if (value == 2) { + bottomLeft = point; // this is definitely the bottom left, then -- end of two L sides + } else { + // Otherwise it's either top left or bottom right -- just assign the two arbitrarily now + if (maybeTopLeft == 0) { + maybeTopLeft = point; + } else { + maybeBottomRight = point; + } + } + } + + if (maybeTopLeft == 0 || bottomLeft == 0 || maybeBottomRight == 0) { + throw NotFoundException(); } // Bottom left is correct but top left and bottom right might be switched @@ -138,10 +154,10 @@ Ref Detector::detect() { if (!(pointA->equals(bottomRight) || pointA->equals(bottomLeft) || pointA->equals(topLeft))) { topRight = pointA; } else if (!(pointB->equals(bottomRight) || pointB->equals(bottomLeft) - || pointB->equals(topLeft))) { + || pointB->equals(topLeft))) { topRight = pointB; } else if (!(pointC->equals(bottomRight) || pointC->equals(bottomLeft) - || pointC->equals(topLeft))) { + || pointC->equals(topLeft))) { topRight = pointC; } else { topRight = pointD; @@ -184,7 +200,7 @@ Ref Detector::detect() { if (4 * dimensionTop >= 7 * dimensionRight || 4 * dimensionRight >= 7 * dimensionTop) { // The matrix is rectangular correctedTopRight = correctTopRightRectangular(bottomLeft, bottomRight, topLeft, topRight, - dimensionTop, dimensionRight); + dimensionTop, dimensionRight); if (correctedTopRight == NULL) { correctedTopRight = topRight; } @@ -203,7 +219,7 @@ Ref Detector::detect() { } transform = createTransform(topLeft, correctedTopRight, bottomLeft, bottomRight, dimensionTop, - dimensionRight); + dimensionRight); bits = sampleGrid(image_, dimensionTop, dimensionRight, transform); } else { @@ -217,15 +233,15 @@ Ref Detector::detect() { } // Redetermine the dimension using the corrected top right point - int dimensionCorrected = max(transitionsBetween(topLeft, correctedTopRight)->getTransitions(), - transitionsBetween(bottomRight, correctedTopRight)->getTransitions()); + int dimensionCorrected = std::max(transitionsBetween(topLeft, correctedTopRight)->getTransitions(), + transitionsBetween(bottomRight, correctedTopRight)->getTransitions()); dimensionCorrected++; if ((dimensionCorrected & 0x01) == 1) { dimensionCorrected++; } transform = createTransform(topLeft, correctedTopRight, bottomLeft, bottomRight, - dimensionCorrected, dimensionCorrected); + dimensionCorrected, dimensionCorrected); bits = sampleGrid(image_, dimensionCorrected, dimensionCorrected, transform); } @@ -243,8 +259,8 @@ Ref Detector::detect() { * for a rectangular matrix */ Ref Detector::correctTopRightRectangular(Ref bottomLeft, - Ref bottomRight, Ref topLeft, Ref topRight, - int dimensionTop, int dimensionRight) { + Ref bottomRight, Ref topLeft, Ref topRight, + int dimensionTop, int dimensionRight) { float corr = distance(bottomLeft, bottomRight) / (float) dimensionTop; int norm = distance(topLeft, topRight); @@ -252,7 +268,7 @@ Ref Detector::correctTopRightRectangular(Ref bottomLef float sin = (topRight->getY() - topLeft->getY()) / norm; Ref c1( - new ResultPoint(topRight->getX() + corr * cos, topRight->getY() + corr * sin)); + new ResultPoint(topRight->getX() + corr * cos, topRight->getY() + corr * sin)); corr = distance(bottomLeft, topLeft) / (float) dimensionRight; norm = distance(bottomRight, topRight); @@ -260,7 +276,7 @@ Ref Detector::correctTopRightRectangular(Ref bottomLef sin = (topRight->getY() - bottomRight->getY()) / norm; Ref c2( - new ResultPoint(topRight->getX() + corr * cos, topRight->getY() + corr * sin)); + new ResultPoint(topRight->getX() + corr * cos, topRight->getY() + corr * sin)); if (!isValid(c1)) { if (isValid(c2)) { @@ -273,9 +289,9 @@ Ref Detector::correctTopRightRectangular(Ref bottomLef } int l1 = abs(dimensionTop - transitionsBetween(topLeft, c1)->getTransitions()) - + abs(dimensionRight - transitionsBetween(bottomRight, c1)->getTransitions()); + + abs(dimensionRight - transitionsBetween(bottomRight, c1)->getTransitions()); int l2 = abs(dimensionTop - transitionsBetween(topLeft, c2)->getTransitions()) - + abs(dimensionRight - transitionsBetween(bottomRight, c2)->getTransitions()); + + abs(dimensionRight - transitionsBetween(bottomRight, c2)->getTransitions()); return l1 <= l2 ? c1 : c2; } @@ -285,8 +301,8 @@ Ref Detector::correctTopRightRectangular(Ref bottomLef * for a square matrix */ Ref Detector::correctTopRight(Ref bottomLeft, - Ref bottomRight, Ref topLeft, Ref topRight, - int dimension) { + Ref bottomRight, Ref topLeft, Ref topRight, + int dimension) { float corr = distance(bottomLeft, bottomRight) / (float) dimension; int norm = distance(topLeft, topRight); @@ -294,7 +310,7 @@ Ref Detector::correctTopRight(Ref bottomLeft, float sin = (topRight->getY() - topLeft->getY()) / norm; Ref c1( - new ResultPoint(topRight->getX() + corr * cos, topRight->getY() + corr * sin)); + new ResultPoint(topRight->getX() + corr * cos, topRight->getY() + corr * sin)); corr = distance(bottomLeft, topLeft) / (float) dimension; norm = distance(bottomRight, topRight); @@ -302,7 +318,7 @@ Ref Detector::correctTopRight(Ref bottomLeft, sin = (topRight->getY() - bottomRight->getY()) / norm; Ref c2( - new ResultPoint(topRight->getX() + corr * cos, topRight->getY() + corr * sin)); + new ResultPoint(topRight->getX() + corr * cos, topRight->getY() + corr * sin)); if (!isValid(c1)) { if (isValid(c2)) { @@ -315,18 +331,18 @@ Ref Detector::correctTopRight(Ref bottomLeft, } int l1 = abs( - transitionsBetween(topLeft, c1)->getTransitions() - - transitionsBetween(bottomRight, c1)->getTransitions()); + transitionsBetween(topLeft, c1)->getTransitions() + - transitionsBetween(bottomRight, c1)->getTransitions()); int l2 = abs( - transitionsBetween(topLeft, c2)->getTransitions() - - transitionsBetween(bottomRight, c2)->getTransitions()); + transitionsBetween(topLeft, c2)->getTransitions() + - transitionsBetween(bottomRight, c2)->getTransitions()); return l1 <= l2 ? c1 : c2; } bool Detector::isValid(Ref p) { return p->getX() >= 0 && p->getX() < image_->getWidth() && p->getY() > 0 - && p->getY() < image_->getHeight(); + && p->getY() < image_->getHeight(); } int Detector::distance(Ref a, Ref b) { @@ -334,7 +350,7 @@ int Detector::distance(Ref a, Ref b) { } Ref Detector::transitionsBetween(Ref from, - Ref to) { + Ref to) { // See QR Code Detector, sizeOfBlackWhiteBlackRun() int fromX = (int) from->getX(); int fromY = (int) from->getY(); @@ -377,32 +393,32 @@ Ref Detector::transitionsBetween(Ref fr } Ref Detector::createTransform(Ref topLeft, - Ref topRight, Ref bottomLeft, Ref bottomRight, - int dimensionX, int dimensionY) { + Ref topRight, Ref bottomLeft, Ref bottomRight, + int dimensionX, int dimensionY) { Ref transform( - PerspectiveTransform::quadrilateralToQuadrilateral( - 0.5f, - 0.5f, - dimensionX - 0.5f, - 0.5f, - dimensionX - 0.5f, - dimensionY - 0.5f, - 0.5f, - dimensionY - 0.5f, - topLeft->getX(), - topLeft->getY(), - topRight->getX(), - topRight->getY(), - bottomRight->getX(), - bottomRight->getY(), - bottomLeft->getX(), - bottomLeft->getY())); + PerspectiveTransform::quadrilateralToQuadrilateral( + 0.5f, + 0.5f, + dimensionX - 0.5f, + 0.5f, + dimensionX - 0.5f, + dimensionY - 0.5f, + 0.5f, + dimensionY - 0.5f, + topLeft->getX(), + topLeft->getY(), + topRight->getX(), + topRight->getY(), + bottomRight->getX(), + bottomRight->getY(), + bottomLeft->getX(), + bottomLeft->getY())); return transform; } Ref Detector::sampleGrid(Ref image, int dimensionX, int dimensionY, - Ref transform) { + Ref transform) { GridSampler &sampler = GridSampler::getInstance(); return sampler.sampleGrid(image, dimensionX, dimensionY, transform); } @@ -428,5 +444,3 @@ void Detector::insertionSort(std::vector > &vect int Detector::compare(Ref a, Ref b) { return a->getTransitions() - b->getTransitions(); } -} -}