vendor: OpenCV 5.0.0 snapshot at 755e50675d97db9b7d449d8bd6b09888646f6c6e

This commit is contained in:
Gitea Mirror Bot
2026-08-22 00:11:13 +08:00
commit 12022378a3
3872 changed files with 2513409 additions and 0 deletions
@@ -0,0 +1,113 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#ifndef __ZXING_COMMON_ARRAY_HPP__
#define __ZXING_COMMON_ARRAY_HPP__
#include "counted.hpp"
namespace zxing {
template <typename T>
class Array : public Counted {
protected:
public:
std::vector<T> values_;
Array() {}
explicit Array(int n) : Counted(), values_(n, T()) {}
Array(T const *ts, int n) : Counted(), values_(ts, ts + n) {}
Array(T const *ts, T const *te) : Counted(), values_(ts, te) {}
Array(T v, int n) : Counted(), values_(n, v) {}
explicit Array(std::vector<T> &v) : Counted(), values_(v) {}
Array(Array<T> &other) : Counted(), values_(other.values_) {}
explicit Array(Array<T> *other) : Counted(), values_(other->values_) {}
virtual ~Array() {}
Array<T> &operator=(const Array<T> &other) {
values_ = other.values_;
return *this;
}
Array<T> &operator=(const std::vector<T> &array) {
values_ = array;
return *this;
}
T const &operator[](int i) const { return values_[i]; }
T &operator[](int i) { return values_[i]; }
int size() const { return values_.size(); }
bool empty() const { return values_.size() == 0; }
std::vector<T> const &values() const { return values_; }
std::vector<T> &values() { return values_; }
T *data() {
// return values_.data();
return &values_[0];
}
void append(T value) { values_.push_back(value); }
};
template <typename T>
class ArrayRef : public Counted {
private:
public:
Array<T> *array_;
ArrayRef() : array_(0) {}
explicit ArrayRef(int n) : array_(0) { reset(new Array<T>(n)); }
ArrayRef(T *ts, int n) : array_(0) { reset(new Array<T>(ts, n)); }
explicit ArrayRef(Array<T> *a) : array_(0) { reset(a); }
ArrayRef(const ArrayRef &other) : Counted(), array_(0) { reset(other.array_); }
~ArrayRef() {
if (array_) {
array_->release();
}
array_ = 0;
}
T const &operator[](int i) const { return (*array_)[i]; }
T &operator[](int i) { return (*array_)[i]; }
void reset(Array<T> *a) {
if (a) {
a->retain();
}
if (array_) {
array_->release();
}
array_ = a;
}
void reset(const ArrayRef<T> &other) { reset(other.array_); }
ArrayRef<T> &operator=(const ArrayRef<T> &other) {
reset(other);
return *this;
}
ArrayRef<T> &operator=(Array<T> *a) {
reset(a);
return *this;
}
Array<T> &operator*() const { return *array_; }
Array<T> *operator->() const { return array_; }
operator bool() const { return array_ != 0; }
bool operator!() const { return array_ == 0; }
T *data() { return array_->data(); }
void clear() {
T *ptr = array_->data();
memset(ptr, 0, array_->size());
}
void append(T value) { array_->append(value); }
};
} // namespace zxing
#endif // __ZXING_COMMON_ARRAY_HPP__
@@ -0,0 +1,99 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
#include "../../../precomp.hpp"
#include "adaptive_threshold_mean_binarizer.hpp"
using zxing::AdaptiveThresholdMeanBinarizer;
namespace {
const int BLOCK_SIZE = 25;
const int Bias = 10;
} // namespace
AdaptiveThresholdMeanBinarizer::AdaptiveThresholdMeanBinarizer(Ref<LuminanceSource> source)
: GlobalHistogramBinarizer(source) {}
AdaptiveThresholdMeanBinarizer::~AdaptiveThresholdMeanBinarizer() {}
Ref<Binarizer> AdaptiveThresholdMeanBinarizer::createBinarizer(Ref<LuminanceSource> source) {
return Ref<Binarizer>(new AdaptiveThresholdMeanBinarizer(source));
}
Ref<BitArray> AdaptiveThresholdMeanBinarizer::getBlackRow(int y, Ref<BitArray> row,
ErrorHandler& err_handler) {
// First call binarize image in child class to get matrix0_ and binCache
if (!matrix0_) {
binarizeImage(err_handler);
if (err_handler.ErrCode()) return Ref<BitArray>();
}
// Call parent getBlackMatrix to get current matrix
return Binarizer::getBlackRow(y, row, err_handler);
}
Ref<BitMatrix> AdaptiveThresholdMeanBinarizer::getBlackMatrix(ErrorHandler& err_handler) {
// First call binarize image in child class to get matrix0_ and binCache
if (!matrix0_) {
binarizeImage(err_handler);
if (err_handler.ErrCode()) return Ref<BitMatrix>();
}
return Binarizer::getBlackMatrix(err_handler);
}
int AdaptiveThresholdMeanBinarizer::binarizeImage(ErrorHandler& err_handler) {
if (width >= BLOCK_SIZE && height >= BLOCK_SIZE) {
LuminanceSource& source = *getLuminanceSource();
Ref<BitMatrix> matrix(new BitMatrix(width, height, err_handler));
if (err_handler.ErrCode()) return -1;
auto src = (unsigned char*)source.getMatrix()->data();
auto dst = matrix->getPtr();
cv::Mat mDst;
mDst = cv::Mat::zeros(cv::Size(width, height), CV_8UC1);
TransBufferToMat(src, mDst, width, height);
cv::Mat result;
int bs = width / 10;
bs = bs + bs % 2 - 1;
if (!(bs % 2 == 1 && bs > 1)) return -1;
cv::adaptiveThreshold(mDst, result, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY,
bs, Bias);
TransMatToBuffer(result, dst, width, height);
if (err_handler.ErrCode()) return -1;
matrix0_ = matrix;
} else {
matrix0_ = GlobalHistogramBinarizer::getBlackMatrix(err_handler);
if (err_handler.ErrCode()) return 1;
}
return 0;
}
int AdaptiveThresholdMeanBinarizer::TransBufferToMat(unsigned char* pBuffer, cv::Mat& mDst,
int nWidth, int nHeight) {
for (int j = 0; j < nHeight; ++j) {
unsigned char* data = mDst.ptr<unsigned char>(j);
unsigned char* pSubBuffer = pBuffer + (nHeight - 1 - j) * nWidth;
memcpy(data, pSubBuffer, nWidth);
}
return 0;
}
int AdaptiveThresholdMeanBinarizer::TransMatToBuffer(cv::Mat mSrc, unsigned char* ppBuffer,
int& nWidth, int& nHeight) {
nWidth = mSrc.cols;
// nWidth = ((nWidth + 3) / 4) * 4;
nHeight = mSrc.rows;
for (int j = 0; j < nHeight; ++j) {
unsigned char* pdi = ppBuffer + j * nWidth;
for (int z = 0; z < nWidth; ++z) {
int nj = nHeight - j - 1;
int value = *(uint8_t*)(mSrc.ptr<uint8_t>(nj) + z);
if (value > 120)
pdi[z] = 0;
else
pdi[z] = 1;
}
}
return 0;
}
@@ -0,0 +1,38 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
#ifndef __ZXING_COMMON_ADAPTIVE_THRESHOLD_MEAN_BINARIZER_HPP__
#define __ZXING_COMMON_ADAPTIVE_THRESHOLD_MEAN_BINARIZER_HPP__
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include "../../binarizer.hpp"
#include "../../errorhandler.hpp"
#include "../bitarray.hpp"
#include "../bitmatrix.hpp"
#include "../bytematrix.hpp"
#include "global_histogram_binarizer.hpp"
namespace zxing {
class AdaptiveThresholdMeanBinarizer : public GlobalHistogramBinarizer {
public:
explicit AdaptiveThresholdMeanBinarizer(Ref<LuminanceSource> source);
virtual ~AdaptiveThresholdMeanBinarizer();
virtual Ref<BitMatrix> getBlackMatrix(ErrorHandler& err_handler) override;
virtual Ref<BitArray> getBlackRow(int y, Ref<BitArray> row, ErrorHandler& err_handler) override;
Ref<Binarizer> createBinarizer(Ref<LuminanceSource> source) override;
private:
int binarizeImage(ErrorHandler& err_handler);
int TransBufferToMat(unsigned char* pBuffer, cv::Mat& mDst, int nWidth, int nHeight);
int TransMatToBuffer(cv::Mat mSrc, unsigned char* ppBuffer, int& nWidth, int& nHeight);
};
} // namespace zxing
#endif // __ZXING_COMMON_ADAPTIVE_THRESHOLD_MEAN_BINARIZER_HPP__
@@ -0,0 +1,285 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#include "../../../precomp.hpp"
#include "fast_window_binarizer.hpp"
using zxing::FastWindowBinarizer;
namespace {
const int BLOCK_SIZE = 6;
// const int BLOCK_SIZE = 8; // not as good as BLOCK_SIZE = 6
const float WINDOW_FRACTION = 0.13f;
static int min(int a, int b) { return a < b ? a : b; }
static int max(int a, int b) { return a > b ? a : b; }
} // namespace
FastWindowBinarizer::FastWindowBinarizer(Ref<LuminanceSource> source)
: GlobalHistogramBinarizer(source), matrix_(NULL), cached_row_(NULL) {
width = source->getWidth();
height = source->getHeight();
int aw = width / BLOCK_SIZE;
int ah = height / BLOCK_SIZE;
int ah2 = ah;
int ow2 = aw + 1;
_luminancesInt = new int[width * height];
_blockTotals = new int[ah * aw];
_totals = new int[(ah + 1) * (aw + 1)];
_rowTotals = new int[ah2 * ow2];
_internal = new unsigned int[(height + 1) * (width + 1)];
}
FastWindowBinarizer::~FastWindowBinarizer() {
delete[] _totals;
delete[] _blockTotals;
delete[] _luminancesInt;
delete[] _rowTotals;
delete[] _internal;
}
Ref<Binarizer> FastWindowBinarizer::createBinarizer(Ref<LuminanceSource> source) {
return Ref<Binarizer>(new FastWindowBinarizer(source));
}
/**
* Calculates the final BitMatrix once for all requests. This could be called
* once from the constructor instead, but there are some advantages to doing it
* lazily, such as making profiling easier, and not doing heavy lifting when
* callers don't expect it.
*/
Ref<BitMatrix> FastWindowBinarizer::getBlackMatrix(ErrorHandler& err_handler) {
if (!matrix0_) {
binarizeImage1(err_handler);
if (err_handler.ErrCode()) return Ref<BitMatrix>();
}
return Binarizer::getBlackMatrix(err_handler);
}
/**
* Calculate black row from BitMatrix
* If BitMatrix has been calculated then just get the row
* If BitMatrix has not been calculated then call getBlackMatrix first
*/
Ref<BitArray> FastWindowBinarizer::getBlackRow(int y, Ref<BitArray> row,
ErrorHandler& err_handler) {
if (!matrix0_) {
binarizeImage1(err_handler);
if (err_handler.ErrCode()) return Ref<BitArray>();
}
// Call parent getBlackMatrix to get current matrix
return Binarizer::getBlackRow(y, row, err_handler);
}
void FastWindowBinarizer::calcBlockTotals(int* luminancesInt, int* output, int aw, int ah) {
for (int by = 0; by < ah; by++) {
int ey = (by + 1) * BLOCK_SIZE;
for (int bx = 0; bx < aw; bx++) {
int t = 0;
for (int y = by * BLOCK_SIZE; y < ey; y++) {
int offset = y * width + bx * BLOCK_SIZE;
int ex = offset + BLOCK_SIZE;
for (; offset < ex; offset++) {
// int v = luminancesInt[offset] & 0xff;
t += luminancesInt[offset];
}
}
output[by * aw + bx] = t;
}
}
}
void FastWindowBinarizer::cumulative(int* data, int* output, int _width, int _height) {
int ah = _height;
int aw = _width;
int ow = _width + 1;
// int[][] totals = new int[ah + 1][aw + 1];
// int* rowTotals = new int[ah*ow];
for (int y = 0; y < ah; y++) {
int* row = _rowTotals + (y * ow);
int* rowdata = data + (y * aw);
int t = 0;
row[0] = t;
for (int x = 0; x < aw; x++) {
t += rowdata[x];
row[x + 1] = t;
}
}
for (int x = 0; x <= aw; x++) {
output[x] = 0; // First row
int t = 0;
for (int y = 0; y < ah; y++) {
t += _rowTotals[y * ow + x];
output[(y + 1) * ow + x] = t;
}
}
}
void FastWindowBinarizer::fastIntegral(const unsigned char* inputMatrix,
unsigned int* outputMatrix) {
// memset(outputMatrix,0,sizeof(int)*(height+1)*(width+1));
// unsigned int *columnSum = new unsigned int[width]; // sum of each column
// calculate integral of the first line
outputMatrix[0] = outputMatrix[width + 1] = 0;
for (int i = 0; i < width; i++) {
// columnSum[i]=inputMatrix[i];
outputMatrix[i + 1] = 0;
outputMatrix[width + 1 + i + 1] = outputMatrix[width + 1 + i] + inputMatrix[i];
}
for (int i = 1; i < height; i++) {
const unsigned char* psi = inputMatrix + i * width;
unsigned int* pdi = outputMatrix + (i + 1) * (width + 1);
// first column of each line
pdi[0] = 0;
pdi[1] = psi[0];
int row_sum = psi[0];
// other columns
for (int j = 1; j < width; j++) {
row_sum += psi[j];
pdi[j + 1] = pdi[j + 1 - width - 1] + row_sum;
}
}
return;
}
int FastWindowBinarizer::binarizeImage1(ErrorHandler& err_handler) {
LuminanceSource& source = *getLuminanceSource();
Ref<BitMatrix> matrix(new BitMatrix(width, height, err_handler));
if (err_handler.ErrCode()) return -1;
ArrayRef<char> localLuminances = source.getMatrix();
unsigned char* src = (unsigned char*)localLuminances->data();
unsigned char* dst = matrix->getPtr();
fastWindow(src, dst, err_handler);
if (err_handler.ErrCode()) return -1;
matrix0_ = matrix;
return 0;
}
void FastWindowBinarizer::fastWindow(const unsigned char* src, unsigned char* dst,
ErrorHandler& err_handler) {
int r = (int)(min(width, height) * WINDOW_FRACTION / BLOCK_SIZE / 2 + 1);
const int NEWH_BLOCK_SIZE = BLOCK_SIZE * r;
if (height < NEWH_BLOCK_SIZE || width < NEWH_BLOCK_SIZE) {
matrix_ = GlobalHistogramBinarizer::getBlackMatrix(err_handler);
return;
}
const unsigned char* _img = src;
fastIntegral(_img, _internal);
int aw = width / BLOCK_SIZE;
int ah = height / BLOCK_SIZE;
memset(dst, 0, sizeof(char) * height * width);
for (int ai = 0; ai < ah; ai++) {
int top = max(0, ((ai - r + 1) * BLOCK_SIZE));
int bottom = min(height, (ai + r) * BLOCK_SIZE);
unsigned int* pt = _internal + top * (width + 1);
unsigned int* pb = _internal + bottom * (width + 1);
for (int aj = 0; aj < aw; aj++) {
int left = max(0, (aj - r + 1) * BLOCK_SIZE);
int right = min(width, (aj + r) * BLOCK_SIZE);
unsigned int block = pb[right] + pt[left] - pt[right] - pb[left];
int pixels = (bottom - top) * (right - left);
int avg = (int)block / pixels;
for (int bi = ai * BLOCK_SIZE; bi < height && bi < (ai + 1) * BLOCK_SIZE; bi++) {
const unsigned char* psi = src + bi * width;
unsigned char* pdi = dst + bi * width;
for (int bj = aj * BLOCK_SIZE; bj < width && bj < (aj + 1) * BLOCK_SIZE; bj++) {
if ((int)psi[bj] < avg)
pdi[bj] = 1;
else
pdi[bj] = 0;
}
}
}
}
// delete [] _internal;
return;
}
int FastWindowBinarizer::binarizeImage0(ErrorHandler& err_handler) {
// if (matrix_) {
// return matrix_;
//}
LuminanceSource& source = *getLuminanceSource();
if (width >= BLOCK_SIZE && height >= BLOCK_SIZE) {
int r = (int)(min(width, height) * WINDOW_FRACTION / BLOCK_SIZE / 2 + 1);
int aw = width / BLOCK_SIZE;
int ah = height / BLOCK_SIZE;
int ow = aw + 1;
ArrayRef<char> _luminances = source.getMatrix();
// Get luminances for int value first
for (int i = 0; i < width * height; i++) {
_luminancesInt[i] = _luminances[i] & 0xff;
}
calcBlockTotals(_luminancesInt, _blockTotals, aw, ah);
cumulative(_blockTotals, _totals, aw, ah);
Ref<BitMatrix> newMatrix(new BitMatrix(width, height, err_handler));
if (err_handler.ErrCode()) return -1;
unsigned char* newimg = newMatrix->getPtr();
for (int by = 0; by < ah; by++) {
int top = max(0, by - r + 1);
int bottom = min(ah, by + r);
for (int bx = 0; bx < aw; bx++) {
int left = max(0, bx - r + 1);
int right = min(aw, bx + r);
int block = _totals[bottom * ow + right] + _totals[top * ow + left] -
_totals[top * ow + right] - _totals[bottom * ow + left];
int pixels = (bottom - top) * (right - left) * BLOCK_SIZE * BLOCK_SIZE;
int avg = block / pixels;
for (int y = by * BLOCK_SIZE; y < (by + 1) * BLOCK_SIZE; y++) {
// int offset = y*width;
int* plumint = _luminancesInt + y * width;
unsigned char* pn = newimg + y * width;
for (int x = bx * BLOCK_SIZE; x < (bx + 1) * BLOCK_SIZE; x++) {
// int pixel = luminances[y*width + x] & 0xff;
// if(plumint[x] < avg)
// newMatrix->set(x, y);
if (plumint[x] < avg)
pn[x] = 1;
else
pn[x] = 0;
}
}
}
}
// delete[] data;
matrix_ = newMatrix;
} else {
// If the image is too small, fall back to the global histogram
// approach.
matrix_ = GlobalHistogramBinarizer::getBlackMatrix(err_handler);
}
return 0;
}
@@ -0,0 +1,56 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#ifndef __ZXING_COMMON_DETECTOR_RESULT_HPP__
#define __ZXING_COMMON_DETECTOR_RESULT_HPP__
#include "../../binarizer.hpp"
#include "../../errorhandler.hpp"
#include "../bitarray.hpp"
#include "../bitmatrix.hpp"
#include "global_histogram_binarizer.hpp"
#include <vector>
namespace zxing {
class FastWindowBinarizer : public GlobalHistogramBinarizer {
private:
Ref<BitMatrix> matrix_;
Ref<BitArray> cached_row_;
int* _luminancesInt;
int* _blockTotals;
int* _totals;
int* _rowTotals;
unsigned int* _internal;
public:
explicit FastWindowBinarizer(Ref<LuminanceSource> source);
virtual ~FastWindowBinarizer();
virtual Ref<BitMatrix> getBlackMatrix(ErrorHandler& err_handler) override;
virtual Ref<BitArray> getBlackRow(int y, Ref<BitArray> row, ErrorHandler& err_handler) override;
Ref<Binarizer> createBinarizer(Ref<LuminanceSource> source) override;
private:
void calcBlockTotals(int* luminancesInt, int* output, int aw, int ah);
void cumulative(int* data, int* output, int _width, int _height);
int binarizeImage0(ErrorHandler& err_handler);
void fastIntegral(const unsigned char* inputMatrix, unsigned int* outputMatrix);
int binarizeImage1(ErrorHandler& err_handler);
void fastWindow(const unsigned char* src, unsigned char* dst, ErrorHandler& err_handler);
};
} // namespace zxing
#endif // __ZXING_COMMON_DETECTOR_RESULT_HPP__
@@ -0,0 +1,308 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#include "../../../precomp.hpp"
#include "global_histogram_binarizer.hpp"
using zxing::GlobalHistogramBinarizer;
namespace {
const int LUMINANCE_BITS = 5;
const int LUMINANCE_SHIFT = 8 - LUMINANCE_BITS;
const int LUMINANCE_BUCKETS = 1 << LUMINANCE_BITS;
const ArrayRef<char> EMPTY(0);
} // namespace
GlobalHistogramBinarizer::GlobalHistogramBinarizer(Ref<LuminanceSource> source)
: Binarizer(source), luminances(EMPTY), buckets(LUMINANCE_BUCKETS) {
filtered = false;
}
GlobalHistogramBinarizer::~GlobalHistogramBinarizer() {}
void GlobalHistogramBinarizer::initArrays(int luminanceSize) {
if (luminances->size() < luminanceSize) {
luminances = ArrayRef<char>(luminanceSize);
}
for (int x = 0; x < LUMINANCE_BUCKETS; x++) {
buckets[x] = 0;
}
}
// Applies simple sharpening to the row data to improve performance of the 1D
// readers.
Ref<BitArray> GlobalHistogramBinarizer::getBlackRow(int y, Ref<BitArray> row,
ErrorHandler& err_handler) {
// First call binarize image in child class to get matrix0_ and binCache
if (!matrix0_) {
binarizeImage0(err_handler);
if (err_handler.ErrCode()) return Ref<BitArray>();
}
// Call parent getBlackMatrix to get current matrix
return Binarizer::getBlackRow(y, row, err_handler);
}
// Does not sharpen the data, as this call is intended to only be used by 2D
// readers.
Ref<BitMatrix> GlobalHistogramBinarizer::getBlackMatrix(ErrorHandler& err_handler) {
binarizeImage0(err_handler);
if (err_handler.ErrCode()) return Ref<BitMatrix>();
// First call binarize image in child class to get matrix0_ and binCache
// Call parent getBlackMatrix to get current matrix
return Binarizer::getBlackMatrix(err_handler);
}
using namespace std;
int GlobalHistogramBinarizer::estimateBlackPoint(ArrayRef<int> const& _buckets,
ErrorHandler& err_handler) {
// Find tallest peak in histogram
int numBuckets = _buckets->size();
int maxBucketCount = 0;
int firstPeak = 0;
int firstPeakSize = 0;
for (int x = 0; x < numBuckets; x++) {
if (_buckets[x] > firstPeakSize) {
firstPeak = x;
firstPeakSize = _buckets[x];
}
if (_buckets[x] > maxBucketCount) {
maxBucketCount = _buckets[x];
}
}
// Find second-tallest peak -- well, another peak that is tall and not
// so close to the first one
int secondPeak = 0;
int secondPeakScore = 0;
for (int x = 0; x < numBuckets; x++) {
int distanceToBiggest = x - firstPeak;
// Encourage more distant second peaks by multiplying by square of
// distance
int score = _buckets[x] * distanceToBiggest * distanceToBiggest;
if (score > secondPeakScore) {
secondPeak = x;
secondPeakScore = score;
}
}
// Make sure firstPeak corresponds to the black peak.
if (firstPeak > secondPeak) {
int temp = firstPeak;
firstPeak = secondPeak;
secondPeak = temp;
}
// Kind of arbitrary; if the two peaks are very close, then we figure there
// is so little dynamic range in the image, that discriminating black and
// white is too error-prone. Decoding the image/line is either pointless, or
// may in some cases lead to a false positive for 1D formats, which are
// relatively lenient. We arbitrarily say "close" is "<= 1/16 of the total
// histogram buckets apart" std::cerr << "! " << secondPeak << " " <<
// firstPeak << " " << numBuckets << std::endl;
if (secondPeak - firstPeak <= numBuckets >> 4) {
err_handler = NotFoundErrorHandler("NotFound GlobalHistogramBinarizer");
return -1;
}
// Find a valley between them that is low and closer to the white peak
int bestValley = secondPeak - 1;
int bestValleyScore = -1;
for (int x = secondPeak - 1; x > firstPeak; x--) {
int fromFirst = x - firstPeak;
// Favor a "valley" that is not too close to either peak -- especially
// not the black peak -- and that has a low value of course
int score = fromFirst * fromFirst * (secondPeak - x) * (maxBucketCount - buckets[x]);
if (score > bestValleyScore) {
bestValley = x;
bestValleyScore = score;
}
}
// std::cerr << "bps " << (bestValley << LUMINANCE_SHIFT) << std::endl;
return bestValley << LUMINANCE_SHIFT;
}
// codes from sagazhou, only works well on one dataset
int GlobalHistogramBinarizer::estimateBlackPoint2(ArrayRef<int> const& _buckets) {
int midValue = LUMINANCE_BUCKETS / 2 + 1;
// Find tallest and lowest peaks in histogram
// const int numBuckets = buckets->size();
int maxPointArray[LUMINANCE_BUCKETS] = {0};
int maxCrusor = 0;
int maxValue = 0, maxIndex = 0;
int minPointArray[LUMINANCE_BUCKETS] = {0};
int minCrusor = 0;
for (int i = 2; i < LUMINANCE_BUCKETS - 3; i++) {
if (_buckets[i] < _buckets[i + 1] && _buckets[i] < _buckets[i + 2] &&
_buckets[i] < _buckets[i - 1] && _buckets[i] < _buckets[i - 2]) {
minPointArray[minCrusor++] = i;
} else if (_buckets[i] > _buckets[i + 1] && _buckets[i] > _buckets[i + 2] &&
_buckets[i] > _buckets[i - 1] && _buckets[i] > _buckets[i - 2]) {
maxPointArray[maxCrusor++] = i;
if (_buckets[i] > maxValue) {
maxValue = _buckets[i];
maxIndex = i;
}
}
}
bool bSlantBlack = true;
// most pixels are black
for (int i = 0; i < maxCrusor; ++i) {
if (maxPointArray[i] > midValue) {
bSlantBlack = false;
break;
}
}
bool bSlantWhite = true;
// most pixels are white
for (int i = 0; i < maxCrusor; ++i) {
if (maxPointArray[i] < midValue) {
bSlantWhite = false;
break;
}
}
if (bSlantBlack) {
int start = maxIndex + 30;
int end = midValue;
if (minCrusor == 0) // unimodal
{
return 255;
} else {
int mostLeftIndex = 0;
bool bFind = false;
for (int i = 0; i < minCrusor; ++i) // wave motion
{
if (minPointArray[i] > start && minPointArray[i] < end) {
mostLeftIndex = minPointArray[i];
bFind = true;
break;
}
}
if (bFind) {
return mostLeftIndex;
} else {
return 255;
}
}
}
if (bSlantWhite) {
int start = midValue;
int end = maxIndex - 30;
if (minCrusor == 0) // unimodal
{
return 0;
} else {
int mostRightIndex = 0;
bool bFind = false;
for (int i = 0; i < minCrusor; ++i) // wave motion
{
if (minPointArray[i] > start && minPointArray[i] < end) {
mostRightIndex = i;
bFind = true;
}
}
if (bFind) {
return mostRightIndex;
} else {
return 0;
}
}
}
// balanced distribution
if (maxIndex < midValue) {
// the minest min value
if (minCrusor == 0) {
return 255; // all black
} else {
int start = maxIndex + 30;
int end = 253;
for (int i = 0; i < minCrusor; ++i) // wave motion
{
if (minPointArray[i] > start && minPointArray[i] < end) {
return minPointArray[i];
}
}
}
} else {
// maxest min value
if (minCrusor == 0) {
return 0; // white
} else {
int start = 0;
int end = maxIndex - 30;
int mostRightIndex = 0;
for (int i = 0; i < minCrusor; ++i) // wave motion
{
if (minPointArray[i] > start && minPointArray[i] < end) {
mostRightIndex = minPointArray[i];
}
}
return mostRightIndex;
}
}
return 0;
}
int GlobalHistogramBinarizer::binarizeImage0(ErrorHandler& err_handler) {
LuminanceSource& source = *getLuminanceSource();
Ref<BitMatrix> matrix(new BitMatrix(width, height, err_handler));
if (err_handler.ErrCode()) return -1;
// Quickly calculates the histogram by sampling four rows from the image.
// This proved to be more robust on the blackbox tests than sampling a
// diagonal as we used to do.
initArrays(width);
ArrayRef<int> localBuckets = buckets;
for (int y = 1; y < 5; y++) {
int row = height * y / 5;
ArrayRef<char> localLuminances = source.getRow(row, luminances, err_handler);
if (err_handler.ErrCode()) return -1;
int right = (width << 2) / 5;
for (int x = width / 5; x < right; x++) {
int pixel = localLuminances[x] & 0xff;
localBuckets[pixel >> LUMINANCE_SHIFT]++;
}
}
int blackPoint = estimateBlackPoint(localBuckets, err_handler);
if (err_handler.ErrCode()) return -1;
ArrayRef<char> localLuminances = source.getMatrix();
for (int y = 0; y < height; y++) {
int offset = y * width;
for (int x = 0; x < width; x++) {
int pixel = localLuminances[offset + x] & 0xff;
if (pixel < blackPoint) {
matrix->set(x, y);
}
}
}
matrix0_ = matrix;
return 0;
}
Ref<Binarizer> GlobalHistogramBinarizer::createBinarizer(Ref<LuminanceSource> source) {
return Ref<Binarizer>(new GlobalHistogramBinarizer(source));
}
@@ -0,0 +1,55 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#ifndef __ZXING_COMMON_GLOBAL_HISTOGRAM_BINARIZER_HPP__
#define __ZXING_COMMON_GLOBAL_HISTOGRAM_BINARIZER_HPP__
#include "../../binarizer.hpp"
#include "../../errorhandler.hpp"
#include "../array.hpp"
#include "../bitarray.hpp"
#include "../bitmatrix.hpp"
#include "../bytematrix.hpp"
using zxing::ArrayRef;
using zxing::Binarizer;
using zxing::BitArray;
using zxing::BitMatrix;
using zxing::ByteMatrix;
using zxing::ErrorHandler;
using zxing::LuminanceSource;
using zxing::Ref;
namespace zxing {
class GlobalHistogramBinarizer : public Binarizer {
protected:
ArrayRef<char> luminances;
ArrayRef<int> buckets;
public:
explicit GlobalHistogramBinarizer(Ref<LuminanceSource> source);
virtual ~GlobalHistogramBinarizer();
virtual Ref<BitArray> getBlackRow(int y, Ref<BitArray> row, ErrorHandler &err_handler) override;
virtual Ref<BitMatrix> getBlackMatrix(ErrorHandler &err_handler) override;
int estimateBlackPoint(ArrayRef<int> const &buckets, ErrorHandler &err_handler);
int estimateBlackPoint2(ArrayRef<int> const &buckets);
Ref<Binarizer> createBinarizer(Ref<LuminanceSource> source) override;
private:
int binarizeImage0(ErrorHandler &err_handler);
void initArrays(int luminanceSize);
bool filtered;
};
} // namespace zxing
#endif // __ZXING_COMMON_GLOBAL_HISTOGRAM_BINARIZER_HPP__
@@ -0,0 +1,419 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#include "../../../precomp.hpp"
#include "hybrid_binarizer.hpp"
using zxing::HybridBinarizer;
using zxing::BINARIZER_BLOCK;
// This class uses 5*5 blocks to compute local luminance, where each block is
// 8*8 pixels So this is the smallest dimension in each axis we can accept.
namespace {
const int BLOCK_SIZE_POWER = 3;
const int BLOCK_SIZE = 1 << BLOCK_SIZE_POWER; // ...0100...00
const int BLOCK_SIZE_MASK = BLOCK_SIZE - 1; // ...0011...11
const int MINIMUM_DIMENSION = BLOCK_SIZE * 5;
#ifdef USE_SET_INT
const int BITS_PER_BYTE = 8;
const int BITS_PER_WORD = BitMatrix::bitsPerWord;
#endif
} // namespace
HybridBinarizer::HybridBinarizer(Ref<LuminanceSource> source) : GlobalHistogramBinarizer(source) {
int subWidth = width >> BLOCK_SIZE_POWER;
if ((width & BLOCK_SIZE_MASK) != 0) {
subWidth++;
}
int subHeight = height >> BLOCK_SIZE_POWER;
if ((height & BLOCK_SIZE_MASK) != 0) {
subHeight++;
}
grayByte_ = source->getByteMatrix();
blocks_ = getBlockArray(subWidth * subHeight);
subWidth_ = subWidth;
subHeight_ = subHeight;
initBlocks();
initBlockIntegral();
}
HybridBinarizer::~HybridBinarizer() {
}
Ref<Binarizer> HybridBinarizer::createBinarizer(Ref<LuminanceSource> source) {
return Ref<Binarizer>(new GlobalHistogramBinarizer(source));
}
int HybridBinarizer::initBlockIntegral() {
blockIntegralWidth = subWidth_ + 1;
blockIntegralHeight = subHeight_ + 1;
blockIntegral_ = new Array<int>(blockIntegralWidth * blockIntegralHeight);
int* integral = blockIntegral_->data();
// unsigned char* therow = grayByte_->getByteRow(0);
// first row only
int rs = 0;
for (int j = 0; j < blockIntegralWidth; j++) {
integral[j] = 0;
}
for (int i = 0; i < blockIntegralHeight; i++) {
integral[i * blockIntegralWidth] = 0;
}
// remaining cells are sum above and to the left
int offsetBlock = 0;
int offsetIntegral = 0;
for (int i = 0; i < subHeight_; ++i) {
// therow = grayByte_->getByteRow(i);
offsetBlock = i * subWidth_;
offsetIntegral = (i + 1) * blockIntegralWidth;
rs = 0;
for (int j = 0; j < subWidth_; ++j) {
rs += blocks_[offsetBlock + j].threshold;
integral[offsetIntegral + j + 1] = rs + integral[offsetIntegral - blockIntegralWidth + j + 1];
}
}
return 1;
}
/**
* Calculates the final BitMatrix once for all requests. This could be called
* once from the constructor instead, but there are some advantages to doing it
* lazily, such as making profiling easier, and not doing heavy lifting when
* callers don't expect it.
*/
Ref<BitMatrix> HybridBinarizer::getBlackMatrix(ErrorHandler& err_handler) {
// First call binarize image in child class to get matrix0_ and binCache
if (!matrix0_) {
binarizeByBlock(err_handler);
if (err_handler.ErrCode()) return Ref<BitMatrix>();
}
// First call binarize image in child class to get matrix0_ and binCache
// Call parent getBlackMatrix to get current matrix
return Binarizer::getBlackMatrix(err_handler);
}
#if 1
/**
* Calculate black row from BitMatrix
* If BitMatrix has been calculated then just get the row
* If BitMatrix has not been calculated then call getBlackMatrix first
*/
Ref<BitArray> HybridBinarizer::getBlackRow(int y, Ref<BitArray> row, ErrorHandler& err_handler) {
// First call binarize image in child class to get matrix0_ and binCache
if (!matrix0_) {
binarizeByBlock(err_handler);
if (err_handler.ErrCode()) return Ref<BitArray>();
}
// Call parent getBlackMatrix to get current matrix
return Binarizer::getBlackRow(y, row, err_handler);
}
#endif
namespace {
inline int cap(int value, int min, int max) {
return value < min ? min : value > max ? max : value;
}
} // namespace
// For each block in the image, calculates the average black point using a 5*5
// grid of the blocks around it. Also handles the corner cases (fractional
// blocks are computed based on the last pixels in the row/column which are also
// used in the previous block.)
#define THRES_BLOCKSIZE 2
// No use of level now
ArrayRef<int> HybridBinarizer::getBlackPoints() {
int blackWidth, blackHeight;
blackWidth = subWidth_;
blackHeight = subHeight_;
ArrayRef<int> blackPoints(blackWidth * blackHeight);
int* blackArray = blackPoints->data();
int offset = 0;
for (int i = 0; i < blackHeight; i++) {
offset = i * blackWidth;
for (int j = 0; j < blackWidth; j++) {
blackArray[offset + j] = blocks_[offset + j].threshold;
}
}
return blackPoints;
}
// Original code 20140606
void HybridBinarizer::calculateThresholdForBlock(Ref<ByteMatrix>& _luminances, int subWidth,
int subHeight, int SIZE_POWER,
// ArrayRef<int> &blackPoints,
Ref<BitMatrix> const& matrix,
ErrorHandler& err_handler) {
int block_size = 1 << SIZE_POWER;
int maxYOffset = height - block_size;
int maxXOffset = width - block_size;
int* blockIntegral = blockIntegral_->data();
int blockArea = ((2 * THRES_BLOCKSIZE + 1) * (2 * THRES_BLOCKSIZE + 1));
for (int y = 0; y < subHeight; y++) {
int yoffset = y << SIZE_POWER;
if (yoffset > maxYOffset) {
yoffset = maxYOffset;
}
for (int x = 0; x < subWidth; x++) {
int xoffset = x << SIZE_POWER;
if (xoffset > maxXOffset) {
xoffset = maxXOffset;
}
int left = cap(x, THRES_BLOCKSIZE, subWidth - THRES_BLOCKSIZE - 1);
int top = cap(y, THRES_BLOCKSIZE, subHeight - THRES_BLOCKSIZE - 1);
int sum = 0;
// int sum2 = 0;
int offset1 = (top - THRES_BLOCKSIZE) * blockIntegralWidth + left - THRES_BLOCKSIZE;
int offset2 = (top + THRES_BLOCKSIZE + 1) * blockIntegralWidth + left - THRES_BLOCKSIZE;
int blocksize = THRES_BLOCKSIZE * 2 + 1;
sum = blockIntegral[offset1] - blockIntegral[offset1 + blocksize] -
blockIntegral[offset2] + blockIntegral[offset2 + blocksize];
int average = sum / blockArea;
thresholdBlock(_luminances, xoffset, yoffset, average, matrix, err_handler);
if (err_handler.ErrCode()) return;
}
}
}
#ifdef USE_SET_INT
void HybridBinarizer::thresholdFourBlocks(Ref<ByteMatrix>& luminances, int xoffset, int yoffset,
int* thresholds, int stride,
Ref<BitMatrix> const& matrix) {
int setIntCircle = BITS_PER_WORD / BITS_PER_BYTE;
for (int y = 0; y < BLOCK_SIZE; y++) {
unsigned char* pTemp = luminances->getByteRow(yoffset + y);
pTemp = pTemp + xoffset;
unsigned int valueInt = 0;
int bitPosition = 0;
for (int k = 0; k < setIntCircle; k++) {
for (int x = 0; x < BLOCK_SIZE; x++) {
int pixel = *pTemp++;
if (pixel <= thresholds[k]) {
// bitPosition=(3-k)*8+x;
valueInt |= (unsigned int)1 << bitPosition;
}
bitPosition++;
}
}
matrix->setIntOneTime(xoffset, yoffset + y, valueInt);
}
return;
}
#endif
// Applies a single threshold to a block of pixels
void HybridBinarizer::thresholdBlock(Ref<ByteMatrix>& _luminances, int xoffset, int yoffset,
int threshold, Ref<BitMatrix> const& matrix,
ErrorHandler& err_handler) {
int rowBitsSize = matrix->getRowBitsSize();
int rowSize = width;
int rowBitStep = rowBitsSize - BLOCK_SIZE;
int rowStep = rowSize - BLOCK_SIZE;
unsigned char* pTemp = _luminances->getByteRow(yoffset, err_handler);
if (err_handler.ErrCode()) return;
bool* bpTemp = matrix->getRowBoolPtr(yoffset);
pTemp += xoffset;
bpTemp += xoffset;
for (int y = 0; y < BLOCK_SIZE; y++) {
for (int x = 0; x < BLOCK_SIZE; x++) {
// comparison needs to be <= so that black == 0 pixels are black
// even if the threshold is 0.
*bpTemp++ = (*pTemp++ <= threshold) ? true : false;
}
pTemp += rowBitStep;
bpTemp += rowStep;
}
}
void HybridBinarizer::thresholdIrregularBlock(Ref<ByteMatrix>& _luminances, int xoffset,
int yoffset, int blockWidth, int blockHeight,
int threshold, Ref<BitMatrix> const& matrix,
ErrorHandler& err_handler) {
for (int y = 0; y < blockHeight; y++) {
unsigned char* pTemp = _luminances->getByteRow(yoffset + y, err_handler);
if (err_handler.ErrCode()) return;
pTemp = pTemp + xoffset;
for (int x = 0; x < blockWidth; x++) {
// comparison needs to be <= so that black == 0 pixels are black
// even if the threshold is 0.
int pixel = *pTemp++;
if (pixel <= threshold) {
matrix->set(xoffset + x, yoffset + y);
}
}
}
}
namespace {
inline int getBlackPointFromNeighbors(ArrayRef<BINARIZER_BLOCK> block, int subWidth, int x, int y) {
return (block[(y - 1) * subWidth + x].threshold + 2 * block[y * subWidth + x - 1].threshold +
block[(y - 1) * subWidth + x - 1].threshold) >>
2;
}
} // namespace
#define MIN_DYNAMIC_RANGE 24
// Calculates a single black point for each block of pixels and saves it away.
int HybridBinarizer::initBlocks() {
Ref<ByteMatrix>& _luminances = grayByte_;
int subWidth = subWidth_;
int subHeight = subHeight_;
unsigned char* bytes = _luminances->bytes;
const int minDynamicRange = 24;
for (int y = 0; y < subHeight; y++) {
int yoffset = y << BLOCK_SIZE_POWER;
int maxYOffset = height - BLOCK_SIZE;
if (yoffset > maxYOffset) yoffset = maxYOffset;
for (int x = 0; x < subWidth; x++) {
int xoffset = x << BLOCK_SIZE_POWER;
int maxXOffset = width - BLOCK_SIZE;
if (xoffset > maxXOffset) xoffset = maxXOffset;
int sum = 0;
int min = 0xFF;
int max = 0;
for (int yy = 0, offset = yoffset * width + xoffset; yy < BLOCK_SIZE;
yy++, offset += width) {
for (int xx = 0; xx < BLOCK_SIZE; xx++) {
// int pixel = luminances->bytes[offset + xx] & 0xFF;
int pixel = bytes[offset + xx];
sum += pixel;
// still looking for good contrast
if (pixel < min) {
min = pixel;
}
if (pixel > max) {
max = pixel;
}
}
// short-circuit min/max tests once dynamic range is met
if (max - min > minDynamicRange) {
// finish the rest of the rows quickly
for (yy++, offset += width; yy < BLOCK_SIZE; yy++, offset += width) {
for (int xx = 0; xx < BLOCK_SIZE; xx += 2) {
sum += bytes[offset + xx];
sum += bytes[offset + xx + 1];
}
}
}
}
blocks_[y * subWidth + x].min = min;
blocks_[y * subWidth + x].max = max;
blocks_[y * subWidth + x].sum = sum;
blocks_[y * subWidth + x].threshold =
getBlockThreshold(x, y, subWidth, sum, min, max, minDynamicRange, BLOCK_SIZE_POWER);
}
}
return 1;
}
int HybridBinarizer::getBlockThreshold(int x, int y, int subWidth, int sum, int min, int max,
int minDynamicRange, int SIZE_POWER) {
// See
// http://groups.google.com/group/zxing/browse_thread/thread/d06efa2c35a7ddc0
// The default estimate is the average of the values in the block.
int average = sum >> (SIZE_POWER * 2);
if (max - min <= minDynamicRange) {
// If variation within the block is low, assume this is a block withe
// only light or only dark pixels. In that case we do not want to use
// the average, as it would divide this low contrast area into black and
// white pixels, essentially creating data out of noise. The default
// assumption is that the block is light/background. Since no estimate
// for the level of dark pixels exists locally, use half the min for the
// block.
average = min >> 1;
if (y > 0 && x > 0) {
// Correct the "white background" assumption for blocks that have
// neighbors by comparing the pixels in this block to the previously
// calculated black points. This is based on the fact that dark
// barcode symbology is always surrounded by some amout of light
// background for which reasonable black point estimates were made.
// The bp estimated at the boundaries is used for the interior.
int bp = getBlackPointFromNeighbors(blocks_, subWidth, x, y);
// The (min<bp) is arbitrary but works better than other heuristics
// that were tried.
if (min < bp) {
average = bp;
}
}
}
// blocks_[y * subWidth + x].average = average;
// blocks_[y * subWidth + x].threshold = average;
return average;
}
int HybridBinarizer::binarizeByBlock(ErrorHandler& err_handler) {
if (width >= MINIMUM_DIMENSION && height >= MINIMUM_DIMENSION) {
Ref<BitMatrix> newMatrix(new BitMatrix(width, height, err_handler));
if (err_handler.ErrCode()) return -1;
calculateThresholdForBlock(grayByte_, subWidth_, subHeight_, BLOCK_SIZE_POWER, newMatrix,
err_handler);
if (err_handler.ErrCode()) return -1;
matrix0_ = newMatrix;
} else {
// If the image is too small, fall back to the global histogram
// approach.
matrix0_ = GlobalHistogramBinarizer::getBlackMatrix(err_handler);
if (err_handler.ErrCode()) return 1;
}
// return matrix0_;
return 1;
}
@@ -0,0 +1,85 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#ifndef __ZXING_COMMON_HYBRID_BINARIZER_HPP__
#define __ZXING_COMMON_HYBRID_BINARIZER_HPP__
#include "../../binarizer.hpp"
#include "../../errorhandler.hpp"
#include "../bitarray.hpp"
#include "../bitmatrix.hpp"
#include "../bytematrix.hpp"
#include "global_histogram_binarizer.hpp"
#include <vector>
namespace zxing {
class HybridBinarizer : public GlobalHistogramBinarizer {
private:
Ref<ByteMatrix> grayByte_;
// ArrayRef<int> integral_;
ArrayRef<int> blockIntegral_;
ArrayRef<BINARIZER_BLOCK> blocks_;
ArrayRef<int> blackPoints_;
int level_;
int subWidth_;
int subHeight_;
int blockIntegralWidth;
int blockIntegralHeight;
public:
explicit HybridBinarizer(Ref<LuminanceSource> source);
virtual ~HybridBinarizer();
virtual Ref<BitMatrix> getBlackMatrix(ErrorHandler& err_handler) override;
virtual Ref<BitArray> getBlackRow(int y, Ref<BitArray> row, ErrorHandler& err_handler) override;
Ref<Binarizer> createBinarizer(Ref<LuminanceSource> source) override;
private:
int initIntegral();
int initBlockIntegral();
int initBlocks();
// int calculateBlackPoints();
ArrayRef<int> getBlackPoints();
int getBlockThreshold(int x, int y, int subWidth, int sum, int min, int max,
int minDynamicRange, int SIZE_POWER);
void calculateThresholdForBlock(Ref<ByteMatrix>& luminances, int subWidth, int subHeight,
int SIZE_POWER, Ref<BitMatrix> const& matrix,
ErrorHandler& err_handler);
void thresholdBlock(Ref<ByteMatrix>& luminances, int xoffset, int yoffset, int threshold,
Ref<BitMatrix> const& matrix, ErrorHandler& err_handler);
void thresholdIrregularBlock(Ref<ByteMatrix>& luminances, int xoffset, int yoffset,
int blockWidth, int blockHeight, int threshold,
Ref<BitMatrix> const& matrix, ErrorHandler& err_handler);
#ifdef USE_SET_INT
void thresholdFourBlocks(Ref<ByteMatrix>& luminances, int xoffset, int yoffset, int* thresholds,
int stride, Ref<BitMatrix> const& matrix);
#endif
// Add for binarize image when call getBlackMatrix
// By Skylook
int binarizeByBlock(ErrorHandler& err_handler);
};
} // namespace zxing
#endif // __ZXING_COMMON_HYBRID_BINARIZER_HPP__
@@ -0,0 +1,155 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#include "../../../precomp.hpp"
#include "simple_adaptive_binarizer.hpp"
using zxing::SimpleAdaptiveBinarizer;
SimpleAdaptiveBinarizer::SimpleAdaptiveBinarizer(Ref<LuminanceSource> source)
: GlobalHistogramBinarizer(source) {
filtered = false;
}
SimpleAdaptiveBinarizer::~SimpleAdaptiveBinarizer() {}
// Applies simple sharpening to the row data to improve performance of the 1D
// readers.
Ref<BitArray> SimpleAdaptiveBinarizer::getBlackRow(int y, Ref<BitArray> row,
ErrorHandler &err_handler) {
// First call binarize image in child class to get matrix0_ and binCache
if (!matrix0_) {
binarizeImage0(err_handler);
if (err_handler.ErrCode()) return Ref<BitArray>();
}
// Call parent getBlackMatrix to get current matrix
return Binarizer::getBlackRow(y, row, err_handler);
}
// Does not sharpen the data, as this call is intended to only be used by 2D
// readers.
Ref<BitMatrix> SimpleAdaptiveBinarizer::getBlackMatrix(ErrorHandler &err_handler) {
// First call binarize image in child class to get matrix0_ and binCache
if (!matrix0_) {
binarizeImage0(err_handler);
if (err_handler.ErrCode()) return Ref<BitMatrix>();
}
// First call binarize image in child class to get matrix0_ and binCache
// Call parent getBlackMatrix to get current matrix
return Binarizer::getBlackMatrix(err_handler);
}
using namespace std;
int SimpleAdaptiveBinarizer::binarizeImage0(ErrorHandler &err_handler) {
LuminanceSource &source = *getLuminanceSource();
Ref<BitMatrix> matrix(new BitMatrix(width, height, err_handler));
if (err_handler.ErrCode()) return -1;
ArrayRef<char> localLuminances = source.getMatrix();
unsigned char *src = (unsigned char *)localLuminances->data();
unsigned char *dst = matrix->getPtr();
qrBinarize(src, dst);
matrix0_ = matrix;
return 0;
}
/*A simplified adaptive thresholder.
This compares the current pixel value to the mean value of a (large) window
surrounding it.*/
int SimpleAdaptiveBinarizer::qrBinarize(const unsigned char *src, unsigned char *dst) {
unsigned char *mask = dst;
if (width > 0 && height > 0) {
unsigned *col_sums;
int logwindw;
int logwindh;
int windw;
int windh;
int y0offs;
int y1offs;
unsigned g;
int x;
int y;
/*We keep the window size fairly large to ensure it doesn't fit
completely inside the center of a finder pattern of a version 1 QR
code at full resolution.*/
for (logwindw = 4; logwindw < 8 && (1 << logwindw) < ((width + 7) >> 3); logwindw++)
;
for (logwindh = 4; logwindh < 8 && (1 << logwindh) < ((height + 7) >> 3); logwindh++)
;
windw = 1 << logwindw;
windh = 1 << logwindh;
int logwinds = (logwindw + logwindh);
col_sums = (unsigned *)malloc(width * sizeof(*col_sums));
/*Initialize sums down each column.*/
for (x = 0; x < width; x++) {
g = src[x];
col_sums[x] = (g << (logwindh - 1)) + g;
}
for (y = 1; y < (windh >> 1); y++) {
y1offs = min(y, height - 1) * width;
for (x = 0; x < width; x++) {
g = src[y1offs + x];
col_sums[x] += g;
}
}
for (y = 0; y < height; y++) {
unsigned m;
int x0;
int x1;
/*Initialize the sum over the window.*/
m = (col_sums[0] << (logwindw - 1)) + col_sums[0];
for (x = 1; x < (windw >> 1); x++) {
x1 = min(x, width - 1);
m += col_sums[x1];
}
int offset = y * width;
for (x = 0; x < width; x++) {
/*Perform the test against the threshold T = (m/n)-D,
where n=windw*windh and D=3.*/
g = src[offset + x];
mask[offset + x] = ((g + 3) << (logwinds) < m);
/*Update the window sum.*/
if (x + 1 < width) {
x0 = max(0, x - (windw >> 1));
x1 = min(x + (windw >> 1), width - 1);
m += col_sums[x1] - col_sums[x0];
}
}
/*Update the column sums.*/
if (y + 1 < height) {
y0offs = max(0, y - (windh >> 1)) * width;
y1offs = min(y + (windh >> 1), height - 1) * width;
for (x = 0; x < width; x++) {
col_sums[x] -= src[y0offs + x];
col_sums[x] += src[y1offs + x];
}
}
}
free(col_sums);
}
return 1;
}
Ref<Binarizer> SimpleAdaptiveBinarizer::createBinarizer(Ref<LuminanceSource> source) {
return Ref<Binarizer>(new SimpleAdaptiveBinarizer(source));
}
@@ -0,0 +1,40 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#ifndef __ZXING_COMMON_SIMPLEADAPTIVEBINARIZER_HPP__
#define __ZXING_COMMON_SIMPLEADAPTIVEBINARIZER_HPP__
#include "../../binarizer.hpp"
#include "../array.hpp"
#include "../bitarray.hpp"
#include "../bitmatrix.hpp"
#include "global_histogram_binarizer.hpp"
namespace zxing {
class SimpleAdaptiveBinarizer : public GlobalHistogramBinarizer {
public:
explicit SimpleAdaptiveBinarizer(Ref<LuminanceSource> source);
virtual ~SimpleAdaptiveBinarizer();
virtual Ref<BitArray> getBlackRow(int y, Ref<BitArray> row, ErrorHandler &err_handler) override;
virtual Ref<BitMatrix> getBlackMatrix(ErrorHandler &err_handler) override;
Ref<Binarizer> createBinarizer(Ref<LuminanceSource> source) override;
private:
int binarizeImage0(ErrorHandler &err_handler);
int qrBinarize(const unsigned char *src, unsigned char *dst);
bool filtered;
};
} // namespace zxing
#endif // __ZXING_COMMON_SIMPLEADAPTIVEBINARIZER_HPP__
@@ -0,0 +1,233 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#include "../../precomp.hpp"
#include "bitarray.hpp"
using zxing::ArrayRef;
using zxing::BitArray;
using zxing::ErrorHandler;
using zxing::Ref;
BitArray::BitArray(int size_) : size(size_), bits(size_), nextSets(size_), nextUnSets(size_) {}
void BitArray::setUnchar(int i, unsigned char newBits) { bits[i] = newBits; }
bool BitArray::isRange(int start, int end, bool value, ErrorHandler &err_handler) {
if (end < start) {
err_handler = IllegalArgumentErrorHandler("isRange");
return false;
}
if (start < 0 || end >= bits->size()) {
err_handler = IllegalArgumentErrorHandler("isRange");
return false;
}
if (end == start) {
return true; // empty range matches
}
bool startBool = bits[start] != (unsigned char)0;
int end2 = start;
if (startBool) {
end2 = getNextUnset(start);
} else {
end2 = getNextSet(start);
}
if (startBool == value) {
if (end2 < end) {
return false;
}
} else {
return false;
}
return true;
}
void BitArray::reverse() {
bool *rowBits = getRowBoolPtr();
bool tempBit;
for (int i = 0; i < size / 2; i++) {
tempBit = rowBits[i];
rowBits[i] = rowBits[size - i - 1];
rowBits[size - i - 1] = tempBit;
}
}
void BitArray::initAllNextSets() {
bool *rowBits = getRowBoolPtr();
int *nextSetArray = nextSets->data();
int *nextUnsetArray = nextUnSets->data();
// Init the last one
if (rowBits[size - 1]) {
nextSetArray[size - 1] = size - 1;
nextUnsetArray[size - 1] = size;
} else {
nextUnsetArray[size - 1] = size - 1;
nextSetArray[size - 1] = size;
}
// do inits
for (int i = size - 2; i >= 0; i--) {
if (rowBits[i]) {
nextSetArray[i] = i;
nextUnsetArray[i] = nextUnsetArray[i + 1];
} else {
nextUnsetArray[i] = i;
nextSetArray[i] = nextSetArray[i + 1];
}
}
}
void BitArray::initAllNextSetsFromCounters(std::vector<int> counters) {
bool *rowBits = getRowBoolPtr();
bool isWhite = rowBits[0];
int c = 0;
int offset = 0;
int count = 0;
int prevCount = 0;
int currCount = 0;
int _size = counters.size();
int *nextSetArray = nextSets->data();
int *nextUnsetArray = nextUnSets->data();
// int* countersArray = counters.data();
int *countersArray = &counters[0];
while (c < _size) {
currCount = countersArray[c];
count += currCount;
if (isWhite) {
for (int i = 0; i < currCount; i++) {
offset = prevCount + i;
nextSetArray[offset] = prevCount + i;
nextUnsetArray[offset] = count;
}
} else {
for (int i = 0; i < currCount; i++) {
offset = prevCount + i;
nextSetArray[offset] = count;
nextUnsetArray[offset] = prevCount + i;
}
}
isWhite = !isWhite;
prevCount += currCount;
c++;
}
}
int BitArray::getNextSet(int from) {
if (from >= size) {
return size;
}
return nextSets[from];
}
int BitArray::getNextUnset(int from) {
if (from >= size) {
return size;
}
return nextUnSets[from];
}
BitArray::~BitArray() {}
int BitArray::getSize() const { return size; }
void BitArray::clear() {
int max = bits->size();
for (int i = 0; i < max; i++) {
bits[i] = 0;
}
}
BitArray::Reverse::Reverse(Ref<BitArray> array_) : array(array_) { array->reverse(); }
BitArray::Reverse::~Reverse() { array->reverse(); }
void BitArray::appendBit(bool value) {
ArrayRef<unsigned char> newBits(size + 1);
for (int i = 0; i < size; i++) {
newBits[i] = bits[i];
}
bits = newBits;
if (value) {
set(size);
}
++size;
}
int BitArray::getSizeInBytes() const { return size; }
// Appends the least-significant bits, from value, in order from
// most-significant to least-significant. For example, appending 6 bits
// from 0x000001E will append the bits 0, 1, 1, 1, 1, 0 in that order.
void BitArray::appendBits(int value, int numBits, ErrorHandler &err_handler) {
if (numBits < 0 || numBits > 32) {
err_handler = IllegalArgumentErrorHandler("Number of bits must be between 0 and 32");
return;
}
ArrayRef<unsigned char> newBits(size + numBits);
for (int i = 0; i < size; i++) newBits[i] = bits[i];
bits = newBits;
for (int numBitsLeft = numBits; numBitsLeft > 0; numBitsLeft--) {
if (((value >> (numBitsLeft - 1)) & 0x01) == 1) {
set(size);
}
++size;
}
return;
}
void BitArray::appendBitArray(const BitArray &array) {
ArrayRef<unsigned char> newBits(size + array.getSize());
for (int i = 0; i < size; ++i) {
newBits[i] = bits[i];
}
bits = newBits;
for (int i = 0; i < array.getSize(); ++i) {
if (array.get(i)) {
set(size);
}
++size;
}
}
void BitArray::toBytes(int bitOffset, ArrayRef<int> &array, int offset, int numBytes) {
for (int i = 0; i < numBytes; i++) {
int theByte = 0;
if (get(bitOffset)) {
theByte = 1;
}
bitOffset++;
array[offset + i] = theByte;
}
}
void BitArray::bitXOR(const BitArray &other, ErrorHandler &err_handler) {
if (size != other.size) {
err_handler = IllegalArgumentErrorHandler("Sizes don't match");
return;
}
for (int i = 0; i < bits->size(); i++) {
bits[i] = bits[i] == other.bits[i] ? 0 : 1;
}
}
@@ -0,0 +1,88 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#ifndef __ZXING_COMMON_BITARRAY_HPP__
#define __ZXING_COMMON_BITARRAY_HPP__
#include "../errorhandler.hpp"
#include "../zxing.hpp"
#include "array.hpp"
#include "counted.hpp"
#include <cstring>
namespace zxing {
class BitArray : public Counted {
private:
int size;
ArrayRef<unsigned char> bits;
ArrayRef<int> nextSets;
ArrayRef<int> nextUnSets;
// bool nextSetsInited;
public:
explicit BitArray(int size);
~BitArray();
int getSize() const;
bool get(int i) const { return bits[i] != 0; }
void set(int i) {
// bits[i] |= 0xFF;
bits[i] = true;
}
void setOneRow(unsigned char* rowBits, int length) {
unsigned char* dst = bits->data();
memcpy(dst, rowBits, length);
}
bool* getRowBoolPtr() {
// return (bool*)bits.data();
return (bool*)bits->data();
}
// Init for next sets and unsets to speed up
void initAllNextSets();
void initAllNextSetsFromCounters(std::vector<int> counters);
int getNextSet(int from);
int getNextUnset(int from);
void setUnchar(int i, unsigned char newBist);
void clear();
bool isRange(int start, int end, bool value, ErrorHandler& err_handler);
void reverse();
class Reverse {
private:
Ref<BitArray> array;
public:
explicit Reverse(Ref<BitArray> array);
~Reverse();
};
void appendBit(bool value);
int getSizeInBytes() const;
void appendBits(int value, int numberOfBits, ErrorHandler& err_handler);
void appendBitArray(const BitArray& array);
void toBytes(int bitOffset, ArrayRef<int>& array, int offset, int numBytes);
void bitXOR(const BitArray& other, ErrorHandler& err_handler);
#ifndef USE_BYTE_FOR_BIT
private:
static int makeArraySize(int size);
#endif
};
} // namespace zxing
#endif // __ZXING_COMMON_BITARRAY_HPP__
@@ -0,0 +1,397 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#include "../../precomp.hpp"
#include "bitmatrix.hpp"
using zxing::ArrayRef;
using zxing::BitArray;
using zxing::BitMatrix;
using zxing::ErrorHandler;
using zxing::Ref;
void BitMatrix::init(int _width, int _height, ErrorHandler& err_handler) {
if (_width < 1 || _height < 1) {
err_handler = IllegalArgumentErrorHandler("Both dimensions must be greater than 0");
return;
}
width = _width;
height = _height;
this->rowBitsSize = width;
bits = ArrayRef<unsigned char>(width * height);
rowOffsets = ArrayRef<int>(height);
// offsetRowSize = new int[height];
rowOffsets[0] = 0;
for (int i = 1; i < height; i++) {
rowOffsets[i] = rowOffsets[i - 1] + width;
}
isInitRowCounters = false;
isInitColsCounters = false;
}
void BitMatrix::init(int _width, int _height, unsigned char* bitsPtr, ErrorHandler& err_handler) {
init(_width, _height, err_handler);
if (err_handler.ErrCode()) return;
memcpy(bits->data(), bitsPtr, width * height * sizeof(unsigned char));
}
void BitMatrix::initRowCounters() {
if (isInitRowCounters == true) {
return;
}
row_counters = vector<COUNTER_TYPE>(width * height, 0);
row_counters_offset = vector<COUNTER_TYPE>(width * height, 0);
row_point_offset = vector<COUNTER_TYPE>(width * height, 0);
row_counter_offset_end = vector<COUNTER_TYPE>(height, 0);
row_counters_recorded = vector<bool>(height, false);
isInitRowCounters = true;
}
void BitMatrix::initColsCounters() {
if (isInitColsCounters == true) {
return;
}
cols_counters = vector<COUNTER_TYPE>(width * height, 0);
cols_counters_offset = vector<COUNTER_TYPE>(width * height, 0);
cols_point_offset = vector<COUNTER_TYPE>(width * height, 0);
cols_counter_offset_end = vector<COUNTER_TYPE>(width, 0);
cols_counters_recorded = vector<bool>(width, false);
isInitColsCounters = true;
}
BitMatrix::BitMatrix(int dimension, ErrorHandler& err_handler) {
init(dimension, dimension, err_handler);
}
BitMatrix::BitMatrix(int _width, int _height, ErrorHandler& err_handler) {
init(_width, _height, err_handler);
}
BitMatrix::BitMatrix(int _width, int _height, unsigned char* bitsPtr, ErrorHandler& err_handler) {
init(_width, _height, bitsPtr, err_handler);
}
// Copy bitMatrix
void BitMatrix::copyOf(Ref<BitMatrix> _bits, ErrorHandler& err_handler) {
int _width = _bits->getWidth();
int _height = _bits->getHeight();
init(_width, _height, err_handler);
for (int y = 0; y < height; y++) {
bool* rowPtr = _bits->getRowBoolPtr(y);
setRowBool(y, rowPtr);
}
}
void BitMatrix::xxor(Ref<BitMatrix> _bits) {
if (width != _bits->getWidth() || height != _bits->getHeight()) {
return;
}
for (int y = 0; y < height && y < _bits->getHeight(); ++y) {
bool* rowPtrA = _bits->getRowBoolPtr(y);
bool* rowPtrB = getRowBoolPtr(y);
for (int x = 0; x < width && x < _bits->getWidth(); ++x) {
rowPtrB[x] = rowPtrB[x] ^ rowPtrA[x];
}
setRowBool(y, rowPtrB);
}
}
BitMatrix::~BitMatrix() {}
void BitMatrix::flip(int x, int y) {
bits[rowOffsets[y] + x] = (bits[rowOffsets[y] + x] == (unsigned char)0);
}
void BitMatrix::flipAll() {
bool* matrixBits = (bool*)bits->data();
for (int i = 0; i < bits->size(); i++) {
matrixBits[i] = !matrixBits[i];
}
}
void BitMatrix::flipRegion(int left, int top, int _width, int _height, ErrorHandler& err_handler) {
if (top < 0 || left < 0) {
err_handler = IllegalArgumentErrorHandler("Left and top must be nonnegative");
return;
}
if (_height < 1 || _width < 1) {
err_handler = IllegalArgumentErrorHandler("Height and width must be at least 1");
return;
}
int right = left + _width;
int bottom = top + _height;
if (bottom > this->height || right > this->width) {
err_handler = IllegalArgumentErrorHandler("The region must fit inside the matrix");
return;
}
for (int y = top; y < bottom; y++) {
for (int x = left; x < right; x++) {
bits[rowOffsets[y] + x] ^= 1;
}
}
}
void BitMatrix::setRegion(int left, int top, int _width, int _height, ErrorHandler& err_handler) {
if (top < 0 || left < 0) {
err_handler = IllegalArgumentErrorHandler("Left and top must be nonnegative");
return;
}
if (_height < 1 || _width < 1) {
err_handler = IllegalArgumentErrorHandler("Height and width must be at least 1");
return;
}
int right = left + _width;
int bottom = top + _height;
if (bottom > this->height || right > this->width) {
err_handler = IllegalArgumentErrorHandler("The region must fit inside the matrix");
return;
}
for (int y = top; y < bottom; y++) {
for (int x = left; x < right; x++) {
bits[rowOffsets[y] + x] = true;
// bits[rowOffsets[y]+x] |= 0xFF;
}
}
}
Ref<BitArray> BitMatrix::getRow(int y, Ref<BitArray> row) {
if (row.empty() || row->getSize() < width) {
row = new BitArray(width);
}
// row->
unsigned char* src = bits.data() + rowOffsets[y];
row->setOneRow(src, width);
return row;
}
ArrayRef<int> BitMatrix::getTopLeftOnBit() const {
int bitsOffset = 0;
while (bitsOffset < bits->size() && bits[bitsOffset] == 0) {
bitsOffset++;
}
if (bitsOffset == bits->size()) {
return ArrayRef<int>();
}
int y = bitsOffset / width;
int x = bitsOffset % width;
ArrayRef<int> res(2);
res[0] = x;
res[1] = y;
return res;
}
ArrayRef<int> BitMatrix::getBottomRightOnBit() const {
int bitsOffset = bits->size() - 1;
while (bitsOffset >= 0 && bits[bitsOffset] == 0) {
bitsOffset--;
}
if (bitsOffset < 0) {
return ArrayRef<int>();
}
int y = bitsOffset / width;
int x = bitsOffset % width;
ArrayRef<int> res(2);
res[0] = x;
res[1] = y;
return res;
}
void BitMatrix::getRowBool(int y, bool* getrow) {
int offset = rowOffsets[y];
unsigned char* src = bits.data() + offset;
memcpy(getrow, src, rowBitsSize * sizeof(bool));
}
void BitMatrix::setRowBool(int y, bool* row) {
int offset = rowOffsets[y];
unsigned char* dst = bits.data() + offset;
memcpy(dst, row, rowBitsSize * sizeof(bool));
return;
}
bool* BitMatrix::getRowBoolPtr(int y) {
int offset = y * rowBitsSize;
unsigned char* src = bits.data() + offset;
return (bool*)src;
}
void BitMatrix::clear() {
int size = bits->size();
unsigned char* dst = bits->data();
memset(dst, 0, size * sizeof(unsigned char));
}
int BitMatrix::getWidth() const { return width; }
int BitMatrix::getHeight() const { return height; }
COUNTER_TYPE* BitMatrix::getRowPointInRecords(int y) {
if (!row_point_offset[y]) {
setRowRecords(y);
}
int offset = y * width;
COUNTER_TYPE* counters = &row_point_offset[0] + offset;
return (COUNTER_TYPE*)counters;
}
COUNTER_TYPE* BitMatrix::getRowRecords(int y) {
if (!row_counters_recorded[y]) {
setRowRecords(y);
}
int offset = y * width;
COUNTER_TYPE* counters = &row_counters[0] + offset;
return (COUNTER_TYPE*)counters;
}
COUNTER_TYPE* BitMatrix::getRowRecordsOffset(int y) {
if (!row_counters_recorded[y]) {
setRowRecords(y);
}
int offset = y * width;
COUNTER_TYPE* counters = &row_counters_offset[0] + offset;
return (COUNTER_TYPE*)counters;
}
bool BitMatrix::getRowFirstIsWhite(int y) {
bool is_white = !get(0, y);
return is_white;
}
bool BitMatrix::getRowLastIsWhite(int y) {
bool last_is_white = !get(width - 1, y);
return last_is_white;
}
COUNTER_TYPE BitMatrix::getRowCounterOffsetEnd(int y) {
if (!row_counters_recorded[y]) {
setRowRecords(y);
}
return row_counter_offset_end[y];
}
void BitMatrix::setRowRecords(int y) {
COUNTER_TYPE* cur_row_counters = &row_counters[0] + y * width;
COUNTER_TYPE* cur_row_counters_offset = &row_counters_offset[0] + y * width;
COUNTER_TYPE* cur_row_point_in_counters = &row_point_offset[0] + y * width;
int end = width;
bool* rowBit = getRowBoolPtr(y);
bool isWhite = !rowBit[0];
int counterPosition = 0;
int i = 0;
cur_row_counters_offset[0] = 0;
while (i < end) {
if (rowBit[i] ^ isWhite) { // that is, exactly one is true
cur_row_counters[counterPosition]++;
} else {
counterPosition++;
if (counterPosition == end) {
break;
} else {
cur_row_counters[counterPosition] = 1;
isWhite = !isWhite;
cur_row_counters_offset[counterPosition] = i;
}
}
cur_row_point_in_counters[i] = counterPosition;
i++;
}
// use the last row__onedReaderData->counter_size to record
// _onedReaderData->counter_size
row_counter_offset_end[y] = counterPosition < end ? (counterPosition + 1) : end;
row_counters_recorded[y] = true;
return;
}
COUNTER_TYPE* BitMatrix::getColsPointInRecords(int x) {
if (!cols_point_offset[x]) {
setColsRecords(x);
}
int offset = x * height;
COUNTER_TYPE* counters = &cols_point_offset[0] + offset;
return (COUNTER_TYPE*)counters;
}
COUNTER_TYPE* BitMatrix::getColsRecords(int x) {
if (!cols_counters_recorded[x]) {
setColsRecords(x);
}
int offset = x * height;
COUNTER_TYPE* counters = &cols_counters[0] + offset;
return (COUNTER_TYPE*)counters;
}
COUNTER_TYPE* BitMatrix::getColsRecordsOffset(int x) {
if (!cols_counters_recorded[x]) {
setColsRecords(x);
}
int offset = x * height;
COUNTER_TYPE* counters = &cols_counters_offset[0] + offset;
return (COUNTER_TYPE*)counters;
}
COUNTER_TYPE BitMatrix::getColsCounterOffsetEnd(int x) {
if (!cols_counters_recorded[x]) {
setColsRecords(x);
}
return cols_counter_offset_end[x];
}
void BitMatrix::setColsRecords(int x) {
COUNTER_TYPE* cur_cols_counters = &cols_counters[0] + x * height;
COUNTER_TYPE* cur_cols_counters_offset = &cols_counters_offset[0] + x * height;
COUNTER_TYPE* cur_cols_point_in_counters = &cols_point_offset[0] + x * height;
int end = height;
bool* rowBit = getRowBoolPtr(0);
bool isWhite = !rowBit[0];
int counterPosition = 0;
int i = 0;
cur_cols_counters_offset[0] = 0;
while (i < end) {
if (rowBit[i] ^ isWhite) { // that is, exactly one is true
cur_cols_counters[counterPosition]++;
} else {
counterPosition++;
if (counterPosition == end) {
break;
} else {
cur_cols_counters[counterPosition] = 1;
isWhite = !isWhite;
cur_cols_counters_offset[counterPosition] = i;
}
}
cur_cols_point_in_counters[i] = counterPosition;
i++;
rowBit += width;
}
cols_counter_offset_end[x] = counterPosition < end ? (counterPosition + 1) : end;
cols_counters_recorded[x] = true;
return;
};
@@ -0,0 +1,115 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#ifndef __ZXING_COMMON_BITMATRIX_HPP__
#define __ZXING_COMMON_BITMATRIX_HPP__
#include "../errorhandler.hpp"
#include "array.hpp"
#include "bitarray.hpp"
#include "counted.hpp"
using namespace std;
namespace zxing {
class BitMatrix : public Counted {
public:
static const int bitsPerWord = std::numeric_limits<unsigned int>::digits;
private:
int width;
int height;
int rowBitsSize;
vector<COUNTER_TYPE> row_counters;
vector<COUNTER_TYPE> row_counters_offset;
vector<bool> row_counters_recorded;
vector<COUNTER_TYPE> row_counter_offset_end;
vector<COUNTER_TYPE> row_point_offset;
vector<COUNTER_TYPE> cols_counters;
vector<COUNTER_TYPE> cols_counters_offset;
vector<bool> cols_counters_recorded;
vector<COUNTER_TYPE> cols_counter_offset_end;
vector<COUNTER_TYPE> cols_point_offset;
ArrayRef<unsigned char> bits;
ArrayRef<int> rowOffsets;
public:
BitMatrix(int _width, int _height, unsigned char* bitsPtr, ErrorHandler& err_handler);
BitMatrix(int dimension, ErrorHandler& err_handler);
BitMatrix(int _width, int _height, ErrorHandler& err_handler);
void copyOf(Ref<BitMatrix> _bits, ErrorHandler& err_handler);
void xxor(Ref<BitMatrix> _bits);
~BitMatrix();
unsigned char get(int x, int y) const { return bits[width * y + x]; }
void set(int x, int y) { bits[rowOffsets[y] + x] = (unsigned char)1; }
void set(int x, int y, unsigned char value) { bits[rowOffsets[y] + x] = value; }
void swap(int srcX, int srcY, int dstX, int dstY) {
auto temp = bits[width * srcY + srcX];
bits[width * srcY + srcX] = bits[width * dstY + dstX];
bits[width * dstY + dstX] = temp;
}
void getRowBool(int y, bool* row);
bool* getRowBoolPtr(int y);
void setRowBool(int y, bool* row);
int getRowBitsSize() { return rowBitsSize; }
unsigned char* getPtr() { return bits->data(); }
void flip(int x, int y);
void flipAll();
void clear();
void setRegion(int left, int top, int _width, int _height, ErrorHandler& err_handler);
void flipRegion(int left, int top, int _width, int _height, ErrorHandler& err_handler);
Ref<BitArray> getRow(int y, Ref<BitArray> row);
int getWidth() const;
int getHeight() const;
ArrayRef<int> getTopLeftOnBit() const;
ArrayRef<int> getBottomRightOnBit() const;
bool isInitRowCounters;
void initRowCounters();
COUNTER_TYPE* getRowRecords(int y);
COUNTER_TYPE* getRowRecordsOffset(int y);
bool getRowFirstIsWhite(int y);
COUNTER_TYPE getRowCounterOffsetEnd(int y);
bool getRowLastIsWhite(int y);
COUNTER_TYPE* getRowPointInRecords(int y);
bool isInitColsCounters;
void initColsCounters();
COUNTER_TYPE* getColsRecords(int x);
COUNTER_TYPE* getColsRecordsOffset(int x);
COUNTER_TYPE* getColsPointInRecords(int x);
COUNTER_TYPE getColsCounterOffsetEnd(int x);
private:
inline void init(int, int, ErrorHandler& err_handler);
inline void init(int _width, int _height, unsigned char* bitsPtr, ErrorHandler& err_handler);
void setRowRecords(int y);
void setColsRecords(int x);
BitMatrix(const BitMatrix&, ErrorHandler& err_handler);
};
} // namespace zxing
#endif // __ZXING_COMMON_BITMATRIX_HPP__
@@ -0,0 +1,62 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#include "../../precomp.hpp"
#include "bitsource.hpp"
#include <sstream>
namespace zxing {
int BitSource::readBits(int numBits, ErrorHandler& err_handler) {
if (numBits < 0 || numBits > 32 || numBits > available()) {
std::ostringstream oss;
oss << numBits;
err_handler = IllegalArgumentErrorHandler(oss.str().c_str());
return -1;
}
int result = 0;
// First, read remainder from current byte
if (bitOffset_ > 0) {
int bitsLeft = 8 - bitOffset_;
int toRead = numBits < bitsLeft ? numBits : bitsLeft;
int bitsToNotRead = bitsLeft - toRead;
int mask = (0xFF >> (8 - toRead)) << bitsToNotRead;
result = (bytes_[byteOffset_] & mask) >> bitsToNotRead;
numBits -= toRead;
bitOffset_ += toRead;
if (bitOffset_ == 8) {
bitOffset_ = 0;
byteOffset_++;
}
}
// Next read whole bytes
if (numBits > 0) {
while (numBits >= 8) {
result = (result << 8) | (bytes_[byteOffset_] & 0xFF);
byteOffset_++;
numBits -= 8;
}
// Finally read a partial byte
if (numBits > 0) {
int bitsToNotRead = 8 - numBits;
int mask = (0xFF >> bitsToNotRead) << bitsToNotRead;
result = (result << numBits) | ((bytes_[byteOffset_] & mask) >> bitsToNotRead);
bitOffset_ += numBits;
}
}
return result;
}
int BitSource::available() { return 8 * (bytes_->size() - byteOffset_) - bitOffset_; }
} // namespace zxing
@@ -0,0 +1,57 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#ifndef __ZXING_COMMON_BITSOURCE_HPP__
#define __ZXING_COMMON_BITSOURCE_HPP__
#include "../errorhandler.hpp"
#include "array.hpp"
namespace zxing {
/**
* <p>This provides an easy abstraction to read bits at a time from a sequence
* of bytes, where the number of bits read is not often a multiple of 8.</p>
*
* <p>This class is not thread-safe.</p>
*
* @author srowen@google.com (Sean Owen)
* @author christian.brunschen@gmail.com (Christian Brunschen)
*/
class BitSource : public Counted {
typedef char byte;
private:
ArrayRef<byte> bytes_;
int byteOffset_;
int bitOffset_;
public:
/**
* @param bytes bytes from which this will read bits. Bits will be read from
* the first byte first. Bits are read within a byte from most-significant
* to least-significant bit.
*/
explicit BitSource(ArrayRef<byte> &bytes) : bytes_(bytes), byteOffset_(0), bitOffset_(0) {}
int getBitOffset() { return bitOffset_; }
int getByteOffset() { return byteOffset_; }
int readBits(int numBits, ErrorHandler &err_handler);
/**
* @return number of bits that can be read successfully
*/
int available();
};
} // namespace zxing
#endif // __ZXING_COMMON_BITSOURCE_HPP__
@@ -0,0 +1,54 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
#include "../../precomp.hpp"
#include "bytematrix.hpp"
using zxing::ArrayRef;
using zxing::ByteMatrix;
using zxing::ErrorHandler;
using zxing::Ref;
void ByteMatrix::init(int _width, int _height) {
if (_width < 1 || _height < 1) {
return;
}
this->width = _width;
this->height = _height;
bytes = new unsigned char[width * height];
row_offsets = new int[height];
row_offsets[0] = 0;
for (int i = 1; i < height; i++) {
row_offsets[i] = row_offsets[i - 1] + width;
}
}
ByteMatrix::ByteMatrix(int dimension) : bytes(nullptr) { init(dimension, dimension); }
ByteMatrix::ByteMatrix(int _width, int _height) : bytes(nullptr) { init(_width, _height); }
ByteMatrix::ByteMatrix(int _width, int _height, ArrayRef<char> source) : bytes(nullptr) {
init(_width, _height);
if( bytes != nullptr)
{
const size_t size = _width * _height;
memcpy(&bytes[0], &source[0], size);
}
}
ByteMatrix::~ByteMatrix() {
if (bytes) delete[] bytes;
if (row_offsets) delete[] row_offsets;
}
unsigned char* ByteMatrix::getByteRow(int y, ErrorHandler& err_handler) {
if (y < 0 || y >= getHeight()) {
err_handler = IllegalArgumentErrorHandler("Requested row is outside the image.");
return NULL;
}
return &bytes[row_offsets[y]];
}
@@ -0,0 +1,58 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
#ifndef __ZXING_COMMON_BYTEMATRIX_HPP__
#define __ZXING_COMMON_BYTEMATRIX_HPP__
#include "../errorhandler.hpp"
#include "array.hpp"
#include "bitarray.hpp"
#include "counted.hpp"
namespace zxing {
class ByteMatrix : public Counted {
public:
explicit ByteMatrix(int dimension);
ByteMatrix(int _width, int _height);
ByteMatrix(int _width, int _height, ArrayRef<char> source);
~ByteMatrix();
char get(int x, int y) const {
int offset = row_offsets[y] + x;
return bytes[offset];
}
void set(int x, int y, char char_value) {
int offset = row_offsets[y] + x;
bytes[offset] = char_value & 0XFF;
}
unsigned char* getByteRow(int y, ErrorHandler& err_handler);
int getWidth() const { return width; }
int getHeight() const { return height; }
unsigned char* bytes;
private:
int width;
int height;
// ArrayRef<char> bytes;
// ArrayRef<int> row_offsets;
int* row_offsets;
private:
inline void init(int, int);
ByteMatrix(const ByteMatrix&);
ByteMatrix& operator=(const ByteMatrix&);
};
} // namespace zxing
#endif // __ZXING_COMMON_BYTEMATRIX_HPP__
@@ -0,0 +1,111 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#include "../../precomp.hpp"
#include "characterseteci.hpp"
using zxing::common::CharacterSetECI;
// Fix memory leak
// https://github.com/ukeller/zxing-cpp/commit/c632ffe47ca7342f894ae533263be249cbdfd37e
// std::map<int, CharacterSetECI*> CharacterSetECI::VALUE_TO_ECI;
// std::map<std::string, CharacterSetECI*> CharacterSetECI::NAME_TO_ECI;
std::map<int, zxing::Ref<CharacterSetECI> > CharacterSetECI::VALUE_TO_ECI;
std::map<std::string, zxing::Ref<CharacterSetECI> > CharacterSetECI::NAME_TO_ECI;
const bool CharacterSetECI::inited = CharacterSetECI::init_tables();
#define ADD_CHARACTER_SET(VALUES, STRINGS) \
{ \
static int values[] = {VALUES, -1}; \
static char const* strings[] = {STRINGS, 0}; \
addCharacterSet(values, strings); \
}
#define XC ,
bool CharacterSetECI::init_tables() {
ADD_CHARACTER_SET(0 XC 2, "Cp437");
ADD_CHARACTER_SET(1 XC 3, "ISO8859_1" XC "ISO-8859-1");
ADD_CHARACTER_SET(4, "ISO8859_2" XC "ISO-8859-2");
ADD_CHARACTER_SET(5, "ISO8859_3" XC "ISO-8859-3");
ADD_CHARACTER_SET(6, "ISO8859_4" XC "ISO-8859-4");
ADD_CHARACTER_SET(7, "ISO8859_5" XC "ISO-8859-5");
ADD_CHARACTER_SET(8, "ISO8859_6" XC "ISO-8859-6");
ADD_CHARACTER_SET(9, "ISO8859_7" XC "ISO-8859-7");
ADD_CHARACTER_SET(10, "ISO8859_8" XC "ISO-8859-8");
ADD_CHARACTER_SET(11, "ISO8859_9" XC "ISO-8859-9");
ADD_CHARACTER_SET(12, "ISO8859_10" XC "ISO-8859-10");
ADD_CHARACTER_SET(13, "ISO8859_11" XC "ISO-8859-11");
ADD_CHARACTER_SET(15, "ISO8859_13" XC "ISO-8859-13");
ADD_CHARACTER_SET(16, "ISO8859_14" XC "ISO-8859-14");
ADD_CHARACTER_SET(17, "ISO8859_15" XC "ISO-8859-15");
ADD_CHARACTER_SET(18, "ISO8859_16" XC "ISO-8859-16");
ADD_CHARACTER_SET(20, "SJIS" XC "Shift_JIS");
ADD_CHARACTER_SET(21, "Cp1250" XC "windows-1250");
ADD_CHARACTER_SET(22, "Cp1251" XC "windows-1251");
ADD_CHARACTER_SET(23, "Cp1252" XC "windows-1252");
ADD_CHARACTER_SET(24, "Cp1256" XC "windows-1256");
ADD_CHARACTER_SET(25, "UnicodeBigUnmarked" XC "UTF-16BE" XC "UnicodeBig");
ADD_CHARACTER_SET(26, "UTF8" XC "UTF-8");
ADD_CHARACTER_SET(27 XC 170, "ASCII" XC "US-ASCII");
ADD_CHARACTER_SET(28, "Big5");
ADD_CHARACTER_SET(29, "GB18030" XC "GB2312" XC "EUC_CN" XC "GBK");
ADD_CHARACTER_SET(30, "EUC_KR" XC "EUC-KR");
return true;
}
#undef XC
CharacterSetECI::CharacterSetECI(int const* values, char const* const* names)
: values_(values), names_(names) {
zxing::Ref<CharacterSetECI> this_ref(this);
for (int const* p_values = values_; *p_values != -1; p_values++) {
// VALUE_TO_ECI[*values] = this;
VALUE_TO_ECI[*p_values] = this_ref;
}
for (char const* const* p_names = names_; *p_names; p_names++) {
// NAME_TO_ECI[string(*names)] = this;
NAME_TO_ECI[string(*p_names)] = this_ref;
}
}
char const* CharacterSetECI::name() const { return names_[0]; }
int CharacterSetECI::getValue() const { return values_[0]; }
void CharacterSetECI::addCharacterSet(int const* values, char const* const* names) {
new CharacterSetECI(values, names);
}
CharacterSetECI* CharacterSetECI::getCharacterSetECIByValueFind(int value) {
if (value < 0 || value >= 900) {
return zxing::Ref<CharacterSetECI>(0);
}
std::map<int, zxing::Ref<CharacterSetECI> >::iterator iter;
iter = VALUE_TO_ECI.find(value);
if (iter != VALUE_TO_ECI.end()) {
return iter->second;
} else {
return zxing::Ref<CharacterSetECI>(0);
}
}
CharacterSetECI* CharacterSetECI::getCharacterSetECIByName(string const& name) {
std::map<std::string, zxing::Ref<CharacterSetECI> >::iterator iter;
iter = NAME_TO_ECI.find(name);
if (iter != NAME_TO_ECI.end()) {
return iter->second;
} else {
return zxing::Ref<CharacterSetECI>(0);
}
}
@@ -0,0 +1,46 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#ifndef __ZXING_COMMON_CHARACTERSETECI_HPP__
#define __ZXING_COMMON_CHARACTERSETECI_HPP__
#include <map>
#include "../decodehints.hpp"
#include "counted.hpp"
namespace zxing {
namespace common {
class CharacterSetECI : public Counted {
private:
static std::map<int, zxing::Ref<CharacterSetECI> > VALUE_TO_ECI;
static std::map<std::string, zxing::Ref<CharacterSetECI> > NAME_TO_ECI;
static const bool inited;
static bool init_tables();
int const* const values_;
char const* const* const names_;
CharacterSetECI(int const* values, char const* const* names);
static void addCharacterSet(int const* value, char const* const* encodingNames);
public:
char const* name() const;
int getValue() const;
static CharacterSetECI* getCharacterSetECIByValueFind(int value);
static CharacterSetECI* getCharacterSetECIByName(std::string const& name);
};
} // namespace common
} // namespace zxing
#endif // __ZXING_COMMON_CHARACTERSETECI_HPP__
@@ -0,0 +1,110 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#ifndef __ZXING_COMMON_COUNTED_HPP__
#define __ZXING_COMMON_COUNTED_HPP__
#include <cstddef>
#include <algorithm>
namespace zxing {
/* base class for reference-counted objects */
class Counted {
private:
unsigned int count_;
public:
Counted() : count_(0) {}
virtual ~Counted() {}
Counted* retain() {
count_++;
return this;
}
void release() {
count_--;
if (count_ == 0) {
count_ = 0xDEADF001;
delete this;
}
}
/* return the current count for denugging purposes or similar */
int count() const { return count_; }
};
/* counting reference to reference-counted objects */
template <typename T>
class Ref {
private:
public:
T* object_;
explicit Ref(T* o = 0) : object_(0) { reset(o); }
Ref(const Ref& other) : object_(0) { reset(other.object_); }
template <class Y>
Ref(const Ref<Y>& other) : object_(0) {
reset(other.object_);
}
~Ref() {
if (object_) {
object_->release();
}
}
void reset(T* o) {
if (o) {
o->retain();
}
if (object_ != 0) {
object_->release();
}
object_ = o;
}
Ref& operator=(const Ref& other) {
reset(other.object_);
return *this;
}
template <class Y>
Ref& operator=(const Ref<Y>& other) {
reset(other.object_);
return *this;
}
Ref& operator=(T* o) {
reset(o);
return *this;
}
template <class Y>
Ref& operator=(Y* o) {
reset(o);
return *this;
}
T& operator*() { return *object_; }
T* operator->() const { return object_; }
operator T*() const { return object_; }
bool operator==(const T* that) { return object_ == that; }
bool operator==(const Ref& other) const {
return object_ == other.object_ || *object_ == *(other.object_);
}
template <class Y>
bool operator==(const Ref<Y>& other) const {
return object_ == other.object_ || *object_ == *(other.object_);
}
bool operator!=(const T* that) { return !(*this == that); }
bool empty() const { return object_ == 0; }
};
} // namespace zxing
#endif // __ZXING_COMMON_COUNTED_HPP__
@@ -0,0 +1,65 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#include "../../precomp.hpp"
#include "decoder_result.hpp"
using zxing::DecoderResult;
using zxing::Ref;
using zxing::ArrayRef;
using zxing::String;
DecoderResult::DecoderResult(ArrayRef<char> rawBytes, Ref<String> text,
ArrayRef<ArrayRef<char> >& byteSegments, string const& ecLevel)
: rawBytes_(rawBytes), text_(text), byteSegments_(byteSegments), ecLevel_(ecLevel) {
outputCharset_ = "UTF-8";
otherClassName = "";
qrcodeVersion_ = -1;
}
DecoderResult::DecoderResult(ArrayRef<char> rawBytes, Ref<String> text,
ArrayRef<ArrayRef<char> >& byteSegments, string const& ecLevel,
string outputCharset)
: rawBytes_(rawBytes),
text_(text),
byteSegments_(byteSegments),
ecLevel_(ecLevel),
outputCharset_(outputCharset) {
otherClassName = "";
qrcodeVersion_ = -1;
}
DecoderResult::DecoderResult(ArrayRef<char> rawBytes, Ref<String> text,
ArrayRef<ArrayRef<char> >& byteSegments, string const& ecLevel,
string outputCharset, int qrcodeVersion, string& charsetMode)
: rawBytes_(rawBytes),
text_(text),
byteSegments_(byteSegments),
ecLevel_(ecLevel),
outputCharset_(outputCharset),
qrcodeVersion_(qrcodeVersion),
charsetMode_(charsetMode) {
otherClassName = "";
}
DecoderResult::DecoderResult(ArrayRef<char> rawBytes, Ref<String> text)
: rawBytes_(rawBytes), text_(text) {
outputCharset_ = "UTF-8";
otherClassName = "";
}
DecoderResult::DecoderResult(ArrayRef<char> rawBytes, Ref<String> text, std::string outputCharset)
: rawBytes_(rawBytes), text_(text), outputCharset_(outputCharset) {
otherClassName = "";
}
ArrayRef<char> DecoderResult::getRawBytes() { return rawBytes_; }
Ref<String> DecoderResult::getText() { return text_; }
string DecoderResult::getCharset() { return outputCharset_; }
@@ -0,0 +1,77 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#ifndef __ZXING_COMMON_DECODER_RESULT_HPP__
#define __ZXING_COMMON_DECODER_RESULT_HPP__
#include "../qrcode/decoder/qrcode_decoder_metadata.hpp"
#include "array.hpp"
#include "counted.hpp"
#include "str.hpp"
namespace zxing {
class DecoderResult : public Counted {
private:
ArrayRef<char> rawBytes_;
Ref<String> text_;
ArrayRef<ArrayRef<char> > byteSegments_;
std::string ecLevel_;
std::string outputCharset_;
int qrcodeVersion_;
std::string charsetMode_;
Ref<qrcode::QRCodeDecoderMetaData> other_;
string otherClassName;
public:
DecoderResult(ArrayRef<char> rawBytes, Ref<String> text,
ArrayRef<ArrayRef<char> >& byteSegments, std::string const& ecLevel);
DecoderResult(ArrayRef<char> rawBytes, Ref<String> text,
ArrayRef<ArrayRef<char> >& byteSegments, std::string const& ecLevel,
std::string outputCharset);
DecoderResult(ArrayRef<char> rawBytes, Ref<String> text,
ArrayRef<ArrayRef<char> >& byteSegments, std::string const& ecLevel,
std::string outputCharset, int qrcodeVersion, std::string& charsetMode);
DecoderResult(ArrayRef<char> rawBytes, Ref<String> text);
DecoderResult(ArrayRef<char> rawBytes, Ref<String> text, std::string outputCharset);
ArrayRef<char> getRawBytes();
Ref<String> getText();
std::string getCharset();
void setOther(Ref<qrcode::QRCodeDecoderMetaData> other) {
other_ = other;
otherClassName = "QRCodeDecoderMetaData";
};
Ref<qrcode::QRCodeDecoderMetaData> getOther() {
// className = otherClassName;
return other_;
};
string getOtherClassName() { return otherClassName; };
int getQRCodeVersion() const { return qrcodeVersion_; };
void setText(Ref<String> text) { text_ = text; };
string getEcLevel() { return ecLevel_; }
string getCharsetMode() { return charsetMode_; }
};
} // namespace zxing
#endif // __ZXING_COMMON_DECODER_RESULT_HPP__
@@ -0,0 +1,27 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#include "../../precomp.hpp"
#include "detector_result.hpp"
namespace zxing {
DetectorResult::DetectorResult(Ref<BitMatrix> bits, ArrayRef<Ref<ResultPoint> > points,
int dimension, float modulesize)
: bits_(bits), points_(points), dimension_(dimension), modulesize_(modulesize) {}
void DetectorResult::SetGray(Ref<ByteMatrix> gray) { gray_ = gray; }
Ref<BitMatrix> DetectorResult::getBits() { return bits_; }
Ref<ByteMatrix> DetectorResult::getGray() { return gray_; }
ArrayRef<Ref<ResultPoint> > DetectorResult::getPoints() { return points_; }
} // namespace zxing
@@ -0,0 +1,42 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#ifndef __ZXING_COMMON_DETECTOR_RESULT_HPP__
#define __ZXING_COMMON_DETECTOR_RESULT_HPP__
#include "../resultpoint.hpp"
#include "array.hpp"
#include "bitmatrix.hpp"
#include "bytematrix.hpp"
#include "counted.hpp"
namespace zxing {
class DetectorResult : public Counted {
private:
Ref<BitMatrix> bits_;
Ref<ByteMatrix> gray_;
ArrayRef<Ref<ResultPoint> > points_;
public:
DetectorResult(Ref<BitMatrix> bits, ArrayRef<Ref<ResultPoint> > points, int dimension = 0,
float modulesize = 0);
DetectorResult(Ref<ByteMatrix> gray, ArrayRef<Ref<ResultPoint> > points, int dimension = 0,
float modulesize = 0);
Ref<BitMatrix> getBits();
Ref<ByteMatrix> getGray();
void SetGray(Ref<ByteMatrix> gray);
ArrayRef<Ref<ResultPoint> > getPoints();
int dimension_;
float modulesize_;
};
} // namespace zxing
#endif // __ZXING_COMMON_DETECTOR_RESULT_HPP__
@@ -0,0 +1,77 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#include "../../precomp.hpp"
#include "greyscale_luminance_source.hpp"
#include "bytematrix.hpp"
#include "greyscale_rotated_luminance_source.hpp"
using zxing::ArrayRef;
using zxing::ByteMatrix;
using zxing::ErrorHandler;
using zxing::GreyscaleLuminanceSource;
using zxing::LuminanceSource;
using zxing::Ref;
GreyscaleLuminanceSource::GreyscaleLuminanceSource(ArrayRef<char> greyData, int dataWidth,
int dataHeight, int left, int top, int width,
int height, ErrorHandler& err_handler)
: Super(width, height),
greyData_(greyData),
dataWidth_(dataWidth),
dataHeight_(dataHeight),
left_(left),
top_(top) {
if (left + width > dataWidth || top + height > dataHeight || top < 0 || left < 0) {
err_handler = IllegalArgumentErrorHandler("Crop rectangle does not fit within image data.");
}
}
ArrayRef<char> GreyscaleLuminanceSource::getRow(int y, ArrayRef<char> row,
ErrorHandler& err_handler) const {
if (y < 0 || y >= this->getHeight()) {
err_handler = IllegalArgumentErrorHandler("Requested row is outside the image.");
return ArrayRef<char>();
}
int width = getWidth();
if (!row || row->size() < width) {
ArrayRef<char> temp(width);
row = temp;
}
int offset = (y + top_) * dataWidth_ + left_;
memcpy(&row[0], &greyData_[offset], width);
return row;
}
ArrayRef<char> GreyscaleLuminanceSource::getMatrix() const {
int size = getWidth() * getHeight();
ArrayRef<char> result(size);
if (left_ == 0 && top_ == 0 && dataWidth_ == getWidth() && dataHeight_ == getHeight()) {
memcpy(&result[0], &greyData_[0], size);
} else {
for (int row = 0; row < getHeight(); row++) {
memcpy(&result[row * getWidth()], &greyData_[(top_ + row) * dataWidth_ + left_],
getWidth());
}
}
return result;
}
Ref<LuminanceSource> GreyscaleLuminanceSource::rotateCounterClockwise(
ErrorHandler& err_handler) const {
// Intentionally flip the left, top, width, and height arguments as
// needed. dataWidth and dataHeight are always kept unrotated.
Ref<LuminanceSource> result(new GreyscaleRotatedLuminanceSource(
greyData_, dataWidth_, dataHeight_, top_, left_, getHeight(), getWidth(), err_handler));
if (err_handler.ErrCode()) return Ref<LuminanceSource>();
return result;
}
Ref<ByteMatrix> GreyscaleLuminanceSource::getByteMatrix() const {
return Ref<ByteMatrix>(new ByteMatrix(getWidth(), getHeight(), getMatrix()));
}
@@ -0,0 +1,44 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#ifndef __ZXING_COMMON_GREYSCALE_LUMINANCE_SOURCE_HPP__
#define __ZXING_COMMON_GREYSCALE_LUMINANCE_SOURCE_HPP__
#include "../errorhandler.hpp"
#include "../luminance_source.hpp"
#include "bytematrix.hpp"
namespace zxing {
class GreyscaleLuminanceSource : public LuminanceSource {
private:
typedef LuminanceSource Super;
ArrayRef<char> greyData_;
const int dataWidth_;
const int dataHeight_;
const int left_;
const int top_;
public:
GreyscaleLuminanceSource(ArrayRef<char> greyData, int dataWidth, int dataHeight, int left,
int top, int width, int height, ErrorHandler& err_handler);
ArrayRef<char> getRow(int y, ArrayRef<char> row, ErrorHandler& err_handler) const override;
ArrayRef<char> getMatrix() const override;
Ref<ByteMatrix> getByteMatrix() const override;
bool isRotateSupported() const override { return true; }
Ref<LuminanceSource> rotateCounterClockwise(ErrorHandler& err_handler) const override;
};
} // namespace zxing
#endif // __ZXING_COMMON_GREYSCALE_LUMINANCE_SOURCE_HPP__
@@ -0,0 +1,67 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#include "../../precomp.hpp"
#include "greyscale_rotated_luminance_source.hpp"
#include "bytematrix.hpp"
using zxing::ArrayRef;
using zxing::ByteMatrix;
using zxing::ErrorHandler;
using zxing::GreyscaleRotatedLuminanceSource;
using zxing::Ref;
// Note that dataWidth and dataHeight are not reversed, as we need to
// be able to traverse the greyData correctly, which does not get
// rotated.
GreyscaleRotatedLuminanceSource::GreyscaleRotatedLuminanceSource(ArrayRef<char> greyData,
int dataWidth, int dataHeight,
int left, int top, int _width,
int _height,
ErrorHandler& err_handler)
: Super(_width, _height), greyData_(greyData), dataWidth_(dataWidth), left_(left), top_(top) {
// Intentionally comparing to the opposite dimension since we're rotated.
if (left + _width > dataHeight || top + _height > dataWidth) {
err_handler = IllegalArgumentErrorHandler("Crop rectangle does not fit within image data.");
}
}
// The API asks for rows, but we're rotated, so we return columns.
ArrayRef<char> GreyscaleRotatedLuminanceSource::getRow(int y, ArrayRef<char> row,
ErrorHandler& err_handler) const {
if (y < 0 || y >= getHeight()) {
err_handler = IllegalArgumentErrorHandler("Requested row is outside the image.");
return ArrayRef<char>();
}
if (!row || row->size() < getWidth()) {
row = ArrayRef<char>(getWidth());
}
int offset = (left_ * dataWidth_) + (dataWidth_ - 1 - (y + top_));
for (int x = 0; x < getWidth(); x++) {
row[x] = greyData_[offset];
offset += dataWidth_;
}
return row;
}
ArrayRef<char> GreyscaleRotatedLuminanceSource::getMatrix() const {
ArrayRef<char> result(getWidth() * getHeight());
for (int y = 0; y < getHeight(); y++) {
char* row = &result[y * getWidth()];
int offset = (left_ * dataWidth_) + (dataWidth_ - 1 - (y + top_));
for (int x = 0; x < getWidth(); x++) {
row[x] = greyData_[offset];
offset += dataWidth_;
}
}
return result;
}
Ref<ByteMatrix> GreyscaleRotatedLuminanceSource::getByteMatrix() const {
return Ref<ByteMatrix>(new ByteMatrix(getWidth(), getHeight(), getMatrix()));
}
@@ -0,0 +1,39 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#ifndef __ZXING_COMMON_GREYSCALE_ROTATED_LUMINANCE_SOURCE_HPP__
#define __ZXING_COMMON_GREYSCALE_ROTATED_LUMINANCE_SOURCE_HPP__
#include "../errorhandler.hpp"
#include "../luminance_source.hpp"
#include "bytematrix.hpp"
namespace zxing {
class GreyscaleRotatedLuminanceSource : public LuminanceSource {
private:
typedef LuminanceSource Super;
ArrayRef<char> greyData_;
const int dataWidth_;
const int left_;
const int top_;
public:
GreyscaleRotatedLuminanceSource(ArrayRef<char> greyData, int dataWidth, int dataHeight,
int left, int top, int _width, int _height,
ErrorHandler& err_handler);
ArrayRef<char> getRow(int y, ArrayRef<char> row, ErrorHandler& err_handler) const override;
ArrayRef<char> getMatrix() const override;
Ref<ByteMatrix> getByteMatrix() const override;
};
} // namespace zxing
#endif // __ZXING_COMMON_GREYSCALE_ROTATED_LUMINANCE_SOURCE_HPP__
@@ -0,0 +1,119 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#include "../../precomp.hpp"
#include "grid_sampler.hpp"
#include "perspective_transform.hpp"
#include <sstream>
namespace zxing {
GridSampler GridSampler::gridSampler;
GridSampler::GridSampler() {}
// Samples an image for a rectangular matrix of bits of the given dimension.
Ref<BitMatrix> GridSampler::sampleGrid(Ref<BitMatrix> image, int dimension,
Ref<PerspectiveTransform> transform,
ErrorHandler &err_handler) {
Ref<BitMatrix> bits(new BitMatrix(dimension, err_handler));
if (err_handler.ErrCode()) return Ref<BitMatrix>();
vector<float> points(dimension << 1, 0.0f);
int outlier = 0;
int maxOutlier = dimension * dimension * 3 / 10 - 1;
for (int y = 0; y < dimension; y++) {
int max = points.size();
float yValue = (float)y + 0.5f;
for (int x = 0; x < max; x += 2) {
points[x] = (float)(x >> 1) + 0.5f;
points[x + 1] = yValue;
}
transform->transformPoints(points);
// Quick check to see if points transformed to something inside the
// image; sufficient to check the endpoings
outlier += checkAndNudgePoints(image->getWidth(), image->getHeight(), points, err_handler);
if (err_handler.ErrCode()) return Ref<BitMatrix>();
if (outlier >= maxOutlier) {
ostringstream s;
s << "Over 30% points out of bounds.";
err_handler = ReaderErrorHandler(s.str().c_str());
return Ref<BitMatrix>();
}
for (int x = 0; x < max; x += 2) {
if (image->get((int)points[x], (int)points[x + 1])) {
// Black (-ish) pixel
bits->set(x >> 1, y);
}
}
}
return bits;
}
int GridSampler::checkAndNudgePoints(int width, int height, vector<float> &points,
ErrorHandler &err_handler) {
// Modified to support stlport
float *pts = NULL;
if (points.size() > 0) {
pts = &points[0];
} else {
err_handler = ReaderErrorHandler("checkAndNudgePoints:: no points!");
return -1;
}
int size = (int)points.size() / 2;
// The Java code assumes that if the start and end points are in bounds, the
// rest will also be. However, in some unusual cases points in the middle
// may also be out of bounds. Since we can't rely on an
// ArrayIndexOutOfBoundsException like Java, we check every point.
int outCount = 0;
// int maxError = (int)(size/2/3 - 1);
float maxborder = width / size * 3;
for (size_t offset = 0; offset < points.size(); offset += 2) {
int x = (int)pts[offset];
int y = (int)pts[offset + 1];
// if((int)offset==0)
// cout<<"checkAndNudgePoints "<<(int)offset<<": ("<<x<<",
//"<<y<<")"<<endl;
if (x < -1 || x > width || y < -1 || y > height) {
outCount++;
if (x > width + maxborder || y > height + maxborder || x < -maxborder ||
y < -maxborder) {
err_handler = ReaderErrorHandler("checkAndNudgePoints::Out of bounds!");
return -1;
}
}
if (x <= -1) {
points[offset] = 0.0f;
} else if (x >= width) {
points[offset] = float(width - 1);
}
if (y <= -1) {
points[offset + 1] = 0.0f;
} else if (y >= height) {
points[offset + 1] = float(height - 1);
}
}
return outCount;
}
GridSampler &GridSampler::getInstance() { return gridSampler; }
} // namespace zxing
@@ -0,0 +1,34 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#ifndef __ZXING_COMMON_GRID_SAMPLER_HPP__
#define __ZXING_COMMON_GRID_SAMPLER_HPP__
#include "bitmatrix.hpp"
#include "bytematrix.hpp"
#include "counted.hpp"
#include "perspective_transform.hpp"
namespace zxing {
class GridSampler {
private:
static GridSampler gridSampler;
GridSampler();
public:
Ref<BitMatrix> sampleGrid(Ref<BitMatrix> image, int dimension,
Ref<PerspectiveTransform> transform, ErrorHandler &err_handler);
static int checkAndNudgePoints(int width, int height, vector<float> &points,
ErrorHandler &err_handler);
static GridSampler &getInstance();
};
} // namespace zxing
#endif // __ZXING_COMMON_GRID_SAMPLER_HPP__
@@ -0,0 +1,66 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
#include "../../precomp.hpp"
#include "imagecut.hpp"
namespace zxing {
ImageCut::ImageCut() {}
ImageCut::~ImageCut() {}
int ImageCut::Cut(uint8_t* poImageData, int iWidth, int iHeight, int iTopLeftX, int iTopLeftY,
int iBottomRightX, int iBottomRightY, ImageCutResult& result) {
if (iTopLeftX < 0 || iTopLeftX > iBottomRightX || iBottomRightX >= iWidth) return -1;
if (iTopLeftY < 0 || iTopLeftY > iBottomRightY || iBottomRightY >= iHeight) return -1;
int iNewWidth = iBottomRightX - iTopLeftX + 1;
int iNewHeight = iBottomRightY - iTopLeftY + 1;
result.arrImage = new Array<uint8_t>(iNewWidth * iNewHeight);
result.iHeight = iNewHeight;
result.iWidth = iNewWidth;
int idx = 0;
for (int y = 0; y < iHeight; ++y) {
if (y < iTopLeftY || y > iBottomRightY) continue;
for (int x = 0; x < iWidth; ++x) {
if (x < iTopLeftX || x > iBottomRightX) continue;
result.arrImage[idx++] = poImageData[y * iWidth + x];
}
}
return 0;
}
int ImageCut::Cut(Ref<ByteMatrix> matrix, float fRatio, ImageCutResult& result) {
int iWidth = matrix->getWidth();
int iHeight = matrix->getHeight();
int iMinX = iWidth * (1 - fRatio) / 2;
int iMinY = iHeight * (1 - fRatio) / 2;
int iMaxX = iWidth * (1 + fRatio) / 2 - 1;
int iMaxY = iHeight * (1 + fRatio) / 2 - 1;
if (iMinY < 0 || iMinY > iMaxX || iMaxX >= iWidth) return -1;
if (iMinX < 0 || iMinX > iMaxX || iMaxX >= iWidth) return -1;
int iNewHeight = iMaxY - iMinY + 1;
int iNewWidth = iMaxX - iMinX + 1;
result.arrImage = new Array<uint8_t>(iNewWidth * iNewHeight);
result.iWidth = iNewWidth;
result.iHeight = iNewHeight;
int idx = 0;
for (int y = 0; y < iNewHeight; ++y) {
for (int x = 0; x < iNewWidth; ++x) {
result.arrImage[idx++] = matrix->get(x + iMinX, y + iMinY);
}
}
return 0;
}
} // namespace zxing
@@ -0,0 +1,32 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
#ifndef __ZXING_COMMON_IMAGECUT_HPP__
#define __ZXING_COMMON_IMAGECUT_HPP__
#include "bytematrix.hpp"
#include "counted.hpp"
namespace zxing {
typedef struct _ImageCutResult {
ArrayRef<uint8_t> arrImage;
int iWidth;
int iHeight;
} ImageCutResult;
class ImageCut {
public:
ImageCut();
~ImageCut();
static int Cut(uint8_t* poImageData, int iWidth, int iHeight, int iTopLeftX, int iTopLeftY,
int iBottomRightX, int iBottomRightY, ImageCutResult& result);
static int Cut(Ref<ByteMatrix> matrix, float fRatio, ImageCutResult& result);
};
} // namespace zxing
#endif // __ZXING_COMMON_IMAGECUT_HPP__
@@ -0,0 +1,89 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
#include "../../precomp.hpp"
#include "kmeans.hpp"
typedef unsigned int uint;
namespace zxing {
double cal_distance(vector<double> a, vector<double> b) {
const float KMEANS_COUNT_FACTOR = 0;
const float KMEANS_MS_FACTOR = 1;
uint da = a.size();
double val = 0.0;
for (uint i = 0; i < da; i++) {
if (i == 1)
val += KMEANS_MS_FACTOR * pow((a[i] - b[i]), 2);
else if (i == 0)
val += KMEANS_COUNT_FACTOR * pow((a[i] - b[i]), 2);
else
val += pow((a[i] - b[i]), 2);
}
return pow(val, 0.5);
}
/*
* maxepoches max iteration epochs
* minchanged min central change times
*/
vector<Cluster> k_means(vector<vector<double> > trainX, uint k, uint maxepoches, uint minchanged) {
const uint row_num = trainX.size();
const uint col_num = trainX[0].size();
// initialize the cluster central
vector<Cluster> clusters(k);
int step = trainX.size() / k;
for (uint i = 0; i < k; i++) {
clusters[i].centroid = trainX[i * step];
}
// try max epochs times iteration untill convergence
for (uint it = 0; it < maxepoches; it++) {
for (uint i = 0; i < k; i++) {
clusters[i].samples.clear();
}
for (uint j = 0; j < row_num; j++) {
uint c = 0;
double min_distance = cal_distance(trainX[j], clusters[c].centroid);
for (uint i = 1; i < k; i++) {
double distance = cal_distance(trainX[j], clusters[i].centroid);
if (distance < min_distance) {
min_distance = distance;
c = i;
}
}
clusters[c].samples.push_back(j);
}
uint changed = 0;
// update cluster central
for (uint i = 0; i < k; i++) {
vector<double> val(col_num, 0.0);
for (uint j = 0; j < clusters[i].samples.size(); j++) {
uint sample = clusters[i].samples[j];
for (uint d = 0; d < col_num; d++) {
val[d] += trainX[sample][d];
if (j == clusters[i].samples.size() - 1) {
double value = val[d] / clusters[i].samples.size();
if (clusters[i].centroid[d] != value) {
clusters[i].centroid[d] = value;
changed++;
}
}
}
}
}
if (changed <= minchanged) return clusters;
}
return clusters;
}
} // namespace zxing
@@ -0,0 +1,26 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
#ifndef __ZXING_COMMON_KMEANS_HPP__
#define __ZXING_COMMON_KMEANS_HPP__
#include <vector>
namespace zxing {
using namespace std;
typedef unsigned int uint;
struct Cluster {
vector<double> centroid;
vector<uint> samples;
};
double cal_distance(vector<double> a, vector<double> b);
vector<Cluster> k_means(vector<vector<double> > trainX, uint k, uint maxepoches, uint minchanged);
} // namespace zxing
#endif // __ZXING_COMMON_KMEANS_HPP__
@@ -0,0 +1,95 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#ifndef __ZXING_COMMON_MATHUTILS_HPP__
#define __ZXING_COMMON_MATHUTILS_HPP__
#include <cmath>
#if (defined __GNUC__ && defined __x86_64__ && defined __SSE2__ && !defined __APPLE__ && \
!defined __GXX_WEAK__)
#include <ammintrin.h>
#elif defined _MSC_VER && (defined _M_X64 || defined _M_IX86)
#include <emmintrin.h>
#endif
#include <algorithm>
#include <numeric>
#include <vector>
namespace zxing {
namespace common {
class MathUtils {
private:
MathUtils();
~MathUtils();
public:
static inline float distance(float aX, float aY, float bX, float bY) {
float xDiff = aX - bX;
float yDiff = aY - bY;
return sqrt(float(xDiff * xDiff + yDiff * yDiff));
}
static inline float distance_4_int(int aX, int aY, int bX, int bY) {
return sqrt(float((aX - bX) * (aX - bX) + (aY - bY) * (aY - bY)));
}
static inline void getRangeValues(int& minValue, int& maxValue, int min, int max) {
int finalMinValue, finalMaxValue;
if (minValue < maxValue) {
finalMinValue = minValue;
finalMaxValue = maxValue;
} else {
finalMinValue = maxValue;
finalMaxValue = minValue;
}
finalMinValue = finalMinValue > min ? finalMinValue : min;
finalMaxValue = finalMaxValue < max ? finalMaxValue : max;
minValue = finalMinValue;
maxValue = finalMaxValue;
}
static inline bool isInRange(float x, float y, float width, float height) {
if ((x >= 0.0 && x <= (width - 1.0)) && (y >= 0.0 && y <= (height - 1.0))) {
return true;
} else {
return false;
}
}
static inline float distance(int aX, int aY, int bX, int bY) {
int xDiff = aX - bX;
int yDiff = aY - bY;
return sqrt(float(xDiff * xDiff + yDiff * yDiff));
}
static inline float VecCross(float* v1, float* v2) { return v1[0] * v2[1] - v1[1] * v2[0]; }
static inline void Stddev(std::vector<float>& resultSet, float& avg, float& stddev) {
double sum = std::accumulate(resultSet.begin(), resultSet.end(), 0.0);
avg = sum / resultSet.size();
double accum = 0.0;
for (std::size_t i = 0; i < resultSet.size(); i++) {
accum += (resultSet[i] - avg) * (resultSet[i] - avg);
}
stddev = sqrt(accum / (resultSet.size()));
}
};
} // namespace common
} // namespace zxing
#endif // __ZXING_COMMON_MATHUTILS_HPP__
@@ -0,0 +1,120 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#include "../../precomp.hpp"
#include "perspective_transform.hpp"
namespace zxing {
// This class implements a perspective transform in two dimensions. Given four
// source and four destination points, it will compute the transformation
// implied between them. The code is based directly upon section 3.4.2 of George
// Wolberg's "Digital Image Warping"; see pages 54-56
PerspectiveTransform::PerspectiveTransform(float inA11, float inA21, float inA31, float inA12,
float inA22, float inA32, float inA13, float inA23,
float inA33)
: a11(inA11),
a12(inA12),
a13(inA13),
a21(inA21),
a22(inA22),
a23(inA23),
a31(inA31),
a32(inA32),
a33(inA33) {}
Ref<PerspectiveTransform> PerspectiveTransform::quadrilateralToQuadrilateral(
float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float x0p,
float y0p, float x1p, float y1p, float x2p, float y2p, float x3p, float y3p) {
Ref<PerspectiveTransform> qToS =
PerspectiveTransform::quadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3);
Ref<PerspectiveTransform> sToQ =
PerspectiveTransform::squareToQuadrilateral(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p);
return sToQ->times(qToS);
}
Ref<PerspectiveTransform> PerspectiveTransform::squareToQuadrilateral(float x0, float y0, float x1,
float y1, float x2, float y2,
float x3, float y3) {
float dx3 = x0 - x1 + x2 - x3;
float dy3 = y0 - y1 + y2 - y3;
if (fabs(dx3) <= 1e-6 && fabs(dy3) <= 1e-6) {
Ref<PerspectiveTransform> result(
new PerspectiveTransform(x1 - x0, x2 - x1, x0, y1 - y0, y2 - y1, y0, 0.0f, 0.0f, 1.0f));
return result;
} else {
float dx1 = x1 - x2;
float dx2 = x3 - x2;
float dy1 = y1 - y2;
float dy2 = y3 - y2;
float denominator = dx1 * dy2 - dx2 * dy1;
float a13 = (dx3 * dy2 - dx2 * dy3) / denominator;
float a23 = (dx1 * dy3 - dx3 * dy1) / denominator;
Ref<PerspectiveTransform> result(
new PerspectiveTransform(x1 - x0 + a13 * x1, x3 - x0 + a23 * x3, x0, y1 - y0 + a13 * y1,
y3 - y0 + a23 * y3, y0, a13, a23, 1.0f));
return result;
}
}
Ref<PerspectiveTransform> PerspectiveTransform::quadrilateralToSquare(float x0, float y0, float x1,
float y1, float x2, float y2,
float x3, float y3) {
// Here, the adjoint serves as the inverse:
return squareToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3)->buildAdjoint();
}
Ref<PerspectiveTransform> PerspectiveTransform::buildAdjoint() {
// Adjoint is the transpose of the cofactor matrix:
Ref<PerspectiveTransform> result(new PerspectiveTransform(
a22 * a33 - a23 * a32, a23 * a31 - a21 * a33, a21 * a32 - a22 * a31, a13 * a32 - a12 * a33,
a11 * a33 - a13 * a31, a12 * a31 - a11 * a32, a12 * a23 - a13 * a22, a13 * a21 - a11 * a23,
a11 * a22 - a12 * a21));
return result;
}
Ref<PerspectiveTransform> PerspectiveTransform::times(Ref<PerspectiveTransform> other) {
Ref<PerspectiveTransform> result(
new PerspectiveTransform(a11 * other->a11 + a21 * other->a12 + a31 * other->a13,
a11 * other->a21 + a21 * other->a22 + a31 * other->a23,
a11 * other->a31 + a21 * other->a32 + a31 * other->a33,
a12 * other->a11 + a22 * other->a12 + a32 * other->a13,
a12 * other->a21 + a22 * other->a22 + a32 * other->a23,
a12 * other->a31 + a22 * other->a32 + a32 * other->a33,
a13 * other->a11 + a23 * other->a12 + a33 * other->a13,
a13 * other->a21 + a23 * other->a22 + a33 * other->a23,
a13 * other->a31 + a23 * other->a32 + a33 * other->a33));
return result;
}
void PerspectiveTransform::transformPoints(vector<float>& points) {
int max = points.size();
// Modified to support stlport
float* pts = NULL;
if (points.size() > 0) {
pts = &points[0];
}
for (int i = 0; i < max; i += 2) {
float x = pts[i];
float y = pts[i + 1];
float denominator = a13 * x + a23 * y + a33;
float w = 1.0f / denominator;
pts[i] = (a11 * x + a21 * y + a31) * w;
pts[i + 1] = (a12 * x + a22 * y + a32) * w;
}
}
} // namespace zxing
@@ -0,0 +1,39 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#ifndef __ZXING_COMMON_PERSPECTIVETRANSFORM_HPP__
#define __ZXING_COMMON_PERSPECTIVETRANSFORM_HPP__
#include "counted.hpp"
#include <vector>
namespace zxing {
class PerspectiveTransform : public Counted {
private:
float a11, a12, a13, a21, a22, a23, a31, a32, a33;
PerspectiveTransform(float a11, float a21, float a31, float a12, float a22, float a32,
float a13, float a23, float a33);
public:
static Ref<PerspectiveTransform> quadrilateralToQuadrilateral(
float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float x0p,
float y0p, float x1p, float y1p, float x2p, float y2p, float x3p, float y3p);
static Ref<PerspectiveTransform> squareToQuadrilateral(float x0, float y0, float x1, float y1,
float x2, float y2, float x3, float y3);
static Ref<PerspectiveTransform> quadrilateralToSquare(float x0, float y0, float x1, float y1,
float x2, float y2, float x3, float y3);
Ref<PerspectiveTransform> buildAdjoint();
Ref<PerspectiveTransform> times(Ref<PerspectiveTransform> other);
void transformPoints(std::vector<float>& points);
};
} // namespace zxing
#endif // __ZXING_COMMON_PERSPECTIVETRANSFORM_HPP__
@@ -0,0 +1,99 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#include "../../../precomp.hpp"
#include "genericgf.hpp"
#include "genericgfpoly.hpp"
using zxing::ErrorHandler;
using zxing::GenericGF;
using zxing::GenericGFPoly;
using zxing::Ref;
GenericGF::GenericGF(int primitive_, int size_, int b, ErrorHandler &err_handler)
: size(size_), primitive(primitive_), generatorBase(b) {
expTable.resize(size);
logTable.resize(size);
int x = 1;
for (int i = 0; i < size; i++) {
expTable[i] = x;
x <<= 1; // x = x * 2; we're assuming the generator alpha is 2
if (x >= size) {
x ^= primitive;
x &= size - 1;
}
}
for (int i = 0; i < size - 1; i++) {
logTable[expTable[i]] = i;
}
// logTable[0] == 0 but this should never be used
zero =
Ref<GenericGFPoly>(new GenericGFPoly(*this, ArrayRef<int>(new Array<int>(1)), err_handler));
zero->getCoefficients()[0] = 0;
one =
Ref<GenericGFPoly>(new GenericGFPoly(*this, ArrayRef<int>(new Array<int>(1)), err_handler));
one->getCoefficients()[0] = 1;
if (err_handler.ErrCode()) return;
// initialized = true;
}
Ref<GenericGFPoly> GenericGF::getZero() { return zero; }
Ref<GenericGFPoly> GenericGF::getOne() { return one; }
Ref<GenericGFPoly> GenericGF::buildMonomial(int degree, int coefficient,
ErrorHandler &err_handler) {
if (degree < 0) {
err_handler = IllegalArgumentErrorHandler("Degree must be non-negative");
return Ref<GenericGFPoly>();
}
if (coefficient == 0) {
return zero;
}
ArrayRef<int> coefficients(new Array<int>(degree + 1));
coefficients[0] = coefficient;
Ref<GenericGFPoly> gfpoly(new GenericGFPoly(*this, coefficients, err_handler));
if (err_handler.ErrCode()) return Ref<GenericGFPoly>();
return gfpoly;
}
int GenericGF::addOrSubtract(int a, int b) { return a ^ b; }
int GenericGF::exp(int a) { return expTable[a]; }
int GenericGF::log(int a, ErrorHandler &err_handler) {
if (a == 0) {
err_handler = IllegalArgumentErrorHandler("cannot give log(0)");
return -1;
}
return logTable[a];
}
int GenericGF::inverse(int a, ErrorHandler &err_handler) {
if (a == 0) {
err_handler = IllegalArgumentErrorHandler("Cannot calculate the inverse of 0");
return -1;
}
return expTable[size - logTable[a] - 1];
}
int GenericGF::multiply(int a, int b) {
if (a == 0 || b == 0) {
return 0;
}
return expTable[(logTable[a] + logTable[b]) % (size - 1)];
}
int GenericGF::getSize() { return size; }
int GenericGF::getGeneratorBase() { return generatorBase; }
@@ -0,0 +1,58 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#ifndef __ZXING_COMMON_REEDSOLOMON_GENERICGF_HPP__
#define __ZXING_COMMON_REEDSOLOMON_GENERICGF_HPP__
#include "../../errorhandler.hpp"
#include "../counted.hpp"
namespace zxing {
class GenericGFPoly;
static zxing::ErrorHandler gf_err_handler_;
#define GF_AZTEC_DATA_12 (new GenericGF(0x1069, 4096, 1, gf_err_handler_))
#define GF_AZTEC_DATA_10 (new GenericGF(0x409, 1024, 1, gf_err_handler_))
#define GF_AZTEC_DATA_6 (new GenericGF(0x43, 64, 1, gf_err_handler_))
#define GF_AZTEC_PARAM (new GenericGF(0x13, 16, 1, gf_err_handler_))
#define GF_QR_CODE_FIELD_256 (new GenericGF(0x011D, 256, 0, gf_err_handler_))
#define GF_DATA_MATRIX_FIELD_256 (new GenericGF(0x012D, 256, 1, gf_err_handler_))
#define GF_AZTEC_DATA_8 (new GenericGF(0x012D, 256, 1, gf_err_handler_))
#define GF_MAXICODE_FIELD_64 (new GenericGF(0x43, 64, 1, gf_err_handler_))
// #define GF_WXCODE (new GenericGF(0x011D, 256, 0, gf_err_handler_))
class GenericGF : public Counted {
private:
std::vector<int> expTable;
std::vector<int> logTable;
Ref<GenericGFPoly> zero;
Ref<GenericGFPoly> one;
int size;
int primitive;
int generatorBase;
public:
GenericGF(int primitive, int size, int b, ErrorHandler &err_handler);
Ref<GenericGFPoly> getZero();
Ref<GenericGFPoly> getOne();
int getSize();
int getGeneratorBase();
Ref<GenericGFPoly> buildMonomial(int degree, int coefficient, ErrorHandler &err_handler);
static int addOrSubtract(int a, int b);
int exp(int a);
int log(int a, ErrorHandler &err_handler);
int inverse(int a, ErrorHandler &err_handler);
int multiply(int a, int b);
};
} // namespace zxing
#endif // __ZXING_COMMON_REEDSOLOMON_GENERICGF_HPP__
@@ -0,0 +1,231 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#include "../../../precomp.hpp"
#include "genericgfpoly.hpp"
#include "genericgf.hpp"
using zxing::ArrayRef;
using zxing::ErrorHandler;
using zxing::GenericGFPoly;
using zxing::Ref;
// VC++
using zxing::GenericGF;
GenericGFPoly::GenericGFPoly(GenericGF &field, ArrayRef<int> coefficients,
ErrorHandler &err_handler)
: field_(field) {
if (coefficients->size() == 0) {
err_handler = IllegalArgumentErrorHandler("need coefficients");
return;
}
int coefficientsLength = coefficients->size();
if (coefficientsLength > 1 && coefficients[0] == 0) {
// Leading term must be non-zero for anything except the constant
// polynomial "0"
int firstNonZero = 1;
while (firstNonZero < coefficientsLength && coefficients[firstNonZero] == 0) {
firstNonZero++;
}
if (firstNonZero == coefficientsLength) {
coefficients_ = field.getZero()->getCoefficients();
} else {
coefficients_ = ArrayRef<int>(new Array<int>(coefficientsLength - firstNonZero));
for (int i = 0; i < (int)coefficients_->size(); i++) {
coefficients_[i] = coefficients[i + firstNonZero];
}
}
} else {
coefficients_ = coefficients;
}
}
ArrayRef<int> GenericGFPoly::getCoefficients() { return coefficients_; }
int GenericGFPoly::getDegree() { return coefficients_->size() - 1; }
bool GenericGFPoly::isZero() { return coefficients_[0] == 0; }
int GenericGFPoly::getCoefficient(int degree) {
return coefficients_[coefficients_->size() - 1 - degree];
}
int GenericGFPoly::evaluateAt(int a) {
if (a == 0) {
// Just return the x^0 coefficient
return getCoefficient(0);
}
int size = coefficients_->size();
if (a == 1) {
// Just the sum of the coefficients
int result = 0;
for (int i = 0; i < size; i++) {
result = GenericGF::addOrSubtract(result, coefficients_[i]);
}
return result;
}
int result = coefficients_[0];
for (int i = 1; i < size; i++) {
result = GenericGF::addOrSubtract(field_.multiply(a, result), coefficients_[i]);
}
return result;
}
Ref<GenericGFPoly> GenericGFPoly::addOrSubtract(Ref<zxing::GenericGFPoly> other,
ErrorHandler &err_handler) {
if (!(&field_ == &other->field_)) {
err_handler =
IllegalArgumentErrorHandler("GenericGFPolys do not have same GenericGF field");
return Ref<GenericGFPoly>();
}
if (isZero()) {
return other;
}
if (other->isZero()) {
return Ref<GenericGFPoly>(this);
}
ArrayRef<int> smallerCoefficients = coefficients_;
ArrayRef<int> largerCoefficients = other->getCoefficients();
if (smallerCoefficients->size() > largerCoefficients->size()) {
ArrayRef<int> temp = smallerCoefficients;
smallerCoefficients = largerCoefficients;
largerCoefficients = temp;
}
ArrayRef<int> sumDiff(new Array<int>(largerCoefficients->size()));
int lengthDiff = largerCoefficients->size() - smallerCoefficients->size();
// Copy high-order terms only found in higher-degree polynomial's
// coefficients
for (int i = 0; i < lengthDiff; i++) {
sumDiff[i] = largerCoefficients[i];
}
for (int i = lengthDiff; i < (int)largerCoefficients->size(); i++) {
sumDiff[i] =
GenericGF::addOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]);
}
// return Ref<GenericGFPoly>(new GenericGFPoly(field_, sumDiff));
Ref<GenericGFPoly> gfpoly(new GenericGFPoly(field_, sumDiff, err_handler));
if (err_handler.ErrCode()) return Ref<GenericGFPoly>();
return gfpoly;
}
Ref<GenericGFPoly> GenericGFPoly::multiply(Ref<zxing::GenericGFPoly> other,
ErrorHandler &err_handler) {
if (!(&field_ == &other->field_)) {
err_handler =
IllegalArgumentErrorHandler("GenericGFPolys do not have same GenericGF field");
return Ref<GenericGFPoly>();
}
if (isZero() || other->isZero()) {
return field_.getZero();
}
ArrayRef<int> aCoefficients = coefficients_;
int aLength = aCoefficients->size();
ArrayRef<int> bCoefficients = other->getCoefficients();
int bLength = bCoefficients->size();
ArrayRef<int> product(new Array<int>(aLength + bLength - 1));
for (int i = 0; i < aLength; i++) {
int aCoeff = aCoefficients[i];
for (int j = 0; j < bLength; j++) {
product[i + j] =
GenericGF::addOrSubtract(product[i + j], field_.multiply(aCoeff, bCoefficients[j]));
}
}
// return Ref<GenericGFPoly>(new GenericGFPoly(field_, product));
Ref<GenericGFPoly> gfpoly(new GenericGFPoly(field_, product, err_handler));
if (err_handler.ErrCode()) return Ref<GenericGFPoly>();
return gfpoly;
}
Ref<GenericGFPoly> GenericGFPoly::multiply(int scalar, ErrorHandler &err_handler) {
if (scalar == 0) {
return field_.getZero();
}
if (scalar == 1) {
return Ref<GenericGFPoly>(this);
}
int size = coefficients_->size();
ArrayRef<int> product(new Array<int>(size));
for (int i = 0; i < size; i++) {
product[i] = field_.multiply(coefficients_[i], scalar);
}
// return Ref<GenericGFPoly>(new GenericGFPoly(field_, product));
Ref<GenericGFPoly> gfpoly(new GenericGFPoly(field_, product, err_handler));
if (err_handler.ErrCode()) return Ref<GenericGFPoly>();
return gfpoly;
}
Ref<GenericGFPoly> GenericGFPoly::multiplyByMonomial(int degree, int coefficient,
ErrorHandler &err_handler) {
if (degree < 0) {
err_handler = IllegalArgumentErrorHandler("degree must not be less then 0");
return Ref<GenericGFPoly>();
}
if (coefficient == 0) {
return field_.getZero();
}
int size = coefficients_->size();
ArrayRef<int> product(new Array<int>(size + degree));
for (int i = 0; i < size; i++) {
product[i] = field_.multiply(coefficients_[i], coefficient);
}
// return Ref<GenericGFPoly>(new GenericGFPoly(field_, product));
Ref<GenericGFPoly> gfpoly(new GenericGFPoly(field_, product, err_handler));
if (err_handler.ErrCode()) return Ref<GenericGFPoly>();
return gfpoly;
}
std::vector<Ref<GenericGFPoly>> GenericGFPoly::divide(Ref<GenericGFPoly> other,
ErrorHandler &err_handler) {
if (!(&field_ == &other->field_)) {
err_handler =
IllegalArgumentErrorHandler("GenericGFPolys do not have same GenericGF field");
return std::vector<Ref<GenericGFPoly>>();
}
if (other->isZero()) {
err_handler = IllegalArgumentErrorHandler("divide by 0");
return std::vector<Ref<GenericGFPoly>>();
}
Ref<GenericGFPoly> quotient = field_.getZero();
Ref<GenericGFPoly> remainder = Ref<GenericGFPoly>(this);
int denominatorLeadingTerm = other->getCoefficient(other->getDegree());
int inverseDenominatorLeadingTerm = field_.inverse(denominatorLeadingTerm, err_handler);
if (err_handler.ErrCode()) return std::vector<Ref<GenericGFPoly>>();
while (remainder->getDegree() >= other->getDegree() && !remainder->isZero()) {
int degreeDifference = remainder->getDegree() - other->getDegree();
int scale = field_.multiply(remainder->getCoefficient(remainder->getDegree()),
inverseDenominatorLeadingTerm);
Ref<GenericGFPoly> term = other->multiplyByMonomial(degreeDifference, scale, err_handler);
if (err_handler.ErrCode()) return std::vector<Ref<GenericGFPoly>>();
Ref<GenericGFPoly> iterationQuotiont =
field_.buildMonomial(degreeDifference, scale, err_handler);
if (err_handler.ErrCode()) return std::vector<Ref<GenericGFPoly>>();
quotient = quotient->addOrSubtract(iterationQuotiont, err_handler);
remainder = remainder->addOrSubtract(term, err_handler);
if (err_handler.ErrCode()) return std::vector<Ref<GenericGFPoly>>();
}
std::vector<Ref<GenericGFPoly>> returnValue(2);
returnValue[0] = quotient;
returnValue[1] = remainder;
return returnValue;
}
@@ -0,0 +1,43 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#ifndef __ZXING_COMMON_REEDSOLOMON_GENERICGFPOLY_HPP__
#define __ZXING_COMMON_REEDSOLOMON_GENERICGFPOLY_HPP__
#include "../../errorhandler.hpp"
#include "../array.hpp"
#include "../counted.hpp"
namespace zxing {
class GenericGF;
class GenericGFPoly : public Counted {
private:
GenericGF &field_;
ArrayRef<int> coefficients_;
public:
GenericGFPoly(GenericGF &field, ArrayRef<int> coefficients, ErrorHandler &err_handler);
ArrayRef<int> getCoefficients();
int getDegree();
bool isZero();
int getCoefficient(int degree);
int evaluateAt(int a);
Ref<GenericGFPoly> addOrSubtract(Ref<GenericGFPoly> other, ErrorHandler &err_handler);
Ref<GenericGFPoly> multiply(Ref<GenericGFPoly> other, ErrorHandler &err_handler);
Ref<GenericGFPoly> multiply(int scalar, ErrorHandler &err_handler);
Ref<GenericGFPoly> multiplyByMonomial(int degree, int coefficient, ErrorHandler &err_handler);
std::vector<Ref<GenericGFPoly>> divide(Ref<GenericGFPoly> other, ErrorHandler &err_handler);
};
} // namespace zxing
#endif // __ZXING_COMMON_REEDSOLOMON_GENERICGFPOLY_HPP__
@@ -0,0 +1,185 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#include "../../../precomp.hpp"
#include "reed_solomon_decoder.hpp"
using zxing::ArrayRef;
using zxing::ErrorHandler;
using zxing::GenericGFPoly;
using zxing::ReedSolomonDecoder;
using zxing::Ref;
using zxing::GenericGF;
ReedSolomonDecoder::ReedSolomonDecoder(Ref<GenericGF> field_) : field(field_) {}
ReedSolomonDecoder::~ReedSolomonDecoder() {}
void ReedSolomonDecoder::decode(ArrayRef<int> received, int twoS, ErrorHandler &err_handler) {
Ref<GenericGFPoly> poly(new GenericGFPoly(*field, received, err_handler));
if (err_handler.ErrCode()) return;
ArrayRef<int> syndromeCoefficients(twoS);
bool noError = true;
for (int i = 0; i < twoS; i++) {
int eval = poly->evaluateAt(field->exp(i + field->getGeneratorBase()));
syndromeCoefficients[syndromeCoefficients->size() - 1 - i] = eval;
if (eval != 0) {
noError = false;
}
}
if (noError) {
return;
}
Ref<GenericGFPoly> syndrome(new GenericGFPoly(*field, syndromeCoefficients, err_handler));
Ref<GenericGFPoly> monomial = field->buildMonomial(twoS, 1, err_handler);
if (!monomial || err_handler.ErrCode()) {
err_handler = ErrorHandler("buildMonomial was zero");
return;
}
vector<Ref<GenericGFPoly>> sigmaOmega =
runEuclideanAlgorithm(monomial, syndrome, twoS, err_handler);
if (err_handler.ErrCode()) return;
Ref<GenericGFPoly> sigma = sigmaOmega[0];
Ref<GenericGFPoly> omega = sigmaOmega[1];
ArrayRef<int> errorLocations = findErrorLocations(sigma, err_handler);
if (err_handler.ErrCode()) return;
ArrayRef<int> errorMagitudes = findErrorMagnitudes(omega, errorLocations, err_handler);
if (err_handler.ErrCode()) return;
for (int i = 0; i < errorLocations->size(); i++) {
int position = received->size() - 1 - field->log(errorLocations[i], err_handler);
if (position < 0 || err_handler.ErrCode()) {
err_handler = ErrorHandler("Bad error location");
return;
}
received[position] = GenericGF::addOrSubtract(received[position], errorMagitudes[i]);
}
}
vector<Ref<GenericGFPoly>> ReedSolomonDecoder::runEuclideanAlgorithm(Ref<GenericGFPoly> a,
Ref<GenericGFPoly> b, int R,
ErrorHandler &err_handler) {
vector<Ref<GenericGFPoly>> result(2);
// Assume a's degree is >= b's
if (a->getDegree() < b->getDegree()) {
Ref<GenericGFPoly> tmp = a;
a = b;
b = tmp;
}
Ref<GenericGFPoly> rLast(a);
Ref<GenericGFPoly> r(b);
Ref<GenericGFPoly> tLast(field->getZero());
Ref<GenericGFPoly> t(field->getOne());
// Run Euclidean algorithm until r's degree is less than R/2
while (r->getDegree() >= R / 2) {
Ref<GenericGFPoly> rLastLast(rLast);
Ref<GenericGFPoly> tLastLast(tLast);
rLast = r;
tLast = t;
// Divide rLastLast by rLast, with quotient q and remainder r
if (rLast->isZero()) {
// Oops, Euclidean algorithm already terminated?
err_handler = ErrorHandler("r_{i-1} was zero");
return vector<Ref<GenericGFPoly>>();
}
r = rLastLast;
Ref<GenericGFPoly> q = field->getZero();
int denominatorLeadingTerm = rLast->getCoefficient(rLast->getDegree());
int dltInverse = field->inverse(denominatorLeadingTerm, err_handler);
if (err_handler.ErrCode()) return vector<Ref<GenericGFPoly>>();
while (r->getDegree() >= rLast->getDegree() && !r->isZero()) {
int degreeDiff = r->getDegree() - rLast->getDegree();
int scale = field->multiply(r->getCoefficient(r->getDegree()), dltInverse);
q = q->addOrSubtract(field->buildMonomial(degreeDiff, scale, err_handler), err_handler);
r = r->addOrSubtract(rLast->multiplyByMonomial(degreeDiff, scale, err_handler),
err_handler);
if (err_handler.ErrCode()) return vector<Ref<GenericGFPoly>>();
}
Ref<GenericGFPoly> tmp = q->multiply(tLast, err_handler);
if (err_handler.ErrCode()) return vector<Ref<GenericGFPoly>>();
t = tmp->addOrSubtract(tLastLast, err_handler);
if (err_handler.ErrCode()) return vector<Ref<GenericGFPoly>>();
if (r->getDegree() >= rLast->getDegree()) {
err_handler = ErrorHandler("Division algorithm failed to reduce polynomial?");
return vector<Ref<GenericGFPoly>>();
}
}
int sigmaTildeAtZero = t->getCoefficient(0);
if (sigmaTildeAtZero == 0) {
err_handler = ErrorHandler("sigmaTilde(0) was zero");
return vector<Ref<GenericGFPoly>>();
}
int inverse = field->inverse(sigmaTildeAtZero, err_handler);
Ref<GenericGFPoly> sigma(t->multiply(inverse, err_handler));
Ref<GenericGFPoly> omega(r->multiply(inverse, err_handler));
if (err_handler.ErrCode()) return vector<Ref<GenericGFPoly>>();
result[0] = sigma;
result[1] = omega;
return result;
}
ArrayRef<int> ReedSolomonDecoder::findErrorLocations(Ref<GenericGFPoly> errorLocator,
ErrorHandler &err_handler) {
// This is a direct application of Chien's search
int numErrors = errorLocator->getDegree();
if (numErrors == 1) { // shortcut
ArrayRef<int> result(new Array<int>(1));
result[0] = errorLocator->getCoefficient(1);
return result;
}
ArrayRef<int> result(new Array<int>(numErrors));
int e = 0;
for (int i = 1; i < field->getSize() && e < numErrors; i++) {
if (errorLocator->evaluateAt(i) == 0) {
result[e] = field->inverse(i, err_handler);
e++;
}
}
if (e != numErrors || err_handler.ErrCode()) {
err_handler = ErrorHandler("Error locator degree does not match number of root");
return ArrayRef<int>();
}
return result;
}
ArrayRef<int> ReedSolomonDecoder::findErrorMagnitudes(Ref<GenericGFPoly> errorEvaluator,
ArrayRef<int> errorLocations,
ErrorHandler &err_handler) {
// This is directly applying Forney's Formula
int s = errorLocations->size();
ArrayRef<int> result(new Array<int>(s));
for (int i = 0; i < s; i++) {
int xiInverse = field->inverse(errorLocations[i], err_handler);
int denominator = 1;
for (int j = 0; j < s; j++) {
if (i != j) {
int term = field->multiply(errorLocations[j], xiInverse);
int termPlus1 = (term & 0x1) == 0 ? term | 1 : term & ~1;
denominator = field->multiply(denominator, termPlus1);
}
}
result[i] = field->multiply(errorEvaluator->evaluateAt(xiInverse),
field->inverse(denominator, err_handler));
if (field->getGeneratorBase() != 0) {
result[i] = field->multiply(result[i], xiInverse);
}
}
if (err_handler.ErrCode()) return ArrayRef<int>();
return result;
}
@@ -0,0 +1,43 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#ifndef __ZXING_COMMON_REEDSOLOMON_REEDSOLOMONDECODER_HPP__
#define __ZXING_COMMON_REEDSOLOMON_REEDSOLOMONDECODER_HPP__
#include "../../errorhandler.hpp"
#include "../array.hpp"
#include "../counted.hpp"
#include "genericgf.hpp"
#include "genericgfpoly.hpp"
namespace zxing {
class GenericGFPoly;
class GenericGF;
class ReedSolomonDecoder {
private:
Ref<GenericGF> field;
public:
explicit ReedSolomonDecoder(Ref<GenericGF> fld);
~ReedSolomonDecoder();
void decode(ArrayRef<int> received, int twoS, ErrorHandler &err_handler);
std::vector<Ref<GenericGFPoly>> runEuclideanAlgorithm(Ref<GenericGFPoly> a,
Ref<GenericGFPoly> b, int R,
ErrorHandler &err_handler);
private:
ArrayRef<int> findErrorLocations(Ref<GenericGFPoly> errorLocator, ErrorHandler &err_handler);
ArrayRef<int> findErrorMagnitudes(Ref<GenericGFPoly> errorEvaluator,
ArrayRef<int> errorLocations, ErrorHandler &err_handler);
};
} // namespace zxing
#endif // __ZXING_COMMON_REEDSOLOMON_REEDSOLOMONDECODER_HPP__
@@ -0,0 +1,96 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#include "../../precomp.hpp"
#include "str.hpp"
using zxing::Ref;
using zxing::String;
using zxing::StrUtil;
String::String(const std::string& text) : text_(text) {}
String::String(int capacity) { text_.reserve(capacity); }
const std::string& String::getText() const { return text_; }
char String::charAt(int i) const { return text_[i]; }
int String::size() const { return text_.size(); }
int String::length() const { return text_.size(); }
Ref<String> String::substring(int i) const { return Ref<String>(new String(text_.substr(i))); }
Ref<String> String::substring(int start, int end) const {
return Ref<String>(new String(text_.substr(start, (end - start))));
}
void String::append(const std::string& tail) { text_.append(tail); }
void String::append(char c) { text_.append(1, c); }
void String::append(int d) {
string str = StrUtil::numberToString(d);
text_.append(str);
}
void String::append(Ref<String> str) { append(str->getText()); }
string StrUtil::COMBINE_STRING(string str1, string str2) {
string str = str1;
str += str2;
return str;
}
string StrUtil::COMBINE_STRING(string str1, char c) {
string str = str1;
str += c;
return str;
}
string StrUtil::COMBINE_STRING(string str1, int d) {
string str = str1;
str += numberToString(d);
return str;
}
Ref<String> StrUtil::COMBINE_STRING(char c1, Ref<String> content, char c2) {
Ref<String> str(new String(0));
str->append(c1);
str->append(content);
str->append(c2);
return str;
}
template <typename T>
string StrUtil::numberToString(T Number) {
ostringstream ss;
ss << Number;
return ss.str();
}
template <typename T>
T StrUtil::stringToNumber(const string& Text) {
std::istringstream ss(Text);
T result;
return ss >> result ? result : 0;
}
int StrUtil::indexOf(const char* str, char c) {
int len = strlen(str);
for (int i = 0; i < len; i++) {
if (str[i] == c) {
return i;
}
}
return -1;
}
@@ -0,0 +1,58 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#ifndef __ZXING_COMMON_STR_HPP__
#define __ZXING_COMMON_STR_HPP__
#include "counted.hpp"
#include <sstream>
#include <string>
using std::string;
namespace zxing {
class String : public Counted {
private:
std::string text_;
public:
explicit String(const std::string& text);
explicit String(int);
char charAt(int) const;
Ref<String> substring(int) const;
Ref<String> substring(int, int) const;
const std::string& getText() const;
int size() const;
void append(std::string const& tail);
void append(char c);
void append(int d);
void append(Ref<String> str);
int length() const;
};
class StrUtil {
public:
static string COMBINE_STRING(string str1, string str2);
static string COMBINE_STRING(string str1, char c);
static string COMBINE_STRING(string str1, int d);
static Ref<String> COMBINE_STRING(char c1, Ref<String> content, char c2);
template <typename T>
static string numberToString(T Number);
template <typename T>
static T stringToNumber(const string& Text);
static int indexOf(const char* str, char c);
};
} // namespace zxing
#endif // __ZXING_COMMON_STR_HPP__
@@ -0,0 +1,683 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#include "../../precomp.hpp"
#include "../common/stringutils.hpp"
#include "../decodehints.hpp"
using namespace zxing::common;
// N.B.: these are the iconv strings for at least some versions of iconv
char const* const StringUtils::PLATFORM_DEFAULT_ENCODING = "ANY";
char const* const StringUtils::ASCII = "ASCII";
char const* const StringUtils::SHIFT_JIS = "SHIFT-JIS";
char const* const StringUtils::GBK = "GBK";
char const* const StringUtils::EUC_JP = "EUC-JP";
char const* const StringUtils::UTF8 = "UTF-8";
char const* const StringUtils::ISO88591 = "ISO8859-1";
char const* const StringUtils::GB2312 = "GB2312";
char const* const StringUtils::BIG5 = "BIG5";
char const* const StringUtils::GB18030 = "GB18030";
const bool StringUtils::ASSUME_SHIFT_JIS = false;
#ifdef USE_UCHARDET
#include "uchardet/uchardet.h"
#endif
// Added convertString
#ifndef NO_ICONV
#include <iconv.h>
// Required for compatibility. TODO: test on Symbian
//#ifdef ZXING_ICONV_CONST
#undef ICONV_CONST
#define ICONV_CONST const
//#endif
#ifndef ICONV_CONST
#define ICONV_CONST /**/
#endif
// Add this to fix both Mac and Windows compilers
// by Skylook
template <class T>
class sloppy {};
// convert between T** and const T**
template <class T>
class sloppy<T**> {
T** t;
public:
sloppy(T** mt) : t(mt) {}
sloppy(const T** mt) : t(const_cast<T**>(mt)) {}
operator T* *() const { return t; }
operator const T* *() const { return const_cast<const T**>(t); }
};
#endif
string StringUtils::convertString(const char* rawData, int length, const char* fromCharset,
const char* toCharset) {
string result;
const char* bufIn = rawData;
int nIn = length;
// If from and to charset are the same, return
int ret = strcmp(fromCharset, toCharset);
if (ret == 0) {
result.append((const char*)bufIn, nIn);
return result;
}
#ifndef NO_ICONV
if (nIn == 0) {
return "";
}
iconv_t cd;
// cout<<src<<endl;
cd = iconv_open(toCharset, fromCharset);
// iconv_t cd = iconv_open(StringUtils::GBK, src);
if (cd == (iconv_t)-1) {
// result.append((const char *)bufIn, nIn);
result = "";
return result;
}
const int maxOut = 4 * nIn + 1;
char* bufOut = new char[maxOut];
ICONV_CONST char* fromPtr = (ICONV_CONST char*)bufIn;
size_t nFrom = nIn;
char* toPtr = (char*)bufOut;
size_t nTo = maxOut;
size_t oneway = -1;
if (nFrom > 0) {
// size_t oneway = iconv(cd, &fromPtr, &nFrom, &toPtr, &nTo);
oneway = iconv(cd, sloppy<char**>(&fromPtr), &nFrom, sloppy<char**>(&toPtr), &nTo);
}
iconv_close(cd);
int nResult = maxOut - nTo;
bufOut[nResult] = '\0';
result.append((const char*)bufOut);
delete[] bufOut;
// Cannot convert string
if (oneway == (size_t)(-1)) {
// result.append((const char *)bufIn, nIn);
result = "";
}
#else
result.append((const char*)bufIn, nIn);
#endif
return result;
}
string StringUtils::guessEncoding(char* bytes, int length) {
#ifdef USE_UCHARDET
if (length < 10) {
return guessEncodingZXing(bytes, length);
} else {
return guessEncodingUCharDet(bytes, length);
}
#else
return guessEncodingZXing(bytes, length);
#endif
}
#ifdef USE_UCHARDET
string StringUtils::guessEncodingUCharDet(char* bytes, int length) {
uchardet_t handle = uchardet_new();
int retval = uchardet_handle_data(handle, bytes, length);
if (retval != 0) {
fprintf(stderr, "Handle data error.\n");
exit(0);
}
uchardet_data_end(handle);
const char* charset = uchardet_get_charset(handle);
string charsetStr(charset);
uchardet_delete(handle);
if (charsetStr.size() != 0) {
return charsetStr;
} else {
return guessEncodingZXing(bytes, length);
}
// Otherwise, we take a wild guess with platform encoding
// return PLATFORM_DEFAULT_ENCODING;
}
#endif
string StringUtils::guessEncodingZXing(char* bytes, int length) {
//
// typedef bool boolean;
// For now, merely tries to distinguish ISO-8859-1, UTF-8 and Shift_JIS,
// which should be by far the most common encodings.
bool canBeISO88591 = true;
bool canBeShiftJIS = true;
bool canBeUTF8 = true;
bool canBeGB2312 = true;
bool canBeGBK = true;
bool canBeBIG5 = true;
bool canBeASCII = true;
int utf8BytesLeft = 0;
int utf2BytesChars = 0;
int utf3BytesChars = 0;
int utf4BytesChars = 0;
int sjisBytesLeft = 0;
int sjisKatakanaChars = 0;
int sjisCurKatakanaWordLength = 0;
int sjisCurDoubleBytesWordLength = 0;
int sjisMaxKatakanaWordLength = 0;
int sjisMaxDoubleBytesWordLength = 0;
int isoHighOther = 0;
int gb2312SCByteChars = 0;
int big5TWBytesChars = 0;
bool utf8bom = length > 3 && (unsigned char)bytes[0] == 0xEF &&
(unsigned char)bytes[1] == 0xBB && (unsigned char)bytes[2] == 0xBF;
for (int i = 0; i < length && (canBeISO88591 || canBeShiftJIS || canBeUTF8 || canBeGBK); i++) {
int value = bytes[i] & 0xFF;
// UTF-8 stuff
if (canBeUTF8) {
if (utf8BytesLeft > 0) {
if ((value & 0x80) == 0) {
canBeUTF8 = false;
} else {
utf8BytesLeft--;
}
} else if ((value & 0x80) != 0) {
if ((value & 0x40) == 0) {
canBeUTF8 = false;
} else {
utf8BytesLeft++;
if ((value & 0x20) == 0) {
utf2BytesChars++;
} else {
utf8BytesLeft++;
if ((value & 0x10) == 0) {
utf3BytesChars++;
} else {
utf8BytesLeft++;
if ((value & 0x08) == 0) {
utf4BytesChars++;
} else {
canBeUTF8 = false;
}
}
}
}
}
}
// Shift_JIS stuff
if (canBeShiftJIS) {
if (sjisBytesLeft > 0) {
if (value < 0x40 || value == 0x7F || value > 0xFC) {
canBeShiftJIS = false;
} else {
sjisBytesLeft--;
}
} else if (value == 0x80 || value == 0xA0 || value > 0xEF) {
canBeShiftJIS = false;
} else if (value > 0xA0 && value < 0xE0) {
sjisKatakanaChars++;
sjisCurDoubleBytesWordLength = 0;
sjisCurKatakanaWordLength++;
if (sjisCurKatakanaWordLength > sjisMaxKatakanaWordLength) {
sjisMaxKatakanaWordLength = sjisCurKatakanaWordLength;
}
} else if (value > 0x7F) {
sjisBytesLeft++;
// sjisDoubleBytesChars++;
sjisCurKatakanaWordLength = 0;
sjisCurDoubleBytesWordLength++;
if (sjisCurDoubleBytesWordLength > sjisMaxDoubleBytesWordLength) {
sjisMaxDoubleBytesWordLength = sjisCurDoubleBytesWordLength;
}
} else {
// sjisLowChars++;
sjisCurKatakanaWordLength = 0;
sjisCurDoubleBytesWordLength = 0;
}
}
// ISO-8859-1 stuff
if (canBeISO88591) {
if (value > 0x7F && value < 0xA0) {
canBeISO88591 = false;
} else if (value > 0x9F) {
if (value < 0xC0 || value == 0xD7 || value == 0xF7) {
isoHighOther++;
}
}
}
}
// Get how many chinese sc & tw words
gb2312SCByteChars = is_gb2312_code(bytes, length);
big5TWBytesChars = is_big5_code(bytes, length);
if (gb2312SCByteChars <= 0) {
canBeGB2312 = false;
}
if (big5TWBytesChars <= 0) {
canBeBIG5 = false;
}
if (!is_gbk_code(bytes, length)) {
canBeGBK = false;
}
if (canBeUTF8 && utf8BytesLeft > 0) {
canBeUTF8 = false;
}
if (canBeShiftJIS && sjisBytesLeft > 0) {
canBeShiftJIS = false;
}
if (is_ascii_code(bytes, length) <= 0) {
canBeASCII = false;
}
// Easy -- if there is BOM or at least 1 valid not-single byte character
// (and no evidence it can't be UTF-8), done
if (canBeUTF8 && (utf8bom || utf2BytesChars + utf3BytesChars + utf4BytesChars > 0)) {
return UTF8;
}
// if ( canBeBIG5 == false && canBeGB2312 == false )
int chineseWordLen =
gb2312SCByteChars > big5TWBytesChars ? gb2312SCByteChars : big5TWBytesChars;
int chineseByteLen = chineseWordLen * 2;
int japaneseByteLen = sjisMaxKatakanaWordLength + sjisMaxDoubleBytesWordLength * 2;
// if ( chineseByteLen < japaneseByteLen || (japaneseByteLen == 0 &&
// chineseByteLen == 0) ) if ( (gb2312SCByteChars < sjisKatakanaChars) &&
// (big5TWBytesChars < sjisKatakanaChars) )
//{
// Easy -- if assuming Shift_JIS or at least 3 valid consecutive not-ascii
// characters (and no evidence it can't be), done
if (canBeShiftJIS &&
(ASSUME_SHIFT_JIS || sjisMaxKatakanaWordLength >= 3 || sjisMaxDoubleBytesWordLength >= 3)) {
// return SHIFT_JIS;
if (chineseByteLen <= japaneseByteLen) {
if (chineseByteLen == japaneseByteLen) {
if (chineseWordLen < sjisKatakanaChars) {
return SHIFT_JIS;
}
} else {
return SHIFT_JIS;
}
}
}
// Distinguishing Shift_JIS and ISO-8859-1 can be a little tough for short
// words. The crude heuristic is:
// - If we saw
// - only two consecutive katakana chars in the whole text, or
// - at least 10% of bytes that could be "upper" not-alphanumeric Latin1,
// - then we conclude Shift_JIS, else ISO-8859-1
if (canBeISO88591 && canBeShiftJIS) {
if ((sjisMaxKatakanaWordLength == 2 && sjisKatakanaChars == 2) ||
isoHighOther * 10 >= length) {
/*
if ( chineseByteLen < japaneseByteLen )
{
return SHIFT_JIS;
}
*/
if (chineseByteLen <= japaneseByteLen) {
if (chineseByteLen == japaneseByteLen) {
if (chineseWordLen < sjisKatakanaChars) {
return SHIFT_JIS;
}
} else {
return SHIFT_JIS;
}
}
} else {
if (chineseByteLen <= 0 && !canBeGB2312 && !canBeBIG5) {
return ISO88591;
}
}
}
//}
// Otherwise, try in order ISO-8859-1, Shift JIS, UTF-8 and fall back to
// default platform encoding
if (canBeGB2312) {
return GB2312;
}
if (canBeBIG5) {
return BIG5;
}
if (canBeShiftJIS) {
return SHIFT_JIS;
}
if (canBeGBK) {
return GBK;
}
if (canBeISO88591) {
return ISO88591;
}
if (canBeUTF8) {
return UTF8;
}
if (canBeASCII) {
return ASCII;
}
// Otherwise, we take a wild guess with platform encoding
return PLATFORM_DEFAULT_ENCODING;
}
// judge the byte whether begin with binary 10
int StringUtils::is_utf8_special_byte(unsigned char c) {
unsigned char special_byte = 0X02; // binary 00000010
if (c >> 6 == special_byte) {
return 1;
} else {
return 0;
}
}
int StringUtils::is_utf8_code(char* str, int length) {
unsigned char one_byte = 0X00; // binary 00000000
unsigned char two_byte = 0X06; // binary 00000110
unsigned char three_byte = 0X0E; // binary 00001110
unsigned char four_byte = 0X1E; // binary 00011110
unsigned char five_byte = 0X3E; // binary 00111110
unsigned char six_byte = 0X7E; // binary 01111110
int utf8_yes = 0;
int utf8_no = 0;
unsigned char k = 0;
unsigned char m = 0;
unsigned char n = 0;
unsigned char p = 0;
unsigned char q = 0;
unsigned char c = 0;
for (int i = 0; i < length;) {
c = (unsigned char)str[i];
if (c >> 7 == one_byte) {
i++;
continue;
} else if (c >> 5 == two_byte) {
k = (unsigned char)str[i + 1];
if (is_utf8_special_byte(k)) {
utf8_yes++;
i += 2;
continue;
}
} else if (c >> 4 == three_byte) {
m = (unsigned char)str[i + 1];
n = (unsigned char)str[i + 2];
if (is_utf8_special_byte(m) && is_utf8_special_byte(n)) {
utf8_yes++;
i += 3;
continue;
}
} else if (c >> 3 == four_byte) {
k = (unsigned char)str[i + 1];
m = (unsigned char)str[i + 2];
n = (unsigned char)str[i + 3];
if (is_utf8_special_byte(k) && is_utf8_special_byte(m) && is_utf8_special_byte(n)) {
utf8_yes++;
i += 4;
continue;
}
} else if (c >> 2 == five_byte) {
k = (unsigned char)str[i + 1];
m = (unsigned char)str[i + 2];
n = (unsigned char)str[i + 3];
p = (unsigned char)str[i + 4];
if (is_utf8_special_byte(k) && is_utf8_special_byte(m) && is_utf8_special_byte(n) &&
is_utf8_special_byte(p)) {
utf8_yes++;
i += 5;
continue;
}
} else if (c >> 1 == six_byte) {
k = (unsigned char)str[i + 1];
m = (unsigned char)str[i + 2];
n = (unsigned char)str[i + 3];
p = (unsigned char)str[i + 4];
q = (unsigned char)str[i + 5];
if (is_utf8_special_byte(k) && is_utf8_special_byte(m) && is_utf8_special_byte(n) &&
is_utf8_special_byte(p) && is_utf8_special_byte(q)) {
utf8_yes++;
i += 6;
continue;
}
}
utf8_no++;
i++;
}
// printf("uft8_yes: %d utf8_no:%d\n", utf8_yes, utf8_no);
if ((utf8_yes + utf8_no) != 0) {
int ret = (100 * utf8_yes) / (utf8_yes + utf8_no);
if (ret > 90) {
return 1;
} else {
return 0;
}
}
return 0;
}
int StringUtils::is_gb2312_code(char* str, int length) {
unsigned char one_byte = 0X00; // binary 00000000
int gb2312_yes = 0;
int gb2312_no = 0;
unsigned char k = 0;
unsigned char c = 0;
for (int i = 0; i < length;) {
c = (unsigned char)str[i];
if (c >> 7 == one_byte) {
i++;
continue;
} else if (c >= 0XA1 && c <= 0XF7) {
k = (unsigned char)str[i + 1];
if (k >= 0XA1 && k <= 0XFE) {
gb2312_yes++;
i += 2;
continue;
}
}
gb2312_no++;
i += 2;
}
// printf("gb2312_yes: %d gb2312_no:%d\n", gb2312_yes, gb2312_no);
if ((gb2312_yes + gb2312_no) > 0) {
int ret = (100 * gb2312_yes) / (gb2312_yes + gb2312_no);
if (ret == 100) {
// if (ret > 90) {
// gb2312SCByteChars = gb2312_yes;
return gb2312_yes;
} else {
return 0;
}
}
return 0;
}
int StringUtils::is_big5_code(char* str, int length) {
unsigned char one_byte = 0X00; // binary 00000000
int big5_yes = 0;
int big5_no = 0;
unsigned char k = 0;
unsigned char c = 0;
for (int i = 0; i < length;) {
c = (unsigned char)str[i];
if (c >> 7 == one_byte) {
i++;
continue;
} else if (c >= 0XA1 && c <= 0XF9) {
k = (unsigned char)str[i + 1];
if ((k >= 0X40 && k <= 0X7E) || (k >= 0XA1 && k <= 0XFE)) {
big5_yes++;
i += 2;
continue;
}
}
big5_no++;
i += 2;
}
// printf("%d %d\n", big5_yes, big5_no);
if ((big5_yes + big5_no) > 0) {
int ret = (100 * big5_yes) / (big5_yes + big5_no);
if (ret == 100) {
// if (ret > 90) {
// big5TWBytesChars = big5_yes;
return big5_yes;
} else {
return 0;
}
}
return 0;
}
int StringUtils::is_gbk_code(char* str, int length) {
unsigned char one_byte = 0X00; // binary 00000000
int gbk_yes = 0;
int gbk_no = 0;
unsigned char k = 0;
unsigned char c = 0;
for (int i = 0; i < length;) {
c = (unsigned char)str[i];
if (c >> 7 == one_byte) {
i++;
continue;
} else if (c >= 0X81 && c <= 0XFE) {
k = (unsigned char)str[i + 1];
if (k >= 0X40 && k <= 0XFE) {
gbk_yes++;
i += 2;
continue;
}
}
gbk_no++;
i += 2;
}
// printf("gbk_yes: %d gbk_no:%d\n", gbk_yes, gbk_no);
if ((gbk_yes + gbk_no) > 0) {
int ret = (100 * gbk_yes) / (gbk_yes + gbk_no);
if (ret == 100) {
// if (ret > 90) {
return 1;
} else {
return 0;
}
}
return 0;
}
int StringUtils::is_ascii_code(char* str, int length) {
unsigned char c = 0;
bool isASCII = true;
for (int i = 0; i < length; i++) {
c = (unsigned char)str[i];
if ((c > 127)) {
isASCII = false;
}
}
return (isASCII ? 1 : -1);
}
//#define DEBUG
int StringUtils::shift_jis_to_jis(const unsigned char* may_be_shift_jis, int* jis_first_ptr,
int* jis_second_ptr) {
int status = 0;
unsigned char first = may_be_shift_jis[0];
unsigned char second = may_be_shift_jis[1];
int jis_first = 0;
int jis_second = 0;
/* Check first byte is valid shift JIS. */
if ((first >= 0x81 && first <= 0x84) || (first >= 0x87 && first <= 0x9f)) {
jis_first = 2 * (first - 0x70) - 1;
if (second >= 0x40 && second <= 0x9e) {
jis_second = second - 31;
if (jis_second > 95) {
jis_second -= 1;
}
status = 1;
} else if (second >= 0x9f && second <= 0xfc) {
jis_second = second - 126;
jis_first += 1;
status = 1;
} else {
}
} else if (first >= 0xe0 && first <= 0xef) {
jis_first = 2 * (first - 0xb0) - 1;
if (second >= 0x40 && second <= 0x9e) {
jis_second = second - 31;
if (jis_second > 95) {
jis_second -= 1;
}
status = 1;
} else if (second >= 0x9f && second <= 0xfc) {
jis_second = second - 126;
jis_first += 1;
status = 1;
}
} else {
}
*jis_first_ptr = jis_first;
*jis_second_ptr = jis_second;
return status;
}
@@ -0,0 +1,65 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Modified from ZXing. Copyright ZXing authors.
// Licensed under the Apache License, Version 2.0 (the "License").
#ifndef __ZXING_COMMON_STRINGUTILS_HPP__
#define __ZXING_COMMON_STRINGUTILS_HPP__
#include "../decodehints.hpp"
#include "../zxing.hpp"
#include <map>
#include <string>
namespace zxing {
namespace common {
class StringUtils;
}
} // namespace zxing
using namespace std;
class zxing::common::StringUtils {
private:
static char const* const PLATFORM_DEFAULT_ENCODING;
public:
static char const* const ASCII;
static char const* const SHIFT_JIS;
static char const* const GB2312;
static char const* const EUC_JP;
static char const* const UTF8;
static char const* const ISO88591;
static char const* const GBK;
static char const* const GB18030;
static char const* const BIG5;
static const bool ASSUME_SHIFT_JIS;
static std::string guessEncoding(char* bytes, int length);
static std::string guessEncodingZXing(char* bytes, int length);
#ifdef USE_UCHARDET
static std::string guessEncodingUCharDet(char* bytes, int length);
#endif
static int is_utf8_special_byte(unsigned char c);
// static int is_utf8_code(const string& str);
static int is_utf8_code(char* str, int length);
static int is_gb2312_code(char* str, int length);
static int is_big5_code(char* str, int length);
static int is_gbk_code(char* str, int length);
static int is_ascii_code(char* str, int length);
static int shift_jis_to_jis(const unsigned char* may_be_shift_jis, int* jis_first_ptr,
int* jis_second_ptr);
static std::string convertString(const char* rawData, int length, const char* fromCharset,
const char* toCharset);
};
#endif // __ZXING_COMMON_STRINGUTILS_HPP__
@@ -0,0 +1,127 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
#include "../../precomp.hpp"
#include "unicomblock.hpp"
namespace zxing {
short UnicomBlock::SEARCH_POS[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
UnicomBlock::UnicomBlock(int iMaxHeight, int iMaxWidth)
: m_iHeight(iMaxHeight), m_iWidth(iMaxWidth), m_bInit(false) {}
UnicomBlock::~UnicomBlock() {}
void UnicomBlock::Init() {
if (m_bInit) return;
m_vcIndex = std::vector<unsigned int>(m_iHeight * m_iWidth, 0);
m_vcCount = std::vector<unsigned int>(m_iHeight * m_iWidth, 0);
m_vcMinPnt = std::vector<int>(m_iHeight * m_iWidth, 0);
m_vcMaxPnt = std::vector<int>(m_iHeight * m_iWidth, 0);
m_vcQueue = std::vector<int>(m_iHeight * m_iWidth, 0);
m_bInit = true;
}
void UnicomBlock::Reset(Ref<BitMatrix> poImage) {
m_poImage = poImage;
memset(&m_vcIndex[0], 0, m_vcIndex.size() * sizeof(m_vcIndex[0]));
m_iNowIdx = 0;
}
unsigned short UnicomBlock::GetUnicomBlockIndex(int y, int x) {
if (y >= m_iHeight || x >= m_iWidth) return 0;
if (m_vcIndex[y * m_iWidth + x]) return m_vcIndex[y * m_iWidth + x];
Bfs(y, x);
return m_vcIndex[y * m_iWidth + x];
}
int UnicomBlock::GetUnicomBlockSize(int y, int x) {
if (y >= m_iHeight || x >= m_iWidth) return 0;
if (m_vcIndex[y * m_iWidth + x]) return m_vcCount[y * m_iWidth + x];
Bfs(y, x);
return m_vcCount[y * m_iWidth + x];
}
int UnicomBlock::GetMinPoint(int y, int x, int &iMinY, int &iMinX) {
if (y >= m_iHeight || x >= m_iWidth) return -1;
if (m_vcIndex[y * m_iWidth + x]) {
iMinY = m_vcMinPnt[y * m_iWidth + x] >> 16;
iMinX = m_vcMinPnt[y * m_iWidth + x] & (0xFFFF);
return 0;
}
Bfs(y, x);
iMinY = m_vcMinPnt[y * m_iWidth + x] >> 16;
iMinX = m_vcMinPnt[y * m_iWidth + x] & (0xFFFF);
return 0;
}
int UnicomBlock::GetMaxPoint(int y, int x, int &iMaxY, int &iMaxX) {
if (y >= m_iHeight || x >= m_iWidth) return -1;
if (m_vcIndex[y * m_iWidth + x]) {
iMaxY = m_vcMaxPnt[y * m_iWidth + x] >> 16;
iMaxX = m_vcMaxPnt[y * m_iWidth + x] & (0xFFFF);
return 0;
}
Bfs(y, x);
iMaxY = m_vcMaxPnt[y * m_iWidth + x] >> 16;
iMaxX = m_vcMaxPnt[y * m_iWidth + x] & (0xFFFF);
return 0;
}
void UnicomBlock::Bfs(int y, int x) {
m_iNowIdx++;
int iFront = 0;
int iTail = 0;
int iCount = 1;
int iMaxX = x, iMaxY = y;
int iMinX = x, iMinY = y;
const bool bValue = (m_poImage->get(x, y) != (unsigned char)0);
m_vcIndex[y * m_iWidth + x] = m_iNowIdx;
m_vcQueue[iTail++] = y << 16 | x;
while (iFront < iTail) {
int iNode = m_vcQueue[iFront++];
int iX = iNode & (0xFFFF);
int iY = iNode >> 16;
iMaxX = max(iX, iMaxX);
iMaxY = max(iY, iMaxY);
iMinX = min(iX, iMinX);
iMinY = min(iY, iMinY);
iCount++;
for (int i = 0; i < 4; ++i) {
const int iNextX = iX + SEARCH_POS[i][0], iNextY = iY + SEARCH_POS[i][1];
const int iPosition = iNextY * m_iWidth + iNextX;
if (iPosition >= 0 && iPosition < int(m_vcIndex.size()) && 0 == m_vcIndex[iPosition]) {
if (iNextX < 0 || iNextX >= m_poImage->getWidth() || iNextY < 0 ||
iNextY >= m_poImage->getHeight() ||
bValue != (m_poImage->get(iNextX, iNextY) != (unsigned char)0))
continue;
m_vcIndex[iPosition] = m_iNowIdx;
m_vcQueue[iTail++] = iNextY << 16 | iNextX;
}
}
}
if (iCount >= (1 << 16) - 1) iCount = 0xFFFF;
const int iMinCombine = iMinY << 16 | iMinX;
const int iMaxCombine = iMaxY << 16 | iMaxX;
for (int i = 0; i < iTail; ++i) {
const int iPosition = (m_vcQueue[i] >> 16) * m_iWidth + (m_vcQueue[i] & (0xFFFF));
m_vcCount[iPosition] = iCount;
m_vcMinPnt[iPosition] = iMinCombine;
m_vcMaxPnt[iPosition] = iMaxCombine;
}
}
} // namespace zxing
@@ -0,0 +1,47 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Tencent is pleased to support the open source community by making WeChat QRCode available.
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
#ifndef __ZXING_COMMON_UNICOMBLOCK_HPP__
#define __ZXING_COMMON_UNICOMBLOCK_HPP__
#include "bitmatrix.hpp"
#include "counted.hpp"
namespace zxing {
class UnicomBlock : public Counted {
public:
UnicomBlock(int iMaxHeight, int iMaxWidth);
~UnicomBlock();
void Init();
void Reset(Ref<BitMatrix> poImage);
unsigned short GetUnicomBlockIndex(int y, int x);
int GetUnicomBlockSize(int y, int x);
int GetMinPoint(int y, int x, int &iMinY, int &iMinX);
int GetMaxPoint(int y, int x, int &iMaxY, int &iMaxX);
private:
void Bfs(int y, int x);
int m_iHeight;
int m_iWidth;
unsigned int m_iNowIdx;
bool m_bInit;
std::vector<unsigned int> m_vcIndex;
std::vector<unsigned int> m_vcCount;
std::vector<int> m_vcMinPnt;
std::vector<int> m_vcMaxPnt;
std::vector<int> m_vcQueue;
static short SEARCH_POS[4][2];
Ref<BitMatrix> m_poImage;
};
} // namespace zxing
#endif // __ZXING_COMMON_UNICOMBLOCK_HPP__