#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);
}
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;
}
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)
{
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;
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;
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;
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;
}
}
}