mirror of
https://github.com/zxing/zxing.git
synced 2025-03-05 20:48:51 -08:00
Issue 497
git-svn-id: https://zxing.googlecode.com/svn/trunk@1515 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
0a5e8e9298
commit
438746649d
|
@ -43,7 +43,7 @@ namespace zxing {
|
||||||
cout << "(1) created detector " << &detector << "\n" << flush;
|
cout << "(1) created detector " << &detector << "\n" << flush;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Ref<DetectorResult> detectorResult(detector.detect());
|
Ref<DetectorResult> detectorResult(detector.detect(hints));
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
cout << "(2) detected, have detectorResult " << detectorResult.object_ << "\n" << flush;
|
cout << "(2) detected, have detectorResult " << detectorResult.object_ << "\n" << flush;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <zxing/qrcode/detector/AlignmentPatternFinder.h>
|
#include <zxing/qrcode/detector/AlignmentPatternFinder.h>
|
||||||
#include <zxing/qrcode/Version.h>
|
#include <zxing/qrcode/Version.h>
|
||||||
#include <zxing/common/GridSampler.h>
|
#include <zxing/common/GridSampler.h>
|
||||||
|
#include <zxing/DecodeHints.h>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
@ -42,9 +43,9 @@ Ref<BitMatrix> Detector::getImage() {
|
||||||
return image_;
|
return image_;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<DetectorResult> Detector::detect() {
|
Ref<DetectorResult> Detector::detect(DecodeHints const& hints) {
|
||||||
FinderPatternFinder finder(image_);
|
FinderPatternFinder finder(image_);
|
||||||
Ref<FinderPatternInfo> info(finder.find());
|
Ref<FinderPatternInfo> info(finder.find(hints));
|
||||||
|
|
||||||
Ref<FinderPattern> topLeft(info->getTopLeft());
|
Ref<FinderPattern> topLeft(info->getTopLeft());
|
||||||
Ref<FinderPattern> topRight(info->getTopRight());
|
Ref<FinderPattern> topRight(info->getTopRight());
|
||||||
|
@ -178,22 +179,28 @@ float Detector::sizeOfBlackWhiteBlackRunBothWays(int fromX, int fromY, int toX,
|
||||||
|
|
||||||
float result = sizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY);
|
float result = sizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY);
|
||||||
|
|
||||||
|
|
||||||
// Now count other way -- don't run off image though of course
|
// Now count other way -- don't run off image though of course
|
||||||
|
float scale = 1.0f;
|
||||||
int otherToX = fromX - (toX - fromX);
|
int otherToX = fromX - (toX - fromX);
|
||||||
if (otherToX < 0) {
|
if (otherToX < 0) {
|
||||||
// "to" should the be the first value not included, so, the first value off
|
scale = (float) fromX / (float) (fromX - otherToX);
|
||||||
// the edge is -1
|
otherToX = 0;
|
||||||
otherToX = -1;
|
|
||||||
} else if (otherToX >= (int)image_->getWidth()) {
|
} else if (otherToX >= (int)image_->getWidth()) {
|
||||||
otherToX = image_->getWidth();
|
scale = (float) (image_->getWidth() - 1 - fromX) / (float) (otherToX - fromX);
|
||||||
|
otherToX = image_->getWidth() - 1;
|
||||||
}
|
}
|
||||||
int otherToY = fromY - (toY - fromY);
|
int otherToY = (int) (fromY - (toY - fromY) * scale);
|
||||||
|
|
||||||
|
scale = 1.0f;
|
||||||
if (otherToY < 0) {
|
if (otherToY < 0) {
|
||||||
otherToY = -1;
|
scale = (float) fromY / (float) (fromY - otherToY);
|
||||||
|
otherToY = 0;
|
||||||
} else if (otherToY >= (int)image_->getHeight()) {
|
} else if (otherToY >= (int)image_->getHeight()) {
|
||||||
otherToY = 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);
|
result += sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY);
|
||||||
return result - 1.0f; // -1 because we counted the middle pixel twice
|
return result - 1.0f; // -1 because we counted the middle pixel twice
|
||||||
}
|
}
|
||||||
|
@ -254,6 +261,9 @@ Ref<AlignmentPattern> Detector::findAlignmentInRegion(float overallEstModuleSize
|
||||||
int allowance = (int)(allowanceFactor * overallEstModuleSize);
|
int allowance = (int)(allowanceFactor * overallEstModuleSize);
|
||||||
int alignmentAreaLeftX = max(0, estAlignmentX - allowance);
|
int alignmentAreaLeftX = max(0, estAlignmentX - allowance);
|
||||||
int alignmentAreaRightX = min((int)(image_->getWidth() - 1), 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 alignmentAreaTopY = max(0, estAlignmentY - allowance);
|
||||||
int alignmentAreaBottomY = min((int)(image_->getHeight() - 1), estAlignmentY + allowance);
|
int alignmentAreaBottomY = min((int)(image_->getHeight() - 1), estAlignmentY + allowance);
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,9 @@
|
||||||
#include <zxing/common/PerspectiveTransform.h>
|
#include <zxing/common/PerspectiveTransform.h>
|
||||||
|
|
||||||
namespace zxing {
|
namespace zxing {
|
||||||
|
|
||||||
|
class DecodeHints;
|
||||||
|
|
||||||
namespace qrcode {
|
namespace qrcode {
|
||||||
|
|
||||||
class Detector : public Counted {
|
class Detector : public Counted {
|
||||||
|
@ -51,7 +54,7 @@ public:
|
||||||
ResultPoint > bottomLeft, Ref<ResultPoint> alignmentPattern, int dimension);
|
ResultPoint > bottomLeft, Ref<ResultPoint> alignmentPattern, int dimension);
|
||||||
|
|
||||||
Detector(Ref<BitMatrix> image);
|
Detector(Ref<BitMatrix> image);
|
||||||
Ref<DetectorResult> detect();
|
Ref<DetectorResult> detect(DecodeHints const& hints);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include <zxing/qrcode/detector/FinderPatternFinder.h>
|
#include <zxing/qrcode/detector/FinderPatternFinder.h>
|
||||||
#include <zxing/ReaderException.h>
|
#include <zxing/ReaderException.h>
|
||||||
|
#include <zxing/DecodeHints.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
@ -49,7 +50,8 @@ public:
|
||||||
class CenterComparator {
|
class CenterComparator {
|
||||||
public:
|
public:
|
||||||
bool operator()(Ref<FinderPattern> a, Ref<FinderPattern> b) {
|
bool operator()(Ref<FinderPattern> a, Ref<FinderPattern> b) {
|
||||||
return a->getCount() < b->getCount();
|
// N.B.: we want the result in descending order ...
|
||||||
|
return a->getCount() > b->getCount();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -260,7 +262,7 @@ int FinderPatternFinder::findRowSkip() {
|
||||||
// This is the case where you find top left first. Draw it out.
|
// This is the case where you find top left first. Draw it out.
|
||||||
hasSkipped_ = true;
|
hasSkipped_ = true;
|
||||||
return (int)(abs(firstConfirmedCenter->getX() - center->getX()) - abs(firstConfirmedCenter->getY()
|
return (int)(abs(firstConfirmedCenter->getX() - center->getX()) - abs(firstConfirmedCenter->getY()
|
||||||
- center->getY()));
|
- center->getY()))/2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -284,51 +286,48 @@ bool FinderPatternFinder::haveMultiplyConfirmedCenters() {
|
||||||
// OK, we have at least 3 confirmed centers, but, it's possible that one is a "false positive"
|
// OK, we have at least 3 confirmed centers, but, it's possible that one is a "false positive"
|
||||||
// and that we need to keep looking. We detect this by asking if the estimated module sizes
|
// and that we need to keep looking. We detect this by asking if the estimated module sizes
|
||||||
// vary too much. We arbitrarily say that when the total deviation from average exceeds
|
// vary too much. We arbitrarily say that when the total deviation from average exceeds
|
||||||
// 15% of the total module size estimates, it's too much.
|
// 5% of the total module size estimates, it's too much.
|
||||||
float average = totalModuleSize / max;
|
float average = totalModuleSize / max;
|
||||||
float totalDeviation = 0.0f;
|
float totalDeviation = 0.0f;
|
||||||
for (size_t i = 0; i < max; i++) {
|
for (size_t i = 0; i < max; i++) {
|
||||||
Ref<FinderPattern> pattern = possibleCenters_[i];
|
Ref<FinderPattern> pattern = possibleCenters_[i];
|
||||||
totalDeviation += abs(pattern->getEstimatedModuleSize() - average);
|
totalDeviation += abs(pattern->getEstimatedModuleSize() - average);
|
||||||
}
|
}
|
||||||
return totalDeviation <= 0.15f * totalModuleSize;
|
return totalDeviation <= 0.05f * totalModuleSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<Ref<FinderPattern> > FinderPatternFinder::selectBestPatterns() {
|
vector<Ref<FinderPattern> > FinderPatternFinder::selectBestPatterns() {
|
||||||
sort(possibleCenters_.begin(), possibleCenters_.end(), CenterComparator());
|
size_t startSize = possibleCenters_.size();
|
||||||
size_t size = 0;
|
|
||||||
size_t max = possibleCenters_.size();
|
|
||||||
while (size < max) {
|
|
||||||
if (possibleCenters_[size]->getCount() < CENTER_QUORUM) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
size++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size < 3) {
|
if (startSize < 3) {
|
||||||
// Couldn't find enough finder patterns
|
// Couldn't find enough finder patterns
|
||||||
throw zxing::ReaderException("Could not find three finder patterns");
|
throw zxing::ReaderException("Could not find three finder patterns");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size == 3) {
|
// Filter outlier possibilities whose module size is too different
|
||||||
// Found just enough -- hope these are good!
|
if (startSize > 3) {
|
||||||
vector<Ref<FinderPattern> > result(3);
|
// But we can only afford to do so if we have at least 4 possibilities to choose from
|
||||||
result[0] = possibleCenters_[0];
|
float totalModuleSize = 0.0f;
|
||||||
result[1] = possibleCenters_[1];
|
for (size_t i = 0; i < startSize; i++) {
|
||||||
result[2] = possibleCenters_[2];
|
totalModuleSize += possibleCenters_[i]->getEstimatedModuleSize();
|
||||||
return result;
|
}
|
||||||
|
float average = totalModuleSize / (float) startSize;
|
||||||
|
for (size_t i = 0; i < possibleCenters_.size() && possibleCenters_.size() > 3; i++) {
|
||||||
|
if (abs(possibleCenters_[i]->getEstimatedModuleSize() - average) > 0.2f * average) {
|
||||||
|
possibleCenters_.erase(possibleCenters_.begin()+i);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hmm, multiple found. We need to pick the best three. Find the most
|
if (possibleCenters_.size() > 3) {
|
||||||
// popular ones whose module size is nearest the average
|
// Throw away all but those first size candidate points we found.
|
||||||
// This does not work for multiple qr codes in the same image
|
sort(possibleCenters_.begin(), possibleCenters_.end(), CenterComparator());
|
||||||
float averageModuleSize = 0.0f;
|
|
||||||
for (size_t i = 0; i < size; i++) {
|
|
||||||
averageModuleSize += possibleCenters_[i]->getEstimatedModuleSize();
|
|
||||||
}
|
}
|
||||||
averageModuleSize /= (float)size;
|
|
||||||
|
|
||||||
sort(possibleCenters_.begin(), possibleCenters_.end(), ClosestToAverageComparator(averageModuleSize));
|
if (possibleCenters_.size() > 3) {
|
||||||
|
possibleCenters_.erase(possibleCenters_.begin()+3,possibleCenters_.end());
|
||||||
|
}
|
||||||
|
|
||||||
vector<Ref<FinderPattern> > result(3);
|
vector<Ref<FinderPattern> > result(3);
|
||||||
result[0] = possibleCenters_[0];
|
result[0] = possibleCenters_[0];
|
||||||
|
@ -389,7 +388,9 @@ FinderPatternFinder::FinderPatternFinder(Ref<BitMatrix> image) :
|
||||||
image_(image), possibleCenters_(), hasSkipped_(false) {
|
image_(image), possibleCenters_(), hasSkipped_(false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<FinderPatternInfo> FinderPatternFinder::find() {
|
Ref<FinderPatternInfo> FinderPatternFinder::find(DecodeHints const& hints) {
|
||||||
|
bool tryHarder = hints.getTryHarder();
|
||||||
|
|
||||||
size_t maxI = image_->getHeight();
|
size_t maxI = image_->getHeight();
|
||||||
size_t maxJ = image_->getWidth();
|
size_t maxJ = image_->getWidth();
|
||||||
|
|
||||||
|
@ -407,7 +408,10 @@ Ref<FinderPatternInfo> FinderPatternFinder::find() {
|
||||||
// modules in size. This gives the smallest number of pixels the center
|
// modules in size. This gives the smallest number of pixels the center
|
||||||
// could be, so skip this often. When trying harder, look for all
|
// could be, so skip this often. When trying harder, look for all
|
||||||
// QR versions regardless of how dense they are.
|
// QR versions regardless of how dense they are.
|
||||||
size_t iSkip = MIN_SKIP;
|
int iSkip = (3 * maxI) / (4 * MAX_MODULES);
|
||||||
|
if (iSkip < MIN_SKIP || tryHarder) {
|
||||||
|
iSkip = MIN_SKIP;
|
||||||
|
}
|
||||||
|
|
||||||
// This is slightly faster than using the Ref. Efficiency is important here
|
// This is slightly faster than using the Ref. Efficiency is important here
|
||||||
BitMatrix& matrix = *image_;
|
BitMatrix& matrix = *image_;
|
||||||
|
@ -434,7 +438,9 @@ Ref<FinderPatternInfo> FinderPatternFinder::find() {
|
||||||
if (foundPatternCross(stateCount)) { // Yes
|
if (foundPatternCross(stateCount)) { // Yes
|
||||||
bool confirmed = handlePossibleCenter(stateCount, i, j);
|
bool confirmed = handlePossibleCenter(stateCount, i, j);
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
iSkip = 1; // Go back to examining each line
|
// Start examining every other line. Checking each line turned out to be too
|
||||||
|
// expensive and didn't improve performance.
|
||||||
|
iSkip = 2;
|
||||||
if (hasSkipped_) {
|
if (hasSkipped_) {
|
||||||
done = haveMultiplyConfirmedCenters();
|
done = haveMultiplyConfirmedCenters();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -27,6 +27,9 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace zxing {
|
namespace zxing {
|
||||||
|
|
||||||
|
class DecodeHints;
|
||||||
|
|
||||||
namespace qrcode {
|
namespace qrcode {
|
||||||
|
|
||||||
class FinderPatternFinder {
|
class FinderPatternFinder {
|
||||||
|
@ -56,7 +59,7 @@ private:
|
||||||
public:
|
public:
|
||||||
static float distance(Ref<ResultPoint> p1, Ref<ResultPoint> p2);
|
static float distance(Ref<ResultPoint> p1, Ref<ResultPoint> p2);
|
||||||
FinderPatternFinder(Ref<BitMatrix> image);
|
FinderPatternFinder(Ref<BitMatrix> image);
|
||||||
Ref<FinderPatternInfo> find();
|
Ref<FinderPatternInfo> find(DecodeHints const& hints);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue