Skip to content

Commit 149d101

Browse files
committed
BitMatrix: add BitMatrixCursor as general purpose abstraction
This is the general part of the former DMDetector EdgeTracer code. Also add a widely usable PointT based accessor interface to BitMatrix.
1 parent 4fe3077 commit 149d101

File tree

4 files changed

+98
-67
lines changed

4 files changed

+98
-67
lines changed

core/src/BitMatrix.h

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,15 @@
1616
* limitations under the License.
1717
*/
1818

19+
#include "Matrix.h"
20+
#include "Point.h"
21+
#include "ZXConfig.h"
22+
1923
#include <algorithm>
2024
#include <cstdint>
2125
#include <utility>
2226
#include <vector>
2327

24-
#include "Matrix.h"
25-
#include "ZXConfig.h"
26-
2728
namespace ZXing {
2829

2930
class BitArray;
@@ -269,6 +270,80 @@ class BitMatrix
269270
{
270271
return a._width == b._width && a._height == b._height && a._rowSize == b._rowSize && a._bits == b._bits;
271272
}
273+
274+
bool isIn(PointI p, int b = 0) const noexcept
275+
{
276+
return b <= p.x && p.x < width() - b && b <= p.y && p.y < height() - b;
277+
}
278+
bool isIn(PointF p) const noexcept { return isIn(round(p)); }
279+
280+
bool get(PointI p) const { return get(p.x, p.y); }
281+
bool get(PointF p) const { return get(round(p)); }
282+
void set(PointI p, bool v = true) { set(p.x, p.y, v); }
283+
void set(PointF p, bool v = true) { set(round(p), v); }
284+
285+
class Value
286+
{
287+
enum { INVALID, WHITE, BLACK };
288+
int v = INVALID;
289+
public:
290+
Value() = default;
291+
Value(bool isBlack) : v(isBlack ? BLACK : WHITE) {}
292+
bool isValid() const { return v != INVALID; }
293+
bool isWhite() const { return v == WHITE; }
294+
bool isBlack() const { return v == BLACK; }
295+
};
296+
297+
template <typename T>
298+
Value testAt(PointT<T> p) const
299+
{
300+
auto q = round(p);
301+
return isIn(q) ? Value{get(q)} : Value{};
302+
}
303+
304+
template <typename T> bool blackAt(PointT<T> p) const { return testAt(p).isBlack(); }
305+
template <typename T> bool whiteAt(PointT<T> p) const { return testAt(p).isWhite(); }
306+
};
307+
308+
/**
309+
* @brief The BitMatrixCursor represents a current position inside an image and durrent direction it can advance towards.
310+
*
311+
* The current position is PointI or PointF. So depending on the type it will either round its current position after each
312+
* step or do a Bresenham traversal through the BitMatrix.
313+
*/
314+
template<typename CPOS_T>
315+
class BitMatrixCursor
316+
{
317+
const BitMatrix* _img;
318+
319+
public:
320+
CPOS_T p; // current position
321+
PointF d; // current direction
322+
323+
BitMatrixCursor(const BitMatrix& image, CPOS_T p, PointF d) : _img(&image), p(p), d(d) {}
324+
325+
bool isIn(PointI p) const noexcept { return _img->isIn(p); }
326+
bool isIn(PointF p) const noexcept { return _img->isIn(p); }
327+
bool isIn() const noexcept { return isIn(p); }
328+
bool isBlack() const noexcept { return blackAt(p); }
329+
bool isWhite() const noexcept { return whiteAt(p); }
330+
331+
PointF front() const noexcept { return d; }
332+
PointF back() const noexcept { return {-d.x, -d.y}; }
333+
PointF right() const noexcept { return {-d.y, d.x}; }
334+
PointF left() const noexcept { return {d.y, -d.x}; }
335+
336+
bool blackAt(PointF pos) const noexcept { return _img->testAt(pos).isBlack(); }
337+
bool whiteAt(PointF pos) const noexcept { return _img->testAt(pos).isWhite(); }
338+
bool isEdge(PointF pos, PointF dir) const noexcept { return whiteAt(pos) && blackAt(pos + dir); }
339+
bool isEdgeBehind() const noexcept { return isEdge(PointF(p), back()); }
340+
341+
void setDirection(PointF dir) { d = bresenhamDirection(dir); }
342+
bool step(int s = 1)
343+
{
344+
moveBy(p, s * d);
345+
return isIn(p);
346+
}
272347
};
273348

274349
/**

core/src/GridSampler.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ DetectorResult SampleGrid(const BitMatrix& image, int width, int height, const P
4747
#ifndef NDEBUG
4848
theGrid.emplace_back(p);
4949
#endif
50-
if (image.get(p.x, p.y))
50+
if (image.get(p))
5151
res.set(x, y);
5252
}
5353
auto projectCorner = [&](PointI p) { return PointI(transform(PointF(p)) + PointF(0.5, 0.5)); };

core/src/Point.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,11 @@ inline PointI round(PointF p)
109109
return PointI(::lround(p.x), ::lround(p.y));
110110
}
111111

112+
inline PointI round(PointI p)
113+
{
114+
return p;
115+
}
116+
112117
inline PointF bresenhamDirection(PointF d)
113118
{
114119
return d / std::fmax(std::fabs(d.x), std::fabs(d.y));
@@ -125,6 +130,15 @@ inline PointF movedTowardsBy(PointF a, PointF b, double d)
125130
return a + d * normalized(b - a);
126131
}
127132

133+
inline void moveBy(PointI& p, PointF d)
134+
{
135+
p = p + round(d);
136+
}
137+
138+
inline void moveBy(PointF& p, PointF d)
139+
{
140+
p = p + d;
141+
}
128142

129143
} // ZXing
130144

core/src/datamatrix/DMDetector.cpp

Lines changed: 5 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -562,55 +562,10 @@ PointF intersect(const RegressionLine& l1, const RegressionLine& l2)
562562
return {x, y};
563563
}
564564

565-
struct BitMatrixAccessor
565+
class EdgeTracer : public BitMatrixCursor<PointI>
566566
{
567-
const BitMatrix* image;
568-
569-
BitMatrixAccessor(const BitMatrix& image) : image(&image) {}
570-
571-
bool isIn(PointI p) const
572-
{
573-
const int b = 0;
574-
return b <= p.x && p.x < image->width()-b &&
575-
b <= p.y && p.y < image->height()-b;
576-
}
577-
bool isIn(PointF p) const { return isIn(round(p)); }
578-
579-
class Value
580-
{
581-
enum { INVALID, WHITE, BLACK };
582-
int v = INVALID;
583-
public:
584-
Value() = default;
585-
Value(bool isBlack) : v(isBlack ? BLACK : WHITE) {}
586-
bool isValid() const { return v != INVALID; }
587-
bool isWhite() const { return v == WHITE; }
588-
bool isBlack() const { return v == BLACK; }
589-
};
590-
591-
Value getAt(PointF p) const
592-
{
593-
auto q = round(p);
594-
if (!isIn(q))
595-
return {};
596-
return {image->get(q.x, q.y)};
597-
}
598-
599-
bool blackAt(PointF p) const { return getAt(p).isBlack(); }
600-
bool whiteAt(PointF p) const { return getAt(p).isWhite(); }
601-
bool isEdge(PointF pos, PointF dir) const { return whiteAt(pos) && blackAt(pos + dir); }
602-
};
603-
604-
class EdgeTracer : BitMatrixAccessor
605-
{
606-
PointI p; // current position
607-
PointF d; // current direction
608-
609567
enum class StepResult { FOUND, OPEN_END, CLOSED_END };
610568

611-
using BitMatrixAccessor::isIn;
612-
bool isIn() const { return isIn(p); }
613-
614569
StepResult traceStep(PointF dEdge, int maxStepSize, bool goodDirection)
615570
{
616571
dEdge = mainDirection(dEdge);
@@ -643,16 +598,7 @@ class EdgeTracer : BitMatrixAccessor
643598
}
644599

645600
public:
646-
EdgeTracer(const BitMatrix& img, PointI p, PointF d) : BitMatrixAccessor(img), p(p), d(d) {}
647-
648-
bool step(int s = 1)
649-
{
650-
p = round(p + s * d);
651-
log(p);
652-
return isIn(p);
653-
}
654-
655-
void setDirection(PointF dir) { d = bresenhamDirection(dir); }
601+
using BitMatrixCursor<PointI>::BitMatrixCursor;
656602

657603
bool updateDirectionFromOrigin(PointF origin)
658604
{
@@ -669,13 +615,6 @@ class EdgeTracer : BitMatrixAccessor
669615
return true;
670616
}
671617

672-
PointF front() const { return d; }
673-
PointF back() const { return {-d.x, -d.y}; }
674-
PointF right() const { return {-d.y, d.x}; }
675-
PointF left() const { return {d.y, -d.x}; }
676-
677-
bool isEdgeBehind() const { return isEdge(PointF(p), back()); }
678-
679618
bool traceLine(PointF dEdge, RegressionLine& line)
680619
{
681620
line.setDirectionInward(dEdge);
@@ -764,6 +703,7 @@ class EdgeTracer : BitMatrixAccessor
764703
bool traceCorner(PointF dir, PointF& corner)
765704
{
766705
step();
706+
log(p);
767707
corner = PointF(p);
768708
std::swap(d, dir);
769709
traceStep(-1 * dir, 2, false);
@@ -807,6 +747,8 @@ static DetectorResult DetectNew(const BitMatrix& image, bool tryRotate)
807747
#endif
808748
EdgeTracer startTracer(image, {image.width()/2, image.height()/2}, startDirection);
809749
while (startTracer.step()) {
750+
log(startTracer.p);
751+
810752
// go forward until we reach a white/black border
811753
if (!startTracer.isEdgeBehind())
812754
continue;

0 commit comments

Comments
 (0)