mirror of
https://github.com/zxing/zxing.git
synced 2025-03-05 20:48:51 -08:00
Port multi reader from Java. Closes Issue 1027.
I tweaked things a little, small formatting (to help me diff) and made some of the protection levels match the Java code. Nothing semantic. Great work. Thanks! git-svn-id: https://zxing.googlecode.com/svn/trunk@1986 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
0e6aad1092
commit
709f7f060a
|
@ -1,3 +1,5 @@
|
|||
# -*- python -*-
|
||||
|
||||
Decider('MD5')
|
||||
|
||||
vars = Variables()
|
||||
|
@ -20,7 +22,7 @@ if env['PIC']:
|
|||
compile_options['CXXFLAGS'] = ' '.join(flags)
|
||||
compile_options['LINKFLAGS'] = "-ldl"
|
||||
|
||||
def all_files(dir, ext='.cpp', level=5):
|
||||
def all_files(dir, ext='.cpp', level=6):
|
||||
files = []
|
||||
for i in range(1, level):
|
||||
files += Glob(dir + ('/*' * i) + ext)
|
||||
|
|
|
@ -22,6 +22,18 @@
|
|||
|
||||
namespace zxing {
|
||||
|
||||
ResultPoint::ResultPoint() : posX_(0), posY_(0) {}
|
||||
|
||||
ResultPoint::ResultPoint(float x, float y) : posX_(x), posY_(y) {}
|
||||
|
||||
ResultPoint::~ResultPoint() {}
|
||||
|
||||
float ResultPoint::getX() const {
|
||||
return posX_;
|
||||
}
|
||||
|
||||
float ResultPoint::getY() const {
|
||||
return posY_;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
|
||||
#ifndef __RESULT_POINT_H__
|
||||
#define __RESULT_POINT_H__
|
||||
|
||||
|
@ -26,12 +27,16 @@ namespace zxing {
|
|||
|
||||
class ResultPoint : public Counted {
|
||||
protected:
|
||||
ResultPoint() {}
|
||||
float posX_;
|
||||
float posY_;
|
||||
|
||||
public:
|
||||
ResultPoint();
|
||||
ResultPoint(float x, float y);
|
||||
virtual ~ResultPoint();
|
||||
|
||||
virtual float getX() const = 0;
|
||||
virtual float getY() const = 0;
|
||||
virtual float getX() const;
|
||||
virtual float getY() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -27,15 +27,7 @@ namespace zxing {
|
|||
using namespace std;
|
||||
|
||||
CornerPoint::CornerPoint(float posX, float posY) :
|
||||
posX_(posX), posY_(posY), counter_(0) {
|
||||
}
|
||||
|
||||
float CornerPoint::getX() const {
|
||||
return posX_;
|
||||
}
|
||||
|
||||
float CornerPoint::getY() const {
|
||||
return posY_;
|
||||
ResultPoint(posX,posY), counter_(0) {
|
||||
}
|
||||
|
||||
int CornerPoint::getCount() const {
|
||||
|
|
|
@ -29,14 +29,10 @@ namespace zxing {
|
|||
|
||||
class CornerPoint : public ResultPoint {
|
||||
private:
|
||||
float posX_;
|
||||
float posY_;
|
||||
int counter_;
|
||||
|
||||
public:
|
||||
CornerPoint(float posX, float posY);
|
||||
float getX() const;
|
||||
float getY() const;
|
||||
int getCount() const;
|
||||
void incrementCount();
|
||||
bool equals(Ref<CornerPoint> other) const;
|
||||
|
|
71
cpp/core/src/zxing/multi/ByQuadrantReader.cpp
Normal file
71
cpp/core/src/zxing/multi/ByQuadrantReader.cpp
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright 2011 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 <zxing/multi/ByQuadrantReader.h>
|
||||
#include <zxing/ReaderException.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace multi {
|
||||
|
||||
ByQuadrantReader::ByQuadrantReader(Reader& delegate) : delegate_(delegate) {}
|
||||
|
||||
ByQuadrantReader::~ByQuadrantReader(){}
|
||||
|
||||
Ref<Result> ByQuadrantReader::decode(Ref<BinaryBitmap> image){
|
||||
return decode(image, DecodeHints::DEFAULT_HINT);
|
||||
}
|
||||
|
||||
Ref<Result> ByQuadrantReader::decode(Ref<BinaryBitmap> image, DecodeHints hints){
|
||||
int width = image->getWidth();
|
||||
int height = image->getHeight();
|
||||
int halfWidth = width / 2;
|
||||
int halfHeight = height / 2;
|
||||
Ref<BinaryBitmap> topLeft = image->crop(0, 0, halfWidth, halfHeight);
|
||||
try {
|
||||
return delegate_.decode(topLeft, hints);
|
||||
} catch (ReaderException re) {
|
||||
// continue
|
||||
}
|
||||
|
||||
Ref<BinaryBitmap> topRight = image->crop(halfWidth, 0, halfWidth, halfHeight);
|
||||
try {
|
||||
return delegate_.decode(topRight, hints);
|
||||
} catch (ReaderException re) {
|
||||
// continue
|
||||
}
|
||||
|
||||
Ref<BinaryBitmap> bottomLeft = image->crop(0, halfHeight, halfWidth, halfHeight);
|
||||
try {
|
||||
return delegate_.decode(bottomLeft, hints);
|
||||
} catch (ReaderException re) {
|
||||
// continue
|
||||
}
|
||||
|
||||
Ref<BinaryBitmap> bottomRight = image->crop(halfWidth, halfHeight, halfWidth, halfHeight);
|
||||
try {
|
||||
return delegate_.decode(bottomRight, hints);
|
||||
} catch (ReaderException re) {
|
||||
// continue
|
||||
}
|
||||
|
||||
int quarterWidth = halfWidth / 2;
|
||||
int quarterHeight = halfHeight / 2;
|
||||
Ref<BinaryBitmap> center = image->crop(quarterWidth, quarterHeight, halfWidth, halfHeight);
|
||||
return delegate_.decode(center, hints);
|
||||
}
|
||||
|
||||
} // End zxing::multi namespace
|
||||
} // End zxing namespace
|
40
cpp/core/src/zxing/multi/ByQuadrantReader.h
Normal file
40
cpp/core/src/zxing/multi/ByQuadrantReader.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
#ifndef __BY_QUADRANT_READER_H__
|
||||
#define __BY_QUADRANT_READER_H__
|
||||
|
||||
/*
|
||||
* Copyright 2011 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 <zxing/Reader.h>
|
||||
#include <zxing/BinaryBitmap.h>
|
||||
#include <zxing/Result.h>
|
||||
#include <zxing/DecodeHints.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace multi {
|
||||
class ByQuadrantReader : public Reader {
|
||||
private:
|
||||
Reader& delegate_;
|
||||
|
||||
public:
|
||||
ByQuadrantReader(Reader& delegate);
|
||||
virtual ~ByQuadrantReader();
|
||||
virtual Ref<Result> decode(Ref<BinaryBitmap> image);
|
||||
virtual Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints);
|
||||
};
|
||||
} // End zxing::multi namespace
|
||||
} // End zxing namespace
|
||||
|
||||
#endif // __BY_QUADRANT_READER_H__
|
128
cpp/core/src/zxing/multi/GenericMultipleBarcodeReader.cpp
Normal file
128
cpp/core/src/zxing/multi/GenericMultipleBarcodeReader.cpp
Normal file
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright 2011 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 <zxing/multi/GenericMultipleBarcodeReader.h>
|
||||
#include <zxing/ReaderException.h>
|
||||
#include <zxing/ResultPoint.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace multi {
|
||||
GenericMultipleBarcodeReader::GenericMultipleBarcodeReader(Reader& delegate) :
|
||||
delegate_(delegate)
|
||||
{
|
||||
}
|
||||
|
||||
GenericMultipleBarcodeReader::~GenericMultipleBarcodeReader(){}
|
||||
|
||||
std::vector<Ref<Result> > GenericMultipleBarcodeReader::decodeMultiple(
|
||||
Ref<BinaryBitmap> image, DecodeHints hints)
|
||||
{
|
||||
std::vector<Ref<Result> > results;
|
||||
doDecodeMultiple(image, hints, results, 0, 0);
|
||||
if (results.empty()){
|
||||
throw ReaderException("No code detected");
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
void GenericMultipleBarcodeReader::doDecodeMultiple(Ref<BinaryBitmap> image,
|
||||
DecodeHints hints, std::vector<Ref<Result> >& results, int xOffset, int yOffset)
|
||||
{
|
||||
Ref<Result> result;
|
||||
try {
|
||||
result = delegate_.decode(image, hints);
|
||||
} catch (ReaderException re) {
|
||||
return;
|
||||
}
|
||||
bool alreadyFound = false;
|
||||
for (unsigned int i = 0; i < results.size(); i++) {
|
||||
Ref<Result> existingResult = results[i];
|
||||
if (existingResult->getText()->getText() == result->getText()->getText()) {
|
||||
alreadyFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (alreadyFound) {
|
||||
return;
|
||||
}
|
||||
|
||||
results.push_back(translateResultPoints(result, xOffset, yOffset));
|
||||
const std::vector<Ref<ResultPoint> > resultPoints = result->getResultPoints();
|
||||
if (resultPoints.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int width = image->getWidth();
|
||||
int height = image->getHeight();
|
||||
float minX = width;
|
||||
float minY = height;
|
||||
float maxX = 0.0f;
|
||||
float maxY = 0.0f;
|
||||
for (unsigned int i = 0; i < resultPoints.size(); i++) {
|
||||
Ref<ResultPoint> point = resultPoints[i];
|
||||
float x = point->getX();
|
||||
float y = point->getY();
|
||||
if (x < minX) {
|
||||
minX = x;
|
||||
}
|
||||
if (y < minY) {
|
||||
minY = y;
|
||||
}
|
||||
if (x > maxX) {
|
||||
maxX = x;
|
||||
}
|
||||
if (y > maxY) {
|
||||
maxY = y;
|
||||
}
|
||||
}
|
||||
|
||||
// Decode left of barcode
|
||||
if (minX > MIN_DIMENSION_TO_RECUR) {
|
||||
doDecodeMultiple(image->crop(0, 0, (int) minX, height),
|
||||
hints, results, xOffset, yOffset);
|
||||
}
|
||||
// Decode above barcode
|
||||
if (minY > MIN_DIMENSION_TO_RECUR) {
|
||||
doDecodeMultiple(image->crop(0, 0, width, (int) minY),
|
||||
hints, results, xOffset, yOffset);
|
||||
}
|
||||
// Decode right of barcode
|
||||
if (maxX < width - MIN_DIMENSION_TO_RECUR) {
|
||||
doDecodeMultiple(image->crop((int) maxX, 0, width - (int) maxX, height),
|
||||
hints, results, xOffset + (int) maxX, yOffset);
|
||||
}
|
||||
// Decode below barcode
|
||||
if (maxY < height - MIN_DIMENSION_TO_RECUR) {
|
||||
doDecodeMultiple(image->crop(0, (int) maxY, width, height - (int) maxY),
|
||||
hints, results, xOffset, yOffset + (int) maxY);
|
||||
}
|
||||
}
|
||||
|
||||
Ref<Result> GenericMultipleBarcodeReader::translateResultPoints(Ref<Result> result, int xOffset, int yOffset){
|
||||
const std::vector<Ref<ResultPoint> > oldResultPoints = result->getResultPoints();
|
||||
if (oldResultPoints.empty()) {
|
||||
return result;
|
||||
}
|
||||
std::vector<Ref<ResultPoint> > newResultPoints;
|
||||
for (unsigned int i = 0; i < oldResultPoints.size(); i++) {
|
||||
Ref<ResultPoint> oldPoint = oldResultPoints[i];
|
||||
newResultPoints.push_back(Ref<ResultPoint>(new ResultPoint(oldPoint->getX() + xOffset, oldPoint->getY() + yOffset)));
|
||||
}
|
||||
return Ref<Result>(new Result(result->getText(), result->getRawBytes(), newResultPoints, result->getBarcodeFormat()));
|
||||
}
|
||||
|
||||
} // End zxing::multi namespace
|
||||
} // End zxing namespace
|
47
cpp/core/src/zxing/multi/GenericMultipleBarcodeReader.h
Normal file
47
cpp/core/src/zxing/multi/GenericMultipleBarcodeReader.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
#ifndef __GENERIC_MULTIPLE_BARCODE_READER_H__
|
||||
#define __GENERIC_MULTIPLE_BARCODE_READER_H__
|
||||
|
||||
/*
|
||||
* Copyright 2011 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 <zxing/multi/MultipleBarcodeReader.h>
|
||||
#include <zxing/Reader.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace multi {
|
||||
class GenericMultipleBarcodeReader : public MultipleBarcodeReader {
|
||||
private:
|
||||
static Ref<Result> translateResultPoints(Ref<Result> result,
|
||||
int xOffset,
|
||||
int yOffset);
|
||||
void doDecodeMultiple(Ref<BinaryBitmap> image,
|
||||
DecodeHints hints,
|
||||
std::vector<Ref<Result> >& results,
|
||||
int xOffset,
|
||||
int yOffset);
|
||||
Reader& delegate_;
|
||||
static const int MIN_DIMENSION_TO_RECUR = 100;
|
||||
|
||||
public:
|
||||
GenericMultipleBarcodeReader(Reader& delegate);
|
||||
virtual ~GenericMultipleBarcodeReader();
|
||||
virtual std::vector<Ref<Result> > decodeMultiple(Ref<BinaryBitmap> image,
|
||||
DecodeHints hints);
|
||||
};
|
||||
} // End zxing::multi namespace
|
||||
} // End zxing namespace
|
||||
|
||||
#endif // __GENERIC_MULTIPLE_BARCODE_READER_H__
|
29
cpp/core/src/zxing/multi/MultipleBarcodeReader.cpp
Normal file
29
cpp/core/src/zxing/multi/MultipleBarcodeReader.cpp
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2011 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 <zxing/multi/MultipleBarcodeReader.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace multi {
|
||||
|
||||
MultipleBarcodeReader::~MultipleBarcodeReader() { }
|
||||
|
||||
std::vector<Ref<Result> > MultipleBarcodeReader::decodeMultiple(Ref<BinaryBitmap> image) {
|
||||
return decodeMultiple(image, DecodeHints::DEFAULT_HINT);
|
||||
}
|
||||
|
||||
} // End zxing::multi namespace
|
||||
} // End zxing namespace
|
39
cpp/core/src/zxing/multi/MultipleBarcodeReader.h
Normal file
39
cpp/core/src/zxing/multi/MultipleBarcodeReader.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
#ifndef __MULTIPLE_BARCODE_READER_H__
|
||||
#define __MULTIPLE_BARCODE_READER_H__
|
||||
|
||||
/*
|
||||
* Copyright 2011 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 <zxing/common/Counted.h>
|
||||
#include <zxing/Result.h>
|
||||
#include <zxing/BinaryBitmap.h>
|
||||
#include <zxing/DecodeHints.h>
|
||||
#include <vector>
|
||||
|
||||
namespace zxing {
|
||||
namespace multi {
|
||||
class MultipleBarcodeReader : public Counted {
|
||||
protected:
|
||||
MultipleBarcodeReader() {}
|
||||
public:
|
||||
virtual std::vector<Ref<Result> > decodeMultiple(Ref<BinaryBitmap> image);
|
||||
virtual std::vector<Ref<Result> > decodeMultiple(Ref<BinaryBitmap> image, DecodeHints hints) = 0;
|
||||
virtual ~MultipleBarcodeReader();
|
||||
};
|
||||
} // End zxing::multi namespace
|
||||
} // End zxing namespace
|
||||
|
||||
#endif // __MULTIPLE_BARCODE_READER_H__
|
57
cpp/core/src/zxing/multi/qrcode/QRCodeMultiReader.cpp
Normal file
57
cpp/core/src/zxing/multi/qrcode/QRCodeMultiReader.cpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
|
||||
/*
|
||||
* Copyright 2011 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 <zxing/multi/qrcode/QRCodeMultiReader.h>
|
||||
#include <zxing/ReaderException.h>
|
||||
#include <zxing/multi/qrcode/detector/MultiDetector.h>
|
||||
#include <zxing/BarcodeFormat.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace multi {
|
||||
QRCodeMultiReader::QRCodeMultiReader(){}
|
||||
|
||||
QRCodeMultiReader::~QRCodeMultiReader(){}
|
||||
|
||||
std::vector<Ref<Result> > QRCodeMultiReader::decodeMultiple(Ref<BinaryBitmap> image,
|
||||
DecodeHints hints)
|
||||
{
|
||||
std::vector<Ref<Result> > results;
|
||||
MultiDetector detector(image->getBlackMatrix());
|
||||
|
||||
std::vector<Ref<DetectorResult> > detectorResult = detector.detectMulti(hints);
|
||||
for (unsigned int i = 0; i < detectorResult.size(); i++) {
|
||||
try {
|
||||
Ref<DecoderResult> decoderResult = getDecoder().decode(detectorResult[i]->getBits());
|
||||
std::vector<Ref<ResultPoint> > points = detectorResult[i]->getPoints();
|
||||
Ref<Result> result = Ref<Result>(new Result(decoderResult->getText(),
|
||||
decoderResult->getRawBytes(),
|
||||
points, BarcodeFormat_QR_CODE));
|
||||
// result->putMetadata(ResultMetadataType.BYTE_SEGMENTS, decoderResult->getByteSegments());
|
||||
// result->putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, decoderResult->getECLevel().toString());
|
||||
results.push_back(result);
|
||||
} catch (ReaderException re) {
|
||||
// ignore and continue
|
||||
}
|
||||
}
|
||||
if (results.empty()){
|
||||
throw ReaderException("No code detected");
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
} // End zxing::multi namespace
|
||||
} // End zxing namespace
|
34
cpp/core/src/zxing/multi/qrcode/QRCodeMultiReader.h
Normal file
34
cpp/core/src/zxing/multi/qrcode/QRCodeMultiReader.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
#ifndef __QRCODE_MULTI_READER_H__
|
||||
#define __QRCODE_MULTI_READER_H__
|
||||
|
||||
/*
|
||||
* Copyright 2011 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 <zxing/multi/MultipleBarcodeReader.h>
|
||||
#include <zxing/qrcode/QRCodeReader.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace multi {
|
||||
class QRCodeMultiReader: public zxing::qrcode::QRCodeReader, public MultipleBarcodeReader {
|
||||
public:
|
||||
QRCodeMultiReader();
|
||||
virtual ~QRCodeMultiReader();
|
||||
virtual std::vector<Ref<Result> > decodeMultiple(Ref<BinaryBitmap> image, DecodeHints hints);
|
||||
};
|
||||
} // End zxing::multi namespace
|
||||
} // End zxing namespace
|
||||
|
||||
#endif // __QRCODE_MULTI_READER_H__
|
46
cpp/core/src/zxing/multi/qrcode/detector/MultiDetector.cpp
Normal file
46
cpp/core/src/zxing/multi/qrcode/detector/MultiDetector.cpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright 2011 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 <zxing/multi/qrcode/detector/MultiDetector.h>
|
||||
#include <zxing/multi/qrcode/detector/MultiFinderPatternFinder.h>
|
||||
#include <zxing/ReaderException.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace multi {
|
||||
using namespace zxing::qrcode;
|
||||
|
||||
MultiDetector::MultiDetector(Ref<BitMatrix> image) : Detector(image) {}
|
||||
|
||||
MultiDetector::~MultiDetector(){}
|
||||
|
||||
std::vector<Ref<DetectorResult> > MultiDetector::detectMulti(DecodeHints hints){
|
||||
Ref<BitMatrix> image = getImage();
|
||||
MultiFinderPatternFinder finder = MultiFinderPatternFinder(image, hints.getResultPointCallback());
|
||||
std::vector<Ref<FinderPatternInfo> > info = finder.findMulti(hints);
|
||||
std::vector<Ref<DetectorResult> > result;
|
||||
for(unsigned int i = 0; i < info.size(); i++){
|
||||
try{
|
||||
result.push_back(processFinderPatternInfo(info[i]));
|
||||
} catch (ReaderException e){
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // End zxing::multi namespace
|
||||
} // End zxing namespace
|
35
cpp/core/src/zxing/multi/qrcode/detector/MultiDetector.h
Normal file
35
cpp/core/src/zxing/multi/qrcode/detector/MultiDetector.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
#ifndef __MULTI_DETECTOR_H__
|
||||
#define __MULTI_DETECTOR_H__
|
||||
|
||||
/*
|
||||
* Copyright 2011 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 <zxing/qrcode/detector/Detector.h>
|
||||
#include <zxing/common/DetectorResult.h>
|
||||
#include <zxing/DecodeHints.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace multi {
|
||||
class MultiDetector : public zxing::qrcode::Detector {
|
||||
public:
|
||||
MultiDetector(Ref<BitMatrix> image);
|
||||
virtual ~MultiDetector();
|
||||
virtual std::vector<Ref<DetectorResult> > detectMulti(DecodeHints hints);
|
||||
};
|
||||
} // End zxing::multi namespace
|
||||
} // End zxing namespace
|
||||
|
||||
#endif // __MULTI_DETECTOR_H__
|
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
* Copyright 2011 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 <algorithm>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <zxing/multi/qrcode/detector/MultiFinderPatternFinder.h>
|
||||
#include <zxing/DecodeHints.h>
|
||||
#include <zxing/ReaderException.h>
|
||||
|
||||
namespace zxing{
|
||||
namespace multi {
|
||||
using namespace zxing::qrcode;
|
||||
|
||||
bool compareModuleSize(Ref<FinderPattern> a, Ref<FinderPattern> b){
|
||||
float value = a->getEstimatedModuleSize() - b->getEstimatedModuleSize();
|
||||
return value < 0.0;
|
||||
}
|
||||
|
||||
|
||||
MultiFinderPatternFinder::MultiFinderPatternFinder(Ref<BitMatrix> image,
|
||||
Ref<ResultPointCallback> resultPointCallback) :
|
||||
FinderPatternFinder(image, resultPointCallback)
|
||||
{
|
||||
}
|
||||
|
||||
MultiFinderPatternFinder::~MultiFinderPatternFinder(){}
|
||||
|
||||
std::vector<Ref<FinderPatternInfo> > MultiFinderPatternFinder::findMulti(DecodeHints const& hints){
|
||||
bool tryHarder = hints.getTryHarder();
|
||||
Ref<BitMatrix> image = image_; // Protected member
|
||||
int maxI = image->getHeight();
|
||||
int maxJ = image->getWidth();
|
||||
// We are looking for black/white/black/white/black modules in
|
||||
// 1:1:3:1:1 ratio; this tracks the number of such modules seen so far
|
||||
|
||||
// Let's assume that the maximum version QR Code we support takes up 1/4 the height of the
|
||||
// image, and then account for the center being 3 modules in size. This gives the smallest
|
||||
// number of pixels the center could be, so skip this often. When trying harder, look for all
|
||||
// QR versions regardless of how dense they are.
|
||||
int iSkip = (int) (maxI / (MAX_MODULES * 4.0f) * 3);
|
||||
if (iSkip < MIN_SKIP || tryHarder) {
|
||||
iSkip = MIN_SKIP;
|
||||
}
|
||||
|
||||
int stateCount[5];
|
||||
for (int i = iSkip - 1; i < maxI; i += iSkip) {
|
||||
// Get a row of black/white values
|
||||
stateCount[0] = 0;
|
||||
stateCount[1] = 0;
|
||||
stateCount[2] = 0;
|
||||
stateCount[3] = 0;
|
||||
stateCount[4] = 0;
|
||||
int currentState = 0;
|
||||
for (int j = 0; j < maxJ; j++) {
|
||||
if (image->get(j, i)) {
|
||||
// Black pixel
|
||||
if ((currentState & 1) == 1) { // Counting white pixels
|
||||
currentState++;
|
||||
}
|
||||
stateCount[currentState]++;
|
||||
} else { // White pixel
|
||||
if ((currentState & 1) == 0) { // Counting black pixels
|
||||
if (currentState == 4) { // A winner?
|
||||
if (foundPatternCross(stateCount)) { // Yes
|
||||
bool confirmed = handlePossibleCenter(stateCount, i, j);
|
||||
if (!confirmed) {
|
||||
do { // Advance to next black pixel
|
||||
j++;
|
||||
} while (j < maxJ && !image->get(j, i));
|
||||
j--; // back up to that last white pixel
|
||||
}
|
||||
// Clear state to start looking again
|
||||
currentState = 0;
|
||||
stateCount[0] = 0;
|
||||
stateCount[1] = 0;
|
||||
stateCount[2] = 0;
|
||||
stateCount[3] = 0;
|
||||
stateCount[4] = 0;
|
||||
} else { // No, shift counts back by two
|
||||
stateCount[0] = stateCount[2];
|
||||
stateCount[1] = stateCount[3];
|
||||
stateCount[2] = stateCount[4];
|
||||
stateCount[3] = 1;
|
||||
stateCount[4] = 0;
|
||||
currentState = 3;
|
||||
}
|
||||
} else {
|
||||
stateCount[++currentState]++;
|
||||
}
|
||||
} else { // Counting white pixels
|
||||
stateCount[currentState]++;
|
||||
}
|
||||
}
|
||||
} // for j=...
|
||||
|
||||
if (foundPatternCross(stateCount)) {
|
||||
handlePossibleCenter(stateCount, i, maxJ);
|
||||
} // end if foundPatternCross
|
||||
} // for i=iSkip-1 ...
|
||||
std::vector<std::vector<Ref<FinderPattern> > > patternInfo = selectBestPatterns();
|
||||
std::vector<Ref<FinderPatternInfo> > result;
|
||||
for (unsigned int i = 0; i < patternInfo.size(); i++) {
|
||||
std::vector<Ref<FinderPattern> > pattern = patternInfo[i];
|
||||
FinderPatternFinder::orderBestPatterns(pattern);
|
||||
result.push_back(Ref<FinderPatternInfo>(new FinderPatternInfo(pattern)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::vector<Ref<FinderPattern> > > MultiFinderPatternFinder::selectBestPatterns(){
|
||||
std::vector<Ref<FinderPattern> > possibleCenters = possibleCenters_;
|
||||
|
||||
int size = possibleCenters.size();
|
||||
|
||||
if (size < 3) {
|
||||
// Couldn't find enough finder patterns
|
||||
throw ReaderException("No code detected");
|
||||
}
|
||||
|
||||
std::vector<std::vector<Ref<FinderPattern> > > results;
|
||||
|
||||
/*
|
||||
* Begin HE modifications to safely detect multiple codes of equal size
|
||||
*/
|
||||
if (size == 3) {
|
||||
results.push_back(possibleCenters_);
|
||||
return results;
|
||||
}
|
||||
|
||||
// Sort by estimated module size to speed up the upcoming checks
|
||||
//TODO do a sort based on module size
|
||||
std::sort(possibleCenters.begin(), possibleCenters.end(), compareModuleSize);
|
||||
|
||||
/*
|
||||
* Now lets start: build a list of tuples of three finder locations that
|
||||
* - feature similar module sizes
|
||||
* - are placed in a distance so the estimated module count is within the QR specification
|
||||
* - have similar distance between upper left/right and left top/bottom finder patterns
|
||||
* - form a triangle with 90° angle (checked by comparing top right/bottom left distance
|
||||
* with pythagoras)
|
||||
*
|
||||
* Note: we allow each point to be used for more than one code region: this might seem
|
||||
* counterintuitive at first, but the performance penalty is not that big. At this point,
|
||||
* we cannot make a good quality decision whether the three finders actually represent
|
||||
* a QR code, or are just by chance layouted so it looks like there might be a QR code there.
|
||||
* So, if the layout seems right, lets have the decoder try to decode.
|
||||
*/
|
||||
|
||||
for (int i1 = 0; i1 < (size - 2); i1++) {
|
||||
Ref<FinderPattern> p1 = possibleCenters[i1];
|
||||
for (int i2 = i1 + 1; i2 < (size - 1); i2++) {
|
||||
Ref<FinderPattern> p2 = possibleCenters[i2];
|
||||
// Compare the expected module sizes; if they are really off, skip
|
||||
float vModSize12 = (p1->getEstimatedModuleSize() - p2->getEstimatedModuleSize()) / std::min(p1->getEstimatedModuleSize(), p2->getEstimatedModuleSize());
|
||||
float vModSize12A = abs(p1->getEstimatedModuleSize() - p2->getEstimatedModuleSize());
|
||||
if (vModSize12A > DIFF_MODSIZE_CUTOFF && vModSize12 >= DIFF_MODSIZE_CUTOFF_PERCENT) {
|
||||
// break, since elements are ordered by the module size deviation there cannot be
|
||||
// any more interesting elements for the given p1.
|
||||
break;
|
||||
}
|
||||
for (int i3 = i2 + 1; i3 < size; i3++) {
|
||||
Ref<FinderPattern> p3 = possibleCenters[i3];
|
||||
// Compare the expected module sizes; if they are really off, skip
|
||||
float vModSize23 = (p2->getEstimatedModuleSize() - p3->getEstimatedModuleSize()) / std::min(p2->getEstimatedModuleSize(), p3->getEstimatedModuleSize());
|
||||
float vModSize23A = abs(p2->getEstimatedModuleSize() - p3->getEstimatedModuleSize());
|
||||
if (vModSize23A > DIFF_MODSIZE_CUTOFF && vModSize23 >= DIFF_MODSIZE_CUTOFF_PERCENT) {
|
||||
// break, since elements are ordered by the module size deviation there cannot be
|
||||
// any more interesting elements for the given p1.
|
||||
break;
|
||||
}
|
||||
std::vector<Ref<FinderPattern> > test;
|
||||
test.push_back(p1);
|
||||
test.push_back(p2);
|
||||
test.push_back(p3);
|
||||
FinderPatternFinder::orderBestPatterns(test);
|
||||
// Calculate the distances: a = topleft-bottomleft, b=topleft-topright, c = diagonal
|
||||
Ref<FinderPatternInfo> info = Ref<FinderPatternInfo>(new FinderPatternInfo(test));
|
||||
float dA = FinderPatternFinder::distance(info->getTopLeft(), info->getBottomLeft());
|
||||
float dC = FinderPatternFinder::distance(info->getTopRight(), info->getBottomLeft());
|
||||
float dB = FinderPatternFinder::distance(info->getTopLeft(), info->getTopRight());
|
||||
// Check the sizes
|
||||
float estimatedModuleCount = (dA + dB) / (p1->getEstimatedModuleSize() * 2.0f);
|
||||
if (estimatedModuleCount > MAX_MODULE_COUNT_PER_EDGE || estimatedModuleCount < MIN_MODULE_COUNT_PER_EDGE) {
|
||||
continue;
|
||||
}
|
||||
// Calculate the difference of the edge lengths in percent
|
||||
float vABBC = abs((dA - dB) / std::min(dA, dB));
|
||||
if (vABBC >= 0.1f) {
|
||||
continue;
|
||||
}
|
||||
// Calculate the diagonal length by assuming a 90° angle at topleft
|
||||
float dCpy = (float) sqrt(dA * dA + dB * dB);
|
||||
// Compare to the real distance in %
|
||||
float vPyC = abs((dC - dCpy) / std::min(dC, dCpy));
|
||||
if (vPyC >= 0.1f) {
|
||||
continue;
|
||||
}
|
||||
// All tests passed!
|
||||
results.push_back(test);
|
||||
} // end iterate p3
|
||||
} // end iterate p2
|
||||
} // end iterate p1
|
||||
if (results.empty()){
|
||||
// Nothing found!
|
||||
throw ReaderException("No code detected");
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
} // End zxing::multi namespace
|
||||
} // End zxing namespace
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef __MULTI_FINDER_PATTERN_FINDER_H__
|
||||
#define __MULTI_FINDER_PATTERN_FINDER_H__
|
||||
|
||||
/*
|
||||
* Copyright 2011 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 <zxing/qrcode/detector/FinderPattern.h>
|
||||
#include <zxing/qrcode/detector/FinderPatternFinder.h>
|
||||
#include <zxing/qrcode/detector/FinderPatternInfo.h>
|
||||
|
||||
namespace zxing {
|
||||
namespace multi {
|
||||
class MultiFinderPatternFinder : zxing::qrcode::FinderPatternFinder {
|
||||
private:
|
||||
std::vector<std::vector<Ref<zxing::qrcode::FinderPattern> > > selectBestPatterns();
|
||||
|
||||
static const float MAX_MODULE_COUNT_PER_EDGE = 180;
|
||||
static const float MIN_MODULE_COUNT_PER_EDGE = 9;
|
||||
static const float DIFF_MODSIZE_CUTOFF_PERCENT = 0.05f;
|
||||
static const float DIFF_MODSIZE_CUTOFF = 0.5f;
|
||||
|
||||
public:
|
||||
MultiFinderPatternFinder(Ref<BitMatrix> image, Ref<ResultPointCallback> resultPointCallback);
|
||||
virtual ~MultiFinderPatternFinder();
|
||||
virtual std::vector<Ref<zxing::qrcode::FinderPatternInfo> > findMulti(DecodeHints const& hints);
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __MULTI_FINDER_PATTERN_FINDER_H__
|
|
@ -22,15 +22,7 @@
|
|||
namespace zxing {
|
||||
namespace oned {
|
||||
|
||||
OneDResultPoint::OneDResultPoint(float posX, float posY) : posX_(posX), posY_(posY) {
|
||||
}
|
||||
|
||||
float OneDResultPoint::getX() const {
|
||||
return posX_;
|
||||
}
|
||||
|
||||
float OneDResultPoint::getY() const {
|
||||
return posY_;
|
||||
OneDResultPoint::OneDResultPoint(float posX, float posY) : ResultPoint(posX,posY) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,14 +25,9 @@ namespace zxing {
|
|||
namespace oned {
|
||||
|
||||
class OneDResultPoint : public ResultPoint {
|
||||
private:
|
||||
float posX_;
|
||||
float posY_;
|
||||
|
||||
public:
|
||||
OneDResultPoint(float posX, float posY);
|
||||
float getX() const;
|
||||
float getY() const;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,5 +79,8 @@ namespace zxing {
|
|||
QRCodeReader::~QRCodeReader() {
|
||||
}
|
||||
|
||||
Decoder& QRCodeReader::getDecoder() {
|
||||
return decoder_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,9 @@ namespace zxing {
|
|||
private:
|
||||
Decoder decoder_;
|
||||
|
||||
protected:
|
||||
Decoder& getDecoder();
|
||||
|
||||
public:
|
||||
QRCodeReader();
|
||||
virtual Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints);
|
||||
|
|
|
@ -27,15 +27,7 @@ namespace qrcode {
|
|||
using namespace std;
|
||||
|
||||
AlignmentPattern::AlignmentPattern(float posX, float posY, float estimatedModuleSize) :
|
||||
posX_(posX), posY_(posY), estimatedModuleSize_(estimatedModuleSize) {
|
||||
}
|
||||
|
||||
float AlignmentPattern::getX() const {
|
||||
return posX_;
|
||||
}
|
||||
|
||||
float AlignmentPattern::getY() const {
|
||||
return posY_;
|
||||
ResultPoint(posX,posY), estimatedModuleSize_(estimatedModuleSize) {
|
||||
}
|
||||
|
||||
bool AlignmentPattern::aboutEquals(float moduleSize, float i, float j) const {
|
||||
|
|
|
@ -30,14 +30,10 @@ namespace zxing {
|
|||
|
||||
class AlignmentPattern : public ResultPoint {
|
||||
private:
|
||||
float posX_;
|
||||
float posY_;
|
||||
float estimatedModuleSize_;
|
||||
|
||||
public:
|
||||
AlignmentPattern(float posX, float posY, float estimatedModuleSize);
|
||||
float getX() const;
|
||||
float getY() const;
|
||||
bool aboutEquals(float moduleSize, float i, float j) const;
|
||||
Ref<AlignmentPattern> combineEstimate(float i, float j,
|
||||
float newModuleSize) const;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
|
||||
/*
|
||||
* Detector.cpp
|
||||
* zxing
|
||||
|
@ -47,7 +48,10 @@ Ref<DetectorResult> Detector::detect(DecodeHints const& hints) {
|
|||
callback_ = hints.getResultPointCallback();
|
||||
FinderPatternFinder finder(image_, hints.getResultPointCallback());
|
||||
Ref<FinderPatternInfo> info(finder.find(hints));
|
||||
return processFinderPatternInfo(info);
|
||||
}
|
||||
|
||||
Ref<DetectorResult> Detector::processFinderPatternInfo(Ref<FinderPatternInfo> info){
|
||||
Ref<FinderPattern> topLeft(info->getTopLeft());
|
||||
Ref<FinderPattern> topRight(info->getTopRight());
|
||||
Ref<FinderPattern> bottomLeft(info->getBottomLeft());
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <zxing/qrcode/detector/AlignmentPattern.h>
|
||||
#include <zxing/common/PerspectiveTransform.h>
|
||||
#include <zxing/ResultPointCallback.h>
|
||||
#include <zxing/qrcode/detector/FinderPatternInfo.h>
|
||||
|
||||
namespace zxing {
|
||||
|
||||
|
@ -50,6 +51,7 @@ protected:
|
|||
float sizeOfBlackWhiteBlackRun(int fromX, int fromY, int toX, int toY);
|
||||
Ref<AlignmentPattern> findAlignmentInRegion(float overallEstModuleSize, int estAlignmentX, int estAlignmentY,
|
||||
float allowanceFactor);
|
||||
Ref<DetectorResult> processFinderPatternInfo(Ref<FinderPatternInfo> info);
|
||||
public:
|
||||
|
||||
virtual Ref<PerspectiveTransform> createTransform(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight, Ref <
|
||||
|
|
|
@ -27,19 +27,11 @@ namespace zxing {
|
|||
using namespace std;
|
||||
|
||||
FinderPattern::FinderPattern(float posX, float posY, float estimatedModuleSize) :
|
||||
posX_(posX), posY_(posY), estimatedModuleSize_(estimatedModuleSize), count_(1) {
|
||||
ResultPoint(posX,posY), estimatedModuleSize_(estimatedModuleSize), count_(1) {
|
||||
}
|
||||
|
||||
FinderPattern::FinderPattern(float posX, float posY, float estimatedModuleSize, int count) :
|
||||
posX_(posX), posY_(posY), estimatedModuleSize_(estimatedModuleSize), count_(count) {
|
||||
}
|
||||
|
||||
float FinderPattern::getX() const {
|
||||
return posX_;
|
||||
}
|
||||
|
||||
float FinderPattern::getY() const {
|
||||
return posY_;
|
||||
ResultPoint(posX,posY), estimatedModuleSize_(estimatedModuleSize), count_(count) {
|
||||
}
|
||||
|
||||
int FinderPattern::getCount() const {
|
||||
|
|
|
@ -29,16 +29,12 @@ namespace zxing {
|
|||
|
||||
class FinderPattern : public ResultPoint {
|
||||
private:
|
||||
float posX_;
|
||||
float posY_;
|
||||
float estimatedModuleSize_;
|
||||
int count_;
|
||||
|
||||
public:
|
||||
FinderPattern(float posX, float posY, float estimatedModuleSize);
|
||||
FinderPattern(float posX, float posY, float estimatedModuleSize, int count);
|
||||
float getX() const;
|
||||
float getY() const;
|
||||
int getCount() const;
|
||||
float getEstimatedModuleSize() const;
|
||||
void incrementCount();
|
||||
|
|
|
@ -36,6 +36,8 @@ namespace qrcode {
|
|||
class FinderPatternFinder {
|
||||
private:
|
||||
static int CENTER_QUORUM;
|
||||
|
||||
protected:
|
||||
static int MIN_SKIP;
|
||||
static int MAX_MODULES;
|
||||
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
/*
|
||||
* MagickBitmapSource.cpp
|
||||
* zxing
|
||||
*
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
* Copyright 2010-2011 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -29,11 +26,9 @@ MagickBitmapSource::MagickBitmapSource(Image& image) : image_(image) {
|
|||
width = image.columns();
|
||||
height = image.rows();
|
||||
|
||||
pixel_cache = image.getConstPixels(0, 0, width, height);
|
||||
}
|
||||
|
||||
MagickBitmapSource::~MagickBitmapSource() {
|
||||
|
||||
}
|
||||
|
||||
int MagickBitmapSource::getWidth() const {
|
||||
|
@ -45,12 +40,13 @@ int MagickBitmapSource::getHeight() const {
|
|||
}
|
||||
|
||||
unsigned char* MagickBitmapSource::getRow(int y, unsigned char* row) {
|
||||
const Magick::PixelPacket* pixel_cache = image_.getConstPixels(0, y, width, 1);
|
||||
int width = getWidth();
|
||||
if (row == NULL) {
|
||||
row = new unsigned char[width];
|
||||
}
|
||||
for (int x = 0; x < width; x++) {
|
||||
const PixelPacket* p = pixel_cache + y * width + x;
|
||||
const PixelPacket* p = pixel_cache + x;
|
||||
// We assume 16 bit values here
|
||||
// 0x200 = 1<<9, half an lsb of the result to force rounding
|
||||
row[x] = (unsigned char)((306 * ((int)p->red >> 8) + 601 * ((int)p->green >> 8) +
|
||||
|
@ -62,6 +58,7 @@ unsigned char* MagickBitmapSource::getRow(int y, unsigned char* row) {
|
|||
|
||||
/** This is a more efficient implementation. */
|
||||
unsigned char* MagickBitmapSource::getMatrix() {
|
||||
const Magick::PixelPacket* pixel_cache = image_.getConstPixels(0, 0, width, height);
|
||||
int width = getWidth();
|
||||
int height = getHeight();
|
||||
unsigned char* matrix = new unsigned char[width*height];
|
||||
|
@ -79,20 +76,29 @@ unsigned char* MagickBitmapSource::getMatrix() {
|
|||
}
|
||||
|
||||
bool MagickBitmapSource::isRotateSupported() const {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
Ref<LuminanceSource> MagickBitmapSource::rotateCounterClockwise() {
|
||||
//TODO(flyashi): add rotated image support.
|
||||
/* this segfaults. I tried a few things, none seemed to work. Perhaps the problem is elsewhere? */
|
||||
/*
|
||||
Magick::Image rotated(image_);
|
||||
rotated.modifyImage();
|
||||
rotated.rotate(90); // Image::rotate takes CCW degrees as an argument
|
||||
rotated.syncPixels();
|
||||
return Ref<MagickBitmapSource> (new MagickBitmapSource(rotated));
|
||||
*/
|
||||
return Ref<MagickBitmapSource> (NULL);
|
||||
}
|
||||
|
||||
bool MagickBitmapSource::isCropSupported() const{
|
||||
return true;
|
||||
}
|
||||
|
||||
Ref<LuminanceSource> MagickBitmapSource::crop(int left, int top, int width, int height){
|
||||
/* TODO Investigate memory leak:
|
||||
* This method "possibly leaks" 160 bytes in 1 block */
|
||||
Image copy(image_);
|
||||
copy.modifyImage();
|
||||
copy.crop( Geometry(width,height,left,top));
|
||||
copy.syncPixels();
|
||||
return Ref<MagickBitmapSource>(new MagickBitmapSource(copy));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
#ifndef __MAGICK_BITMAP_SOURCE_H_
|
||||
#define __MAGICK_BITMAP_SOURCE_H_
|
||||
/*
|
||||
* MagickBitmapSource.h
|
||||
* zxing
|
||||
*
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
* Copyright 2010-2011 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -26,10 +23,9 @@ namespace zxing {
|
|||
|
||||
class MagickBitmapSource : public LuminanceSource {
|
||||
private:
|
||||
Magick::Image& image_;
|
||||
Magick::Image image_;
|
||||
int width;
|
||||
int height;
|
||||
const Magick::PixelPacket* pixel_cache;
|
||||
|
||||
public:
|
||||
MagickBitmapSource(Magick::Image& image);
|
||||
|
@ -40,6 +36,8 @@ public:
|
|||
int getHeight() const;
|
||||
unsigned char* getRow(int y, unsigned char* row);
|
||||
unsigned char* getMatrix();
|
||||
bool isCropSupported() const;
|
||||
Ref<LuminanceSource> crop(int left, int top, int width, int height);
|
||||
bool isRotateSupported() const;
|
||||
Ref<LuminanceSource> rotateCounterClockwise();
|
||||
};
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
// -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
|
||||
/*
|
||||
* main.cpp
|
||||
* zxing
|
||||
*
|
||||
* Copyright 2010 ZXing authors All rights reserved.
|
||||
* Copyright 2010-2011 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -24,7 +21,6 @@
|
|||
#include <Magick++.h>
|
||||
#include "MagickBitmapSource.h"
|
||||
#include <zxing/common/Counted.h>
|
||||
//#include <zxing/qrcode/QRCodeReader.h>
|
||||
#include <zxing/Binarizer.h>
|
||||
#include <zxing/MultiFormatReader.h>
|
||||
#include <zxing/Result.h>
|
||||
|
@ -37,6 +33,12 @@
|
|||
#include <zxing/BinaryBitmap.h>
|
||||
#include <zxing/DecodeHints.h>
|
||||
|
||||
#include <zxing/qrcode/QRCodeReader.h>
|
||||
#include <zxing/multi/qrcode/QRCodeMultiReader.h>
|
||||
#include <zxing/multi/ByQuadrantReader.h>
|
||||
#include <zxing/multi/MultipleBarcodeReader.h>
|
||||
#include <zxing/multi/GenericMultipleBarcodeReader.h>
|
||||
|
||||
//#include <zxing/qrcode/detector/Detector.h>
|
||||
//#include <zxing/qrcode/detector/QREdgeDetector.h>
|
||||
//#include <zxing/qrcode/decoder/Decoder.h>
|
||||
|
@ -44,12 +46,14 @@
|
|||
using namespace Magick;
|
||||
using namespace std;
|
||||
using namespace zxing;
|
||||
//using namespace zxing::qrcode;
|
||||
using namespace zxing::multi;
|
||||
using namespace zxing::qrcode;
|
||||
|
||||
static bool raw_dump = false;
|
||||
static bool show_format = false;
|
||||
static bool tryHarder = false;
|
||||
static bool show_filename = false;
|
||||
static bool search_multi = false;
|
||||
|
||||
static const int MAX_EXPECTED = 1024;
|
||||
|
||||
|
@ -58,6 +62,16 @@ Ref<Result> decode(Ref<BinaryBitmap> image, DecodeHints hints) {
|
|||
return reader->decode(image, hints);
|
||||
}
|
||||
|
||||
vector<Ref<Result> > decodeMultiple(Ref<BinaryBitmap> image, DecodeHints hints){
|
||||
MultiFormatReader delegate;
|
||||
// MultiFormatReader mformat;
|
||||
// ByQuadrantReader delegate(mformat);
|
||||
|
||||
GenericMultipleBarcodeReader reader(delegate);
|
||||
// QRCodeMultiReader reader;
|
||||
return reader.decodeMultiple(image,hints);
|
||||
}
|
||||
|
||||
|
||||
int test_image(Image& image, bool hybrid, string expected = "") {
|
||||
|
||||
|
@ -101,22 +115,20 @@ int test_image(Image& image, bool hybrid, string expected = "") {
|
|||
if (cell_result.compare(expected)) {
|
||||
res = -6;
|
||||
if (!raw_dump) {
|
||||
cout << (hybrid ? "Hybrid" : "Global") << " binarizer failed:\n";
|
||||
if (expected.length() >= 0) {
|
||||
cout << " Expected: " << expected << "\n";
|
||||
}
|
||||
cout << " Detected: " << cell_result << endl;
|
||||
cout << (hybrid ? "Hybrid" : "Global") << " binarizer failed:\n";
|
||||
if (expected.length() >= 0) {
|
||||
cout << " Expected: " << expected << "\n";
|
||||
}
|
||||
cout << " Detected: " << cell_result << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (raw_dump && !hybrid) {/* don't print twice, and global is a bit better */
|
||||
cout << cell_result;
|
||||
if (show_format) {
|
||||
cout << " " << result_format;
|
||||
}
|
||||
cout << endl;
|
||||
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -129,6 +141,64 @@ int test_image_global(Image& image, string expected = "") {
|
|||
return test_image(image, false, expected);
|
||||
}
|
||||
|
||||
int test_image_multi(Image& image, bool hybrid){
|
||||
vector<Ref<Result> > results;
|
||||
string cell_result;
|
||||
int res = -1;
|
||||
|
||||
Ref<BitMatrix> matrix(NULL);
|
||||
Ref<Binarizer> binarizer(NULL);
|
||||
|
||||
try {
|
||||
Ref<MagickBitmapSource> source(new MagickBitmapSource(image));
|
||||
|
||||
if (hybrid) {
|
||||
binarizer = new HybridBinarizer(source);
|
||||
} else {
|
||||
binarizer = new GlobalHistogramBinarizer(source);
|
||||
}
|
||||
DecodeHints hints(DecodeHints::DEFAULT_HINT);
|
||||
hints.setTryHarder(tryHarder);
|
||||
Ref<BinaryBitmap> binary(new BinaryBitmap(binarizer));
|
||||
results = decodeMultiple(binary, hints);
|
||||
res = 0;
|
||||
} catch (ReaderException e) {
|
||||
cell_result = "zxing::ReaderException: " + string(e.what());
|
||||
res = -2;
|
||||
} catch (zxing::IllegalArgumentException& e) {
|
||||
cell_result = "zxing::IllegalArgumentException: " + string(e.what());
|
||||
res = -3;
|
||||
} catch (zxing::Exception& e) {
|
||||
cell_result = "zxing::Exception: " + string(e.what());
|
||||
res = -4;
|
||||
} catch (std::exception& e) {
|
||||
cell_result = "std::exception: " + string(e.what());
|
||||
res = -5;
|
||||
}
|
||||
cout << (hybrid ? "Hybrid" : "Global");
|
||||
if (res != 0){
|
||||
cout<<" binarizer failed: "<<cell_result<<endl;
|
||||
} else {
|
||||
cout<<" binarizer succeeded: "<<endl;
|
||||
for (unsigned int i = 0; i < results.size(); i++){
|
||||
cout << " "<<results[i]->getText()->getText();
|
||||
if (show_format) {
|
||||
cout << " " << barcodeFormatNames[results[i]->getBarcodeFormat()];
|
||||
}
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int test_image_multi_hybrid(Image& image){
|
||||
return test_image_multi(image, true);
|
||||
}
|
||||
|
||||
int test_image_multi_global(Image& image){
|
||||
return test_image_multi(image, false);
|
||||
}
|
||||
|
||||
string get_expected(string imagefilename) {
|
||||
string textfilename = imagefilename;
|
||||
int dotpos = textfilename.rfind(".");
|
||||
|
@ -146,8 +216,8 @@ string get_expected(string imagefilename) {
|
|||
rewind(fp);
|
||||
|
||||
if (toread > MAX_EXPECTED) {
|
||||
cerr << "MAX_EXPECTED = " << MAX_EXPECTED << " but file '" << textfilename << "' has " << toread
|
||||
<< " bytes! Skipping..." << endl;
|
||||
cerr << "MAX_EXPECTED = " << MAX_EXPECTED << " but file '" << textfilename << "' has " << toread
|
||||
<< " bytes! Skipping..." << endl;
|
||||
fclose(fp);
|
||||
return "";
|
||||
}
|
||||
|
@ -166,7 +236,7 @@ string get_expected(string imagefilename) {
|
|||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc <= 1) {
|
||||
cout << "Usage: " << argv[0] << " [--dump-raw] [--show-format] [--try-harder] [--show-filename] <filename1> [<filename2> ...]" << endl;
|
||||
cout << "Usage: " << argv[0] << " [--dump-raw] [--show-format] [--try-harder] [--search_multi] [--show-filename] <filename1> [<filename2> ...]" << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -199,6 +269,10 @@ int main(int argc, char** argv) {
|
|||
show_filename = true;
|
||||
continue;
|
||||
}
|
||||
if (infilename.compare("--search_multi") == 0){
|
||||
search_multi = true;
|
||||
continue;
|
||||
}
|
||||
if (!raw_dump)
|
||||
cerr << "Processing: " << infilename << endl;
|
||||
if (show_filename)
|
||||
|
@ -214,27 +288,39 @@ int main(int argc, char** argv) {
|
|||
string expected;
|
||||
expected = get_expected(infilename);
|
||||
|
||||
int gresult = 1;
|
||||
int hresult = 1;
|
||||
if (search_multi){
|
||||
int gresult = 1;
|
||||
int hresult = 1;
|
||||
gresult = test_image_multi_global(image);
|
||||
hresult = test_image_multi_hybrid(image);
|
||||
gresult = gresult == 0;
|
||||
hresult = hresult == 0;
|
||||
gonly += gresult && !hresult;
|
||||
honly += hresult && !gresult;
|
||||
both += gresult && hresult;
|
||||
neither += !gresult && !hresult;
|
||||
total = total + 1;
|
||||
} else {
|
||||
int gresult = 1;
|
||||
int hresult = 1;
|
||||
hresult = test_image_hybrid(image, expected);
|
||||
gresult = test_image_global(image, expected);
|
||||
gresult = gresult == 0;
|
||||
hresult = hresult == 0;
|
||||
|
||||
hresult = test_image_hybrid(image, expected);
|
||||
gresult = test_image_global(image, expected);
|
||||
|
||||
gresult = gresult == 0;
|
||||
hresult = hresult == 0;
|
||||
|
||||
gonly += gresult && !hresult;
|
||||
honly += hresult && !gresult;
|
||||
both += gresult && hresult;
|
||||
neither += !gresult && !hresult;
|
||||
total = total + 1;
|
||||
gonly += gresult && !hresult;
|
||||
honly += hresult && !gresult;
|
||||
both += gresult && hresult;
|
||||
neither += !gresult && !hresult;
|
||||
total = total + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!raw_dump)
|
||||
cout << (honly+both) << " passed hybrid, " << (gonly+both) << " passed global, "
|
||||
<< both << " pass both, " << neither << " pass neither, " << honly
|
||||
<< " passed only hybrid, " << gonly << " passed only global, of " << total
|
||||
<< " total." << endl;
|
||||
<< both << " pass both, " << neither << " pass neither, " << honly
|
||||
<< " passed only hybrid, " << gonly << " passed only global, of " << total
|
||||
<< " total." << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue