tesseract v5.3.3.20231005
bbgrid.cpp
Go to the documentation of this file.
1
2// File: bbgrid.cpp
3// Description: Class to hold BLOBNBOXs in a grid for fast access
4// to neighbours.
5// Author: Ray Smith
6//
7// (C) Copyright 2007, Google Inc.
8// Licensed under the Apache License, Version 2.0 (the "License");
9// you may not use this file except in compliance with the License.
10// You may obtain a copy of the License at
11// http://www.apache.org/licenses/LICENSE-2.0
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17//
19
20#include "bbgrid.h"
21#include "helpers.h"
22#include "ocrblock.h"
23
24namespace tesseract {
25
27// BBGrid IMPLEMENTATION.
29GridBase::GridBase(int gridsize, const ICOORD &bleft, const ICOORD &tright) {
31}
32
33// Destructor.
34// It is defined here, so the compiler can create a single vtable
35// instead of weak vtables in every compilation unit.
36GridBase::~GridBase() = default;
37
38// (Re)Initialize the grid. The gridsize is the size in pixels of each cell,
39// and bleft, tright are the bounding box of everything to go in it.
40void GridBase::Init(int gridsize, const ICOORD &bleft, const ICOORD &tright) {
42 bleft_ = bleft;
44 if (gridsize_ == 0) {
45 gridsize_ = 1;
46 }
47 gridwidth_ = (tright.x() - bleft.x() + gridsize_ - 1) / gridsize_;
48 gridheight_ = (tright.y() - bleft.y() + gridsize_ - 1) / gridsize_;
50}
51
52// Compute the given grid coordinates from image coords.
53void GridBase::GridCoords(int x, int y, int *grid_x, int *grid_y) const {
54 *grid_x = (x - bleft_.x()) / gridsize_;
55 *grid_y = (y - bleft_.y()) / gridsize_;
56 ClipGridCoords(grid_x, grid_y);
57}
58
59// Clip the given grid coordinates to fit within the grid.
60void GridBase::ClipGridCoords(int *x, int *y) const {
61 *x = ClipToRange(*x, 0, gridwidth_ - 1);
62 *y = ClipToRange(*y, 0, gridheight_ - 1);
63}
64
66 grid_ = nullptr;
67}
68
69IntGrid::IntGrid(int gridsize, const ICOORD &bleft, const ICOORD &tright) : grid_(nullptr) {
71}
72
74 delete[] grid_;
75}
76
77// (Re)Initialize the grid. The gridsize is the size in pixels of each cell,
78// and bleft, tright are the bounding box of everything to go in it.
79void IntGrid::Init(int gridsize, const ICOORD &bleft, const ICOORD &tright) {
81 delete[] grid_;
82 grid_ = new int[gridbuckets_];
83 Clear();
84}
85
86// Clear all the ints in the grid to zero.
88 for (int i = 0; i < gridbuckets_; ++i) {
89 grid_[i] = 0;
90 }
91}
92
93// Rotate the grid by rotation, keeping cell contents.
94// rotation must be a multiple of 90 degrees.
95// NOTE: due to partial cells, cell coverage in the rotated grid will be
96// inexact. This is why there is no Rotate for the generic BBGrid.
97// TODO(rays) investigate fixing this inaccuracy by moving the origin after
98// rotation.
99void IntGrid::Rotate(const FCOORD &rotation) {
100 ASSERT_HOST(rotation.x() == 0.0f || rotation.y() == 0.0f);
101 ICOORD old_bleft(bleft());
102 // ICOORD old_tright(tright());
103 int old_width = gridwidth();
104 int old_height = gridheight();
105 TBOX box(bleft(), tright());
106 box.rotate(rotation);
107 int *old_grid = grid_;
108 grid_ = nullptr;
109 Init(gridsize(), box.botleft(), box.topright());
110 // Iterate over the old grid, copying data to the rotated position in the new.
111 int oldi = 0;
112 FCOORD x_step(rotation);
113 x_step *= gridsize();
114 for (int oldy = 0; oldy < old_height; ++oldy) {
115 FCOORD line_pos(old_bleft.x(), old_bleft.y() + gridsize() * oldy);
116 line_pos.rotate(rotation);
117 for (int oldx = 0; oldx < old_width; ++oldx, line_pos += x_step, ++oldi) {
118 int grid_x, grid_y;
119 GridCoords(static_cast<int>(line_pos.x() + 0.5), static_cast<int>(line_pos.y() + 0.5),
120 &grid_x, &grid_y);
121 grid_[grid_y * gridwidth() + grid_x] = old_grid[oldi];
122 }
123 }
124 delete[] old_grid;
125}
126
127// Returns a new IntGrid containing values equal to the sum of all the
128// neighbouring cells. The returned grid must be deleted after use.
129// For ease of implementation, edge cells are double counted, to make them
130// have the same range as the non-edge cells.
132 auto *sumgrid = new IntGrid(gridsize(), bleft(), tright());
133 for (int y = 0; y < gridheight(); ++y) {
134 for (int x = 0; x < gridwidth(); ++x) {
135 int cell_count = 0;
136 for (int yoffset = -1; yoffset <= 1; ++yoffset) {
137 for (int xoffset = -1; xoffset <= 1; ++xoffset) {
138 int grid_x = x + xoffset;
139 int grid_y = y + yoffset;
140 ClipGridCoords(&grid_x, &grid_y);
141 cell_count += GridCellValue(grid_x, grid_y);
142 }
143 }
144 if (GridCellValue(x, y) > 1) {
145 sumgrid->SetGridCell(x, y, cell_count);
146 }
147 }
148 }
149 return sumgrid;
150}
151
152// Returns true if more than half the area of the rect is covered by grid
153// cells that are over the threshold.
154bool IntGrid::RectMostlyOverThreshold(const TBOX &rect, int threshold) const {
155 int min_x, min_y, max_x, max_y;
156 GridCoords(rect.left(), rect.bottom(), &min_x, &min_y);
157 GridCoords(rect.right(), rect.top(), &max_x, &max_y);
158 int total_area = 0;
159 for (int y = min_y; y <= max_y; ++y) {
160 for (int x = min_x; x <= max_x; ++x) {
161 int value = GridCellValue(x, y);
162 if (value > threshold) {
163 TBOX cell_box(x * gridsize_, y * gridsize_, (x + 1) * gridsize_, (y + 1) * gridsize_);
164 cell_box &= rect; // This is in-place box intersection.
165 total_area += cell_box.area();
166 }
167 }
168 }
169 return total_area * 2 > rect.area();
170}
171
172// Returns true if any cell value in the given rectangle is zero.
173bool IntGrid::AnyZeroInRect(const TBOX &rect) const {
174 int min_x, min_y, max_x, max_y;
175 GridCoords(rect.left(), rect.bottom(), &min_x, &min_y);
176 GridCoords(rect.right(), rect.top(), &max_x, &max_y);
177 for (int y = min_y; y <= max_y; ++y) {
178 for (int x = min_x; x <= max_x; ++x) {
179 if (GridCellValue(x, y) == 0) {
180 return true;
181 }
182 }
183 }
184 return false;
185}
186
187// Returns a full-resolution binary pix in which each cell over the given
188// threshold is filled as a black square. pixDestroy after use.
189// Edge cells, which have a zero 4-neighbour, are not marked.
190Image IntGrid::ThresholdToPix(int threshold) const {
191 Image pix = pixCreate(tright().x() - bleft().x(), tright().y() - bleft().y(), 1);
192 int cellsize = gridsize();
193 for (int y = 0; y < gridheight(); ++y) {
194 for (int x = 0; x < gridwidth(); ++x) {
195 if (GridCellValue(x, y) > threshold && GridCellValue(x - 1, y) > 0 &&
196 GridCellValue(x + 1, y) > 0 && GridCellValue(x, y - 1) > 0 &&
197 GridCellValue(x, y + 1) > 0) {
198 pixRasterop(pix, x * cellsize, tright().y() - ((y + 1) * cellsize), cellsize, cellsize,
199 PIX_SET, nullptr, 0, 0);
200 }
201 }
202 }
203 return pix;
204}
205
206// Make a Pix of the correct scaled size for the TraceOutline functions.
207static Image GridReducedPix(const TBOX &box, int gridsize, ICOORD bleft, int *left, int *bottom) {
208 // Compute grid bounds of the outline and pad all round by 1.
209 int grid_left = (box.left() - bleft.x()) / gridsize - 1;
210 int grid_bottom = (box.bottom() - bleft.y()) / gridsize - 1;
211 int grid_right = (box.right() - bleft.x()) / gridsize + 1;
212 int grid_top = (box.top() - bleft.y()) / gridsize + 1;
213 *left = grid_left;
214 *bottom = grid_bottom;
215 return pixCreate(grid_right - grid_left + 1, grid_top - grid_bottom + 1, 1);
216}
217
218// Helper function to return a scaled Pix with one pixel per grid cell,
219// set (black) where the given outline enters the corresponding grid cell,
220// and clear where the outline does not touch the grid cell.
221// Also returns the grid coords of the bottom-left of the Pix, in *left
222// and *bottom, which corresponds to (0, 0) on the Pix.
223// Note that the Pix is used upside-down, with (0, 0) being the bottom-left.
224Image TraceOutlineOnReducedPix(C_OUTLINE *outline, int gridsize, ICOORD bleft, int *left,
225 int *bottom) {
226 const TBOX &box = outline->bounding_box();
227 Image pix = GridReducedPix(box, gridsize, bleft, left, bottom);
228 int wpl = pixGetWpl(pix);
229 l_uint32 *data = pixGetData(pix);
230 int length = outline->pathlength();
231 ICOORD pos = outline->start_pos();
232 for (int i = 0; i < length; ++i) {
233 int grid_x = (pos.x() - bleft.x()) / gridsize - *left;
234 int grid_y = (pos.y() - bleft.y()) / gridsize - *bottom;
235 SET_DATA_BIT(data + grid_y * wpl, grid_x);
236 pos += outline->step(i);
237 }
238 return pix;
239}
240#if 0 // Example code shows how to use TraceOutlineOnReducedPix.
241 C_OUTLINE_IT ol_it(blob->cblob()->out_list());
242 int grid_left, grid_bottom;
243 Pix* pix = TraceOutlineOnReducedPix(ol_it.data(), gridsize_, bleft_,
244 &grid_left, &grid_bottom);
245 grid->InsertPixPtBBox(grid_left, grid_bottom, pix, blob);
246 pix.destroy();
247#endif
248
249// As TraceOutlineOnReducedPix above, but on a BLOCK instead of a C_OUTLINE.
250Image TraceBlockOnReducedPix(BLOCK *block, int gridsize, ICOORD bleft, int *left, int *bottom) {
251 const TBOX &box = block->pdblk.bounding_box();
252 Image pix = GridReducedPix(box, gridsize, bleft, left, bottom);
253 int wpl = pixGetWpl(pix);
254 l_uint32 *data = pixGetData(pix);
255 ICOORDELT_IT it(block->pdblk.poly_block()->points());
256 for (it.mark_cycle_pt(); !it.cycled_list();) {
257 ICOORD pos = *it.data();
258 it.forward();
259 ICOORD next_pos = *it.data();
260 ICOORD line_vector = next_pos - pos;
261 int major, minor;
262 ICOORD major_step, minor_step;
263 line_vector.setup_render(&major_step, &minor_step, &major, &minor);
264 int accumulator = major / 2;
265 while (pos != next_pos) {
266 int grid_x = (pos.x() - bleft.x()) / gridsize - *left;
267 int grid_y = (pos.y() - bleft.y()) / gridsize - *bottom;
268 SET_DATA_BIT(data + grid_y * wpl, grid_x);
269 pos += major_step;
270 accumulator += minor;
271 if (accumulator >= major) {
272 accumulator -= major;
273 pos += minor_step;
274 }
275 }
276 }
277 return pix;
278}
279
280} // namespace tesseract.
#define ASSERT_HOST(x)
Definition: errcode.h:54
int value
const double y
Image TraceOutlineOnReducedPix(C_OUTLINE *outline, int gridsize, ICOORD bleft, int *left, int *bottom)
Definition: bbgrid.cpp:224
Image TraceBlockOnReducedPix(BLOCK *block, int gridsize, ICOORD bleft, int *left, int *bottom)
Definition: bbgrid.cpp:250
T ClipToRange(const T &x, const T &lower_bound, const T &upper_bound)
Definition: helpers.h:105
int32_t pathlength() const
Definition: coutln.h:134
const TBOX & bounding_box() const
Definition: coutln.h:113
ICOORD step(int index) const
Definition: coutln.h:143
const ICOORD & start_pos() const
Definition: coutln.h:147
PDBLK pdblk
Page Description Block.
Definition: ocrblock.h:185
POLY_BLOCK * poly_block() const
Definition: pdblock.h:59
void bounding_box(ICOORD &bottom_left, ICOORD &top_right) const
get box
Definition: pdblock.h:67
integer coordinate
Definition: points.h:36
TDimension y() const
access_function
Definition: points.h:62
TDimension x() const
access function
Definition: points.h:58
void setup_render(ICOORD *major_step, ICOORD *minor_step, int *major, int *minor) const
Definition: points.cpp:99
void rotate(const FCOORD vec)
Definition: points.h:712
float y() const
Definition: points.h:209
float x() const
Definition: points.h:206
ICOORDELT_LIST * points()
Definition: polyblk.h:42
TDimension left() const
Definition: rect.h:82
void rotate(const FCOORD &vec)
Definition: rect.h:210
TDimension top() const
Definition: rect.h:68
const ICOORD & botleft() const
Definition: rect.h:102
const ICOORD & topright() const
Definition: rect.h:114
TDimension right() const
Definition: rect.h:89
TDimension bottom() const
Definition: rect.h:75
int32_t area() const
Definition: rect.h:134
int gridsize() const
Definition: bbgrid.h:63
int gridheight() const
Definition: bbgrid.h:69
void ClipGridCoords(int *x, int *y) const
Definition: bbgrid.cpp:60
void Init(int gridsize, const ICOORD &bleft, const ICOORD &tright)
Definition: bbgrid.cpp:40
const ICOORD & bleft() const
Definition: bbgrid.h:72
int gridwidth() const
Definition: bbgrid.h:66
ICOORD tright_
Definition: bbgrid.h:91
void GridCoords(int x, int y, int *grid_x, int *grid_y) const
Definition: bbgrid.cpp:53
const ICOORD & tright() const
Definition: bbgrid.h:75
IntGrid * NeighbourhoodSum() const
Definition: bbgrid.cpp:131
int GridCellValue(int grid_x, int grid_y) const
Definition: bbgrid.h:120
void Init(int gridsize, const ICOORD &bleft, const ICOORD &tright)
Definition: bbgrid.cpp:79
bool RectMostlyOverThreshold(const TBOX &rect, int threshold) const
Definition: bbgrid.cpp:154
Image ThresholdToPix(int threshold) const
Definition: bbgrid.cpp:190
~IntGrid() override
Definition: bbgrid.cpp:73
void Rotate(const FCOORD &rotation)
Definition: bbgrid.cpp:99
bool AnyZeroInRect(const TBOX &rect) const
Definition: bbgrid.cpp:173