Files
ANSLibs/QRCode/WhiteRectDetector.cpp

277 lines
6.6 KiB
C++
Raw Permalink Normal View History

/*
* Copyright 2016 Nu-book Inc.
* Copyright 2016 ZXing authors
*/
// SPDX-License-Identifier: Apache-2.0
#include "WhiteRectDetector.h"
#include "BitMatrix.h"
#include "BitMatrixCursor.h"
#include "ResultPoint.h"
namespace ZXing {
static const int INIT_SIZE = 10;
static const int CORR = 1;
bool DetectWhiteRect(const BitMatrix& image, ResultPoint& p0, ResultPoint& p1, ResultPoint& p2, ResultPoint& p3)
{
return DetectWhiteRect(image, INIT_SIZE, image.width() / 2, image.height() / 2, p0, p1, p2, p3);
}
/**
* Determines whether a segment contains a black point
*
* @param a min value of the scanned coordinate
* @param b max value of the scanned coordinate
* @param fixed value of fixed coordinate
* @param horizontal set to true if scan must be horizontal, false if vertical
* @return true if a black point has been found, else false.
*/
static bool ContainsBlackPoint(const BitMatrix& image, int a, int b, int fixed, bool horizontal) {
a = std::max(a, 0);
if (horizontal) {
if (fixed < 0 || fixed >= image.height())
return false;
b = std::min(b, image.width() - 1);
for (int x = a; x <= b; x++) {
if (image.get(x, fixed)) {
return true;
}
}
}
else {
if (fixed < 0 || fixed >= image.width())
return false;
b = std::min(b, image.height() - 1);
for (int y = a; y <= b; y++) {
if (image.get(fixed, y)) {
return true;
}
}
}
return false;
}
static bool GetBlackPointOnSegment(const BitMatrix& image, int aX, int aY, int bX, int bY, ResultPoint& result)
{
PointF a(aX, aY), b(bX, bY);
BitMatrixCursorF cur(image, a, b - a);
auto dist = std::lround(distance(a, b) / length(cur.d));
for (int i = 0; i < dist; i++) {
if (cur.isBlack()) {
result = cur.p;
return true;
}
cur.step();
}
return false;
}
/**
* recenters the points of a constant distance towards the center
*
* p0 to p3 describing the corners of the rectangular
* region. The first and last points are opposed on the diagonal, as
* are the second and third. The first point will be the topmost
* point and the last, the bottommost. The second point will be
* leftmost and the third, the rightmost
*
* @param y bottom most point
* @param z left most point
* @param x right most point
* @param t top most point
*/
static void CenterEdges(const ResultPoint& y, const ResultPoint& z, const ResultPoint& x, const ResultPoint& t, int width, ResultPoint& p0, ResultPoint& p1, ResultPoint& p2, ResultPoint& p3)
{
//
// t t
// z x
// x OR z
// y y
//
float yi = y.x();
float yj = y.y();
float zi = z.x();
float zj = z.y();
float xi = x.x();
float xj = x.y();
float ti = t.x();
float tj = t.y();
if (yi < width / 2.0f) {
p0 = ResultPoint(ti - CORR, tj + CORR);
p1 = ResultPoint(zi + CORR, zj + CORR);
p2 = ResultPoint(xi - CORR, xj - CORR);
p3 = ResultPoint(yi + CORR, yj - CORR);
}
else {
p0 = ResultPoint(ti + CORR, tj + CORR);
p1 = ResultPoint(zi + CORR, zj - CORR);
p2 = ResultPoint(xi - CORR, xj + CORR);
p3 = ResultPoint(yi - CORR, yj - CORR);
}
}
bool DetectWhiteRect(const BitMatrix& image, int initSize, int x, int y, ResultPoint& p0, ResultPoint& p1,
ResultPoint& p2, ResultPoint& p3)
{
int height = image.height();
int width = image.width();
int halfsize = initSize / 2;
int left = x - halfsize;
int right = x + halfsize;
int up = y - halfsize;
int down = y + halfsize;
if (up < 0 || left < 0 || down >= height || right >= width) {
return false;
}
bool aBlackPointFoundOnBorder = true;
bool atLeastOneBlackPointFoundOnBorder = false;
bool atLeastOneBlackPointFoundOnRight = false;
bool atLeastOneBlackPointFoundOnBottom = false;
bool atLeastOneBlackPointFoundOnLeft = false;
bool atLeastOneBlackPointFoundOnTop = false;
while (aBlackPointFoundOnBorder) {
aBlackPointFoundOnBorder = false;
// .....
// . |
// .....
bool rightBorderNotWhite = true;
while ((rightBorderNotWhite || !atLeastOneBlackPointFoundOnRight) && right < width) {
rightBorderNotWhite = ContainsBlackPoint(image, up, down, right, false);
if (rightBorderNotWhite) {
right++;
aBlackPointFoundOnBorder = true;
atLeastOneBlackPointFoundOnRight = true;
}
else if (!atLeastOneBlackPointFoundOnRight) {
right++;
}
}
// .....
// . .
// .___.
bool bottomBorderNotWhite = true;
while ((bottomBorderNotWhite || !atLeastOneBlackPointFoundOnBottom) && down < height) {
bottomBorderNotWhite = ContainsBlackPoint(image, left, right, down, true);
if (bottomBorderNotWhite) {
down++;
aBlackPointFoundOnBorder = true;
atLeastOneBlackPointFoundOnBottom = true;
}
else if (!atLeastOneBlackPointFoundOnBottom) {
down++;
}
}
// .....
// | .
// .....
bool leftBorderNotWhite = true;
while ((leftBorderNotWhite || !atLeastOneBlackPointFoundOnLeft) && left >= 0) {
leftBorderNotWhite = ContainsBlackPoint(image, up, down, left, false);
if (leftBorderNotWhite) {
left--;
aBlackPointFoundOnBorder = true;
atLeastOneBlackPointFoundOnLeft = true;
}
else if (!atLeastOneBlackPointFoundOnLeft) {
left--;
}
}
// .___.
// . .
// .....
bool topBorderNotWhite = true;
while ((topBorderNotWhite || !atLeastOneBlackPointFoundOnTop) && up >= 0) {
topBorderNotWhite = ContainsBlackPoint(image, left, right, up, true);
if (topBorderNotWhite) {
up--;
aBlackPointFoundOnBorder = true;
atLeastOneBlackPointFoundOnTop = true;
}
else if (!atLeastOneBlackPointFoundOnTop) {
up--;
}
}
if (aBlackPointFoundOnBorder) {
atLeastOneBlackPointFoundOnBorder = true;
}
}
if (up < 0 || left < 0 || down >= height || right >= width)
return false;
if (atLeastOneBlackPointFoundOnBorder) {
int maxSize = right - left;
ResultPoint z;
bool found = false;
for (int i = 1; !found && i < maxSize; i++) {
found = GetBlackPointOnSegment(image, left, down - i, left + i, down, z);
}
if (!found) {
return false;
}
ResultPoint t;
found = false;
//go down right
for (int i = 1; !found && i < maxSize; i++) {
found = GetBlackPointOnSegment(image, left, up + i, left + i, up, t);
}
if (!found) {
return false;
}
ResultPoint x;
found = false;
//go down left
for (int i = 1; !found && i < maxSize; i++) {
found = GetBlackPointOnSegment(image, right, up + i, right - i, up, x);
}
if (!found) {
return false;
}
ResultPoint y;
found = false;
//go up left
for (int i = 1; !found && i < maxSize; i++) {
found = GetBlackPointOnSegment(image, right, down - i, right - i, down, y);
}
if (!found) {
return false;
}
CenterEdges(y, z, x, t, width, p0, p1, p2, p3);
return true;
}
else {
return false;
}
}
} // ZXing