/src/tesseract/src/textord/bbgrid.h
Line | Count | Source |
1 | | /////////////////////////////////////////////////////////////////////// |
2 | | // File: bbgrid.h |
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 | | // |
18 | | /////////////////////////////////////////////////////////////////////// |
19 | | |
20 | | #ifndef TESSERACT_TEXTORD_BBGRID_H_ |
21 | | #define TESSERACT_TEXTORD_BBGRID_H_ |
22 | | |
23 | | #include <unordered_set> |
24 | | |
25 | | #include "clst.h" |
26 | | #include "coutln.h" |
27 | | #include "image.h" // for Image |
28 | | #include "rect.h" |
29 | | #include "scrollview.h" |
30 | | |
31 | | class BLOCK; |
32 | | |
33 | | namespace tesseract { |
34 | | |
35 | | // Helper function to return a scaled Pix with one pixel per grid cell, |
36 | | // set (black) where the given outline enters the corresponding grid cell, |
37 | | // and clear where the outline does not touch the grid cell. |
38 | | // Also returns the grid coords of the bottom-left of the Pix, in *left |
39 | | // and *bottom, which corresponds to (0, 0) on the Pix. |
40 | | // Note that the Pix is used upside-down, with (0, 0) being the bottom-left. |
41 | | Image TraceOutlineOnReducedPix(C_OUTLINE *outline, int gridsize, ICOORD bleft, int *left, |
42 | | int *bottom); |
43 | | // As TraceOutlineOnReducedPix above, but on a BLOCK instead of a C_OUTLINE. |
44 | | Image TraceBlockOnReducedPix(BLOCK *block, int gridsize, ICOORD bleft, int *left, int *bottom); |
45 | | |
46 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
47 | | class GridSearch; |
48 | | |
49 | | // The GridBase class is the base class for BBGrid and IntGrid. |
50 | | // It holds the geometry and scale of the grid. |
51 | | class TESS_API GridBase { |
52 | | public: |
53 | 13.8k | GridBase() = default; |
54 | | GridBase(int gridsize, const ICOORD &bleft, const ICOORD &tright); |
55 | | virtual ~GridBase(); |
56 | | |
57 | | // (Re)Initialize the grid. The gridsize is the size in pixels of each cell, |
58 | | // and bleft, tright are the bounding box of everything to go in it. |
59 | | void Init(int gridsize, const ICOORD &bleft, const ICOORD &tright); |
60 | | |
61 | | // Simple accessors. |
62 | 0 | int gridsize() const { |
63 | 0 | return gridsize_; |
64 | 0 | } |
65 | 0 | int gridwidth() const { |
66 | 0 | return gridwidth_; |
67 | 0 | } |
68 | 0 | int gridheight() const { |
69 | 0 | return gridheight_; |
70 | 0 | } |
71 | 0 | const ICOORD &bleft() const { |
72 | 0 | return bleft_; |
73 | 0 | } |
74 | 0 | const ICOORD &tright() const { |
75 | 0 | return tright_; |
76 | 0 | } |
77 | | // Compute the given grid coordinates from image coords. |
78 | | void GridCoords(int x, int y, int *grid_x, int *grid_y) const; |
79 | | |
80 | | // Clip the given grid coordinates to fit within the grid. |
81 | | void ClipGridCoords(int *x, int *y) const; |
82 | | |
83 | | protected: |
84 | | // TODO(rays) Make these private and migrate to the accessors in subclasses. |
85 | | int gridsize_; // Pixel size of each grid cell. |
86 | | int gridwidth_; // Size of the grid in cells. |
87 | | int gridheight_; |
88 | | int gridbuckets_; // Total cells in grid. |
89 | | ICOORD bleft_; // Pixel coords of bottom-left of grid. |
90 | | ICOORD tright_; // Pixel coords of top-right of grid. |
91 | | |
92 | | private: |
93 | | }; |
94 | | |
95 | | // The IntGrid maintains a single int for each cell in a grid. |
96 | | class IntGrid : public GridBase { |
97 | | public: |
98 | | IntGrid(); |
99 | | IntGrid(int gridsize, const ICOORD &bleft, const ICOORD &tright); |
100 | | ~IntGrid() override; |
101 | | |
102 | | // (Re)Initialize the grid. The gridsize is the size in pixels of each cell, |
103 | | // and bleft, tright are the bounding box of everything to go in it. |
104 | | void Init(int gridsize, const ICOORD &bleft, const ICOORD &tright); |
105 | | |
106 | | // Clear all the ints in the grid to zero. |
107 | | void Clear(); |
108 | | |
109 | | // Rotate the grid by rotation, keeping cell contents. |
110 | | // rotation must be a multiple of 90 degrees. |
111 | | // NOTE: due to partial cells, cell coverage in the rotated grid will be |
112 | | // inexact. This is why there is no Rotate for the generic BBGrid. |
113 | | void Rotate(const FCOORD &rotation); |
114 | | |
115 | | // Returns a new IntGrid containing values equal to the sum of all the |
116 | | // neighbouring cells. The returned grid must be deleted after use. |
117 | | IntGrid *NeighbourhoodSum() const; |
118 | | |
119 | 0 | int GridCellValue(int grid_x, int grid_y) const { |
120 | 0 | ClipGridCoords(&grid_x, &grid_y); |
121 | 0 | return grid_[grid_y * gridwidth_ + grid_x]; |
122 | 0 | } |
123 | 0 | void SetGridCell(int grid_x, int grid_y, int value) { |
124 | 0 | ASSERT_HOST(grid_x >= 0 && grid_x < gridwidth()); |
125 | 0 | ASSERT_HOST(grid_y >= 0 && grid_y < gridheight()); |
126 | 0 | grid_[grid_y * gridwidth_ + grid_x] = value; |
127 | 0 | } |
128 | | // Returns true if more than half the area of the rect is covered by grid |
129 | | // cells that are over the threshold. |
130 | | bool RectMostlyOverThreshold(const TBOX &rect, int threshold) const; |
131 | | |
132 | | // Returns true if any cell value in the given rectangle is zero. |
133 | | bool AnyZeroInRect(const TBOX &rect) const; |
134 | | |
135 | | // Returns a full-resolution binary pix in which each cell over the given |
136 | | // threshold is filled as a black square. pixDestroy after use. |
137 | | Image ThresholdToPix(int threshold) const; |
138 | | |
139 | | private: |
140 | | int *grid_; // 2-d array of ints. |
141 | | }; |
142 | | |
143 | | // The BBGrid class holds C_LISTs of template classes BBC (bounding box class) |
144 | | // in a grid for fast neighbour access. |
145 | | // The BBC class must have a member const TBOX& bounding_box() const. |
146 | | // The BBC class must have been CLISTIZEH'ed elsewhere to make the |
147 | | // list class BBC_CLIST and the iterator BBC_C_IT. |
148 | | // Use of C_LISTs enables BBCs to exist in multiple cells simultaneously. |
149 | | // As a consequence, ownership of BBCs is assumed to be elsewhere and |
150 | | // persistent for at least the life of the BBGrid, or at least until Clear is |
151 | | // called which removes all references to inserted objects without actually |
152 | | // deleting them. |
153 | | // Most uses derive a class from a specific instantiation of BBGrid, |
154 | | // thereby making most of the ugly template notation go away. |
155 | | // The friend class GridSearch, with the same template arguments, is |
156 | | // used to search a grid efficiently in one of several search patterns. |
157 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
158 | | class BBGrid : public GridBase { |
159 | | friend class GridSearch<BBC, BBC_CLIST, BBC_C_IT>; |
160 | | |
161 | | public: |
162 | | BBGrid(); |
163 | | BBGrid(int gridsize, const ICOORD &bleft, const ICOORD &tright); |
164 | | ~BBGrid() override; |
165 | | |
166 | | // (Re)Initialize the grid. The gridsize is the size in pixels of each cell, |
167 | | // and bleft, tright are the bounding box of everything to go in it. |
168 | | void Init(int gridsize, const ICOORD &bleft, const ICOORD &tright); |
169 | | |
170 | | // Empty all the lists but leave the grid itself intact. |
171 | | void Clear(); |
172 | | // Deallocate the data in the lists but otherwise leave the lists and the grid |
173 | | // intact. |
174 | | void ClearGridData(void (*free_method)(BBC *)); |
175 | | |
176 | | // Insert a bbox into the appropriate place in the grid. |
177 | | // If h_spread, then all cells covered horizontally by the box are |
178 | | // used, otherwise, just the bottom-left. Similarly for v_spread. |
179 | | // WARNING: InsertBBox may invalidate an active GridSearch. Call |
180 | | // RepositionIterator() on any GridSearches that are active on this grid. |
181 | | void InsertBBox(bool h_spread, bool v_spread, BBC *bbox); |
182 | | |
183 | | // Using a pix from TraceOutlineOnReducedPix or TraceBlockOnReducedPix, in |
184 | | // which each pixel corresponds to a grid cell, insert a bbox into every |
185 | | // place in the grid where the corresponding pixel is 1. The Pix is handled |
186 | | // upside-down to match the Tesseract coordinate system. (As created by |
187 | | // TraceOutlineOnReducedPix or TraceBlockOnReducedPix.) |
188 | | // (0, 0) in the pix corresponds to (left, bottom) in the |
189 | | // grid (in grid coords), and the pix works up the grid from there. |
190 | | // WARNING: InsertPixPtBBox may invalidate an active GridSearch. Call |
191 | | // RepositionIterator() on any GridSearches that are active on this grid. |
192 | | void InsertPixPtBBox(int left, int bottom, Image pix, BBC *bbox); |
193 | | |
194 | | // Remove the bbox from the grid. |
195 | | // WARNING: Any GridSearch operating on this grid could be invalidated! |
196 | | // If a GridSearch is operating, call GridSearch::RemoveBBox() instead. |
197 | | void RemoveBBox(BBC *bbox); |
198 | | |
199 | | // Returns true if the given rectangle has no overlapping elements. |
200 | | bool RectangleEmpty(const TBOX &rect); |
201 | | |
202 | | // Returns an IntGrid showing the number of elements in each cell. |
203 | | // Returned IntGrid must be deleted after use. |
204 | | IntGrid *CountCellElements(); |
205 | | |
206 | | #ifndef GRAPHICS_DISABLED |
207 | | |
208 | | // Make a window of an appropriate size to display things in the grid. |
209 | | ScrollView *MakeWindow(int x, int y, const char *window_name); |
210 | | |
211 | | // Display the bounding boxes of the BLOBNBOXes in this grid. |
212 | | // Use of this function requires an additional member of the BBC class: |
213 | | // ScrollView::Color BBC::BoxColor() const. |
214 | | void DisplayBoxes(ScrollView *window); |
215 | | |
216 | | #endif // !GRAPHICS_DISABLED |
217 | | |
218 | | // ASSERT_HOST that every cell contains no more than one copy of each entry. |
219 | | void AssertNoDuplicates(); |
220 | | |
221 | | // Handle a click event in a display window. |
222 | | virtual void HandleClick(int x, int y); |
223 | | |
224 | | protected: |
225 | | BBC_CLIST *grid_; // 2-d array of CLISTS of BBC elements. |
226 | | |
227 | | private: |
228 | | }; |
229 | | |
230 | | // The GridSearch class enables neighbourhood searching on a BBGrid. |
231 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
232 | | class GridSearch { |
233 | | public: |
234 | 13.8k | GridSearch(BBGrid<BBC, BBC_CLIST, BBC_C_IT> *grid) : grid_(grid) {}Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::GridSearch(tesseract::BBGrid<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>*) Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::GridSearch(tesseract::BBGrid<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>*) Unexecuted instantiation: tesseract::GridSearch<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::GridSearch(tesseract::BBGrid<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>*) tesseract::GridSearch<tesseract::WordWithBox, tesseract::WordWithBox_CLIST, tesseract::ConsList<tesseract::WordWithBox>::Iterator>::GridSearch(tesseract::BBGrid<tesseract::WordWithBox, tesseract::WordWithBox_CLIST, tesseract::ConsList<tesseract::WordWithBox>::Iterator>*) Line | Count | Source | 234 | 13.8k | GridSearch(BBGrid<BBC, BBC_CLIST, BBC_C_IT> *grid) : grid_(grid) {} |
|
235 | | |
236 | | // Get the grid x, y coords of the most recently returned BBC. |
237 | 0 | int GridX() const { |
238 | 0 | return x_; |
239 | 0 | } |
240 | 0 | int GridY() const { |
241 | 0 | return y_; |
242 | 0 | } Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::GridY() const Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::GridY() const |
243 | | |
244 | | // Sets the search mode to return a box only once. |
245 | | // Efficiency warning: Implementation currently uses a squared-order |
246 | | // search in the number of returned elements. Use only where a small |
247 | | // number of elements are spread over a wide area, eg ColPartitions. |
248 | 0 | void SetUniqueMode(bool mode) { |
249 | 0 | unique_mode_ = mode; |
250 | 0 | } Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::SetUniqueMode(bool) Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::SetUniqueMode(bool) |
251 | | // TODO(rays) Replace calls to ReturnedSeedElement with SetUniqueMode. |
252 | | // It only works if the search includes the bottom-left corner. |
253 | | // Apart from full search, all other searches return a box several |
254 | | // times if the box is inserted with h_spread or v_spread. |
255 | | // This method will return true for only one occurrence of each box |
256 | | // that was inserted with both h_spread and v_spread as true. |
257 | | // It will usually return false for boxes that were not inserted with |
258 | | // both h_spread=true and v_spread=true |
259 | | bool ReturnedSeedElement() const { |
260 | | TBOX box = previous_return_->bounding_box(); |
261 | | int x_center = (box.left() + box.right()) / 2; |
262 | | int y_center = (box.top() + box.bottom()) / 2; |
263 | | int grid_x, grid_y; |
264 | | grid_->GridCoords(x_center, y_center, &grid_x, &grid_y); |
265 | | return (x_ == grid_x) && (y_ == grid_y); |
266 | | } |
267 | | |
268 | | // Various searching iterations... Note that these iterations |
269 | | // all share data members, so you can't run more than one iteration |
270 | | // in parallel in a single GridSearch instance, but multiple instances |
271 | | // can search the same BBGrid in parallel. |
272 | | // Note that all the searches can return blobs that may not exactly |
273 | | // match the search conditions, since they return everything in the |
274 | | // covered grid cells. It is up to the caller to check for |
275 | | // appropriateness. |
276 | | // TODO(rays) NextRectSearch only returns valid elements. Make the other |
277 | | // searches test before return also and remove the tests from code |
278 | | // that uses GridSearch. |
279 | | |
280 | | // Start a new full search. Will iterate all stored blobs, from the top. |
281 | | // If the blobs have been inserted using InsertBBox, (not InsertPixPtBBox) |
282 | | // then the full search guarantees to return each blob in the grid once. |
283 | | // Other searches may return a blob more than once if they have been |
284 | | // inserted using h_spread or v_spread. |
285 | | void StartFullSearch(); |
286 | | // Return the next bbox in the search or nullptr if done. |
287 | | BBC *NextFullSearch(); |
288 | | |
289 | | // Start a new radius search. Will search in a spiral up to a |
290 | | // given maximum radius in grid cells from the given center in pixels. |
291 | | void StartRadSearch(int x, int y, int max_radius); |
292 | | // Return the next bbox in the radius search or nullptr if the |
293 | | // maximum radius has been reached. |
294 | | BBC *NextRadSearch(); |
295 | | |
296 | | // Start a new left or right-looking search. Will search to the side |
297 | | // for a box that vertically overlaps the given vertical line segment. |
298 | | // CAVEAT: This search returns all blobs from the cells to the side |
299 | | // of the start, and somewhat below, since there is no guarantee |
300 | | // that there may not be a taller object in a lower cell. The |
301 | | // blobs returned will include all those that vertically overlap and |
302 | | // are no more than twice as high, but may also include some that do |
303 | | // not overlap and some that are more than twice as high. |
304 | | void StartSideSearch(int x, int ymin, int ymax); |
305 | | // Return the next bbox in the side search or nullptr if the |
306 | | // edge has been reached. Searches left to right or right to left |
307 | | // according to the flag. |
308 | | BBC *NextSideSearch(bool right_to_left); |
309 | | |
310 | | // Start a vertical-looking search. Will search up or down |
311 | | // for a box that horizontally overlaps the given line segment. |
312 | | void StartVerticalSearch(int xmin, int xmax, int y); |
313 | | // Return the next bbox in the vertical search or nullptr if the |
314 | | // edge has been reached. Searches top to bottom or bottom to top |
315 | | // according to the flag. |
316 | | BBC *NextVerticalSearch(bool top_to_bottom); |
317 | | |
318 | | // Start a rectangular search. Will search for a box that overlaps the |
319 | | // given rectangle. |
320 | | void StartRectSearch(const TBOX &rect); |
321 | | // Return the next bbox in the rectangular search or nullptr if complete. |
322 | | BBC *NextRectSearch(); |
323 | | |
324 | | // Remove the last returned BBC. Will not invalidate this. May invalidate |
325 | | // any other concurrent GridSearch on the same grid. If any others are |
326 | | // in use, call RepositionIterator on those, to continue without harm. |
327 | | void RemoveBBox(); |
328 | | void RepositionIterator(); |
329 | | |
330 | | private: |
331 | | // Factored out helper to start a search. |
332 | | void CommonStart(int x, int y); |
333 | | // Factored out helper to complete a next search. |
334 | | BBC *CommonNext(); |
335 | | // Factored out final return when search is exhausted. |
336 | | BBC *CommonEnd(); |
337 | | // Factored out function to set the iterator to the current x_, y_ |
338 | | // grid coords and mark the cycle pt. |
339 | | void SetIterator(); |
340 | | |
341 | | private: |
342 | | // The grid we are searching. |
343 | | BBGrid<BBC, BBC_CLIST, BBC_C_IT> *grid_ = nullptr; |
344 | | // For executing a search. The different search algorithms use these in |
345 | | // different ways, but most use x_origin_ and y_origin_ as the start position. |
346 | | int x_origin_ = 0; |
347 | | int y_origin_ = 0; |
348 | | int max_radius_ = 0; |
349 | | int radius_ = 0; |
350 | | int rad_index_ = 0; |
351 | | int rad_dir_ = 0; |
352 | | TBOX rect_; |
353 | | int x_ = 0; // The current location in grid coords, of the current search. |
354 | | int y_ = 0; |
355 | | bool unique_mode_ = false; |
356 | | BBC *previous_return_ = nullptr; // Previous return from Next*. |
357 | | BBC *next_return_ = nullptr; // Current value of it_.data() used for repositioning. |
358 | | // An iterator over the list at (x_, y_) in the grid_. |
359 | | BBC_C_IT it_; |
360 | | // Set of unique returned elements used when unique_mode_ is true. |
361 | | std::unordered_set<BBC *> returns_; |
362 | | }; |
363 | | |
364 | | // Sort function to sort a BBC by bounding_box().left(). |
365 | | template <class BBC> |
366 | 10.7M | int SortByBoxLeft(const BBC *p1, const BBC *p2) { |
367 | 10.7M | int result = p1->bounding_box().left() - p2->bounding_box().left(); |
368 | 10.7M | if (result != 0) { |
369 | 9.94M | return result; |
370 | 9.94M | } |
371 | 800k | result = p1->bounding_box().right() - p2->bounding_box().right(); |
372 | 800k | if (result != 0) { |
373 | 286k | return result; |
374 | 286k | } |
375 | 513k | result = p1->bounding_box().bottom() - p2->bounding_box().bottom(); |
376 | 513k | if (result != 0) { |
377 | 513k | return result; |
378 | 513k | } |
379 | 418 | return p1->bounding_box().top() - p2->bounding_box().top(); |
380 | 513k | } Unexecuted instantiation: int tesseract::SortByBoxLeft<tesseract::ColPartition>(tesseract::ColPartition const*, tesseract::ColPartition const*) Unexecuted instantiation: int tesseract::SortByBoxLeft<tesseract::BLOBNBOX>(tesseract::BLOBNBOX const*, tesseract::BLOBNBOX const*) Unexecuted instantiation: int tesseract::SortByBoxLeft<tesseract::ColSegment>(tesseract::ColSegment const*, tesseract::ColSegment const*) int tesseract::SortByBoxLeft<tesseract::WordWithBox>(tesseract::WordWithBox const*, tesseract::WordWithBox const*) Line | Count | Source | 366 | 10.7M | int SortByBoxLeft(const BBC *p1, const BBC *p2) { | 367 | 10.7M | int result = p1->bounding_box().left() - p2->bounding_box().left(); | 368 | 10.7M | if (result != 0) { | 369 | 9.94M | return result; | 370 | 9.94M | } | 371 | 800k | result = p1->bounding_box().right() - p2->bounding_box().right(); | 372 | 800k | if (result != 0) { | 373 | 286k | return result; | 374 | 286k | } | 375 | 513k | result = p1->bounding_box().bottom() - p2->bounding_box().bottom(); | 376 | 513k | if (result != 0) { | 377 | 513k | return result; | 378 | 513k | } | 379 | 418 | return p1->bounding_box().top() - p2->bounding_box().top(); | 380 | 513k | } |
|
381 | | |
382 | | template <class BBC> |
383 | 0 | bool StdSortByBoxLeft(const BBC *p1, const BBC *p2) { |
384 | 0 | int result = p1->bounding_box().left() - p2->bounding_box().left(); |
385 | 0 | if (result != 0) { |
386 | 0 | return result < 0; |
387 | 0 | } |
388 | 0 | result = p1->bounding_box().right() - p2->bounding_box().right(); |
389 | 0 | if (result != 0) { |
390 | 0 | return result < 0; |
391 | 0 | } |
392 | 0 | result = p1->bounding_box().bottom() - p2->bounding_box().bottom(); |
393 | 0 | if (result != 0) { |
394 | 0 | return result < 0; |
395 | 0 | } |
396 | 0 | return p1->bounding_box().top() < p2->bounding_box().top(); |
397 | 0 | } |
398 | | |
399 | | // Sort function to sort a BBC by bounding_box().right() in right-to-left order. |
400 | | template <class BBC> |
401 | | int SortRightToLeft(const BBC *p1, const BBC *p2) { |
402 | | int result = p2->bounding_box().right() - p1->bounding_box().right(); |
403 | | if (result != 0) { |
404 | | return result; |
405 | | } |
406 | | result = p2->bounding_box().left() - p1->bounding_box().left(); |
407 | | if (result != 0) { |
408 | | return result; |
409 | | } |
410 | | result = p1->bounding_box().bottom() - p2->bounding_box().bottom(); |
411 | | if (result != 0) { |
412 | | return result; |
413 | | } |
414 | | return p1->bounding_box().top() - p2->bounding_box().top(); |
415 | | } |
416 | | |
417 | | template <class BBC> |
418 | 0 | bool StdSortRightToLeft(const BBC *p1, const BBC *p2) { |
419 | 0 | int result = p2->bounding_box().right() - p1->bounding_box().right(); |
420 | 0 | if (result != 0) { |
421 | 0 | return result < 0; |
422 | 0 | } |
423 | 0 | result = p2->bounding_box().left() - p1->bounding_box().left(); |
424 | 0 | if (result != 0) { |
425 | 0 | return result < 0; |
426 | 0 | } |
427 | 0 | result = p1->bounding_box().bottom() - p2->bounding_box().bottom(); |
428 | 0 | if (result != 0) { |
429 | 0 | return result < 0; |
430 | 0 | } |
431 | 0 | return p1->bounding_box().top() < p2->bounding_box().top(); |
432 | 0 | } |
433 | | |
434 | | // Sort function to sort a BBC by bounding_box().bottom(). |
435 | | template <class BBC> |
436 | 0 | int SortByBoxBottom(const BBC *p1, const BBC *p2) { |
437 | 0 | int result = p1->bounding_box().bottom() - p2->bounding_box().bottom(); |
438 | 0 | if (result != 0) { |
439 | 0 | return result; |
440 | 0 | } |
441 | 0 | result = p1->bounding_box().top() - p2->bounding_box().top(); |
442 | 0 | if (result != 0) { |
443 | 0 | return result; |
444 | 0 | } |
445 | 0 | result = p1->bounding_box().left() - p2->bounding_box().left(); |
446 | 0 | if (result != 0) { |
447 | 0 | return result; |
448 | 0 | } |
449 | 0 | return p1->bounding_box().right() - p2->bounding_box().right(); |
450 | 0 | } |
451 | | |
452 | | /////////////////////////////////////////////////////////////////////// |
453 | | // BBGrid IMPLEMENTATION. |
454 | | /////////////////////////////////////////////////////////////////////// |
455 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
456 | 0 | BBGrid<BBC, BBC_CLIST, BBC_C_IT>::BBGrid() : grid_(nullptr) {}Unexecuted instantiation: tesseract::BBGrid<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::BBGrid() Unexecuted instantiation: tesseract::BBGrid<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::BBGrid() |
457 | | |
458 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
459 | | BBGrid<BBC, BBC_CLIST, BBC_C_IT>::BBGrid(int gridsize, const ICOORD &bleft, const ICOORD &tright) |
460 | 13.8k | : grid_(nullptr) { |
461 | 13.8k | Init(gridsize, bleft, tright); |
462 | 13.8k | } Unexecuted instantiation: tesseract::BBGrid<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::BBGrid(int, tesseract::ICOORD const&, tesseract::ICOORD const&) Unexecuted instantiation: tesseract::BBGrid<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::BBGrid(int, tesseract::ICOORD const&, tesseract::ICOORD const&) tesseract::BBGrid<tesseract::WordWithBox, tesseract::WordWithBox_CLIST, tesseract::ConsList<tesseract::WordWithBox>::Iterator>::BBGrid(int, tesseract::ICOORD const&, tesseract::ICOORD const&) Line | Count | Source | 460 | 13.8k | : grid_(nullptr) { | 461 | 13.8k | Init(gridsize, bleft, tright); | 462 | 13.8k | } |
|
463 | | |
464 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
465 | 13.8k | BBGrid<BBC, BBC_CLIST, BBC_C_IT>::~BBGrid() { |
466 | 13.8k | delete[] grid_; |
467 | 13.8k | } Unexecuted instantiation: tesseract::BBGrid<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::~BBGrid() Unexecuted instantiation: tesseract::BBGrid<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::~BBGrid() Unexecuted instantiation: tesseract::BBGrid<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::~BBGrid() tesseract::BBGrid<tesseract::WordWithBox, tesseract::WordWithBox_CLIST, tesseract::ConsList<tesseract::WordWithBox>::Iterator>::~BBGrid() Line | Count | Source | 465 | 13.8k | BBGrid<BBC, BBC_CLIST, BBC_C_IT>::~BBGrid() { | 466 | 13.8k | delete[] grid_; | 467 | 13.8k | } |
|
468 | | |
469 | | // (Re)Initialize the grid. The gridsize is the size in pixels of each cell, |
470 | | // and bleft, tright are the bounding box of everything to go in it. |
471 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
472 | | void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::Init(int gridsize, const ICOORD &bleft, |
473 | 13.8k | const ICOORD &tright) { |
474 | 13.8k | GridBase::Init(gridsize, bleft, tright); |
475 | 13.8k | delete[] grid_; |
476 | 13.8k | grid_ = new BBC_CLIST[gridbuckets_]; |
477 | 13.8k | } Unexecuted instantiation: tesseract::BBGrid<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::Init(int, tesseract::ICOORD const&, tesseract::ICOORD const&) Unexecuted instantiation: tesseract::BBGrid<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::Init(int, tesseract::ICOORD const&, tesseract::ICOORD const&) Unexecuted instantiation: tesseract::BBGrid<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::Init(int, tesseract::ICOORD const&, tesseract::ICOORD const&) tesseract::BBGrid<tesseract::WordWithBox, tesseract::WordWithBox_CLIST, tesseract::ConsList<tesseract::WordWithBox>::Iterator>::Init(int, tesseract::ICOORD const&, tesseract::ICOORD const&) Line | Count | Source | 473 | 13.8k | const ICOORD &tright) { | 474 | 13.8k | GridBase::Init(gridsize, bleft, tright); | 475 | 13.8k | delete[] grid_; | 476 | 13.8k | grid_ = new BBC_CLIST[gridbuckets_]; | 477 | 13.8k | } |
|
478 | | |
479 | | // Clear all lists, but leave the array of lists present. |
480 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
481 | 0 | void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::Clear() { |
482 | 0 | for (int i = 0; i < gridbuckets_; ++i) { |
483 | 0 | grid_[i].shallow_clear(); |
484 | 0 | } |
485 | 0 | } Unexecuted instantiation: tesseract::BBGrid<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::Clear() Unexecuted instantiation: tesseract::BBGrid<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::Clear() Unexecuted instantiation: tesseract::BBGrid<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::Clear() |
486 | | |
487 | | // Deallocate the data in the lists but otherwise leave the lists and the grid |
488 | | // intact. |
489 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
490 | 0 | void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::ClearGridData(void (*free_method)(BBC *)) { |
491 | 0 | if (grid_ == nullptr) { |
492 | 0 | return; |
493 | 0 | } |
494 | 0 | GridSearch<BBC, BBC_CLIST, BBC_C_IT> search(this); |
495 | 0 | search.StartFullSearch(); |
496 | 0 | BBC *bb; |
497 | 0 | BBC_CLIST bb_list; |
498 | 0 | BBC_C_IT it(&bb_list); |
499 | 0 | while ((bb = search.NextFullSearch()) != nullptr) { |
500 | 0 | it.add_after_then_move(bb); |
501 | 0 | } |
502 | 0 | for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) { |
503 | 0 | free_method(it.data()); |
504 | 0 | } |
505 | 0 | } Unexecuted instantiation: tesseract::BBGrid<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::ClearGridData(void (*)(tesseract::ColPartition*)) Unexecuted instantiation: tesseract::BBGrid<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::ClearGridData(void (*)(tesseract::ColSegment*)) |
506 | | |
507 | | // Insert a bbox into the appropriate place in the grid. |
508 | | // If h_spread, then all cells covered horizontally by the box are |
509 | | // used, otherwise, just the bottom-left. Similarly for v_spread. |
510 | | // WARNING: InsertBBox may invalidate an active GridSearch. Call |
511 | | // RepositionIterator() on any GridSearches that are active on this grid. |
512 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
513 | 196k | void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::InsertBBox(bool h_spread, bool v_spread, BBC *bbox) { |
514 | 196k | TBOX box = bbox->bounding_box(); |
515 | 196k | int start_x, start_y, end_x, end_y; |
516 | 196k | GridCoords(box.left(), box.bottom(), &start_x, &start_y); |
517 | 196k | GridCoords(box.right(), box.top(), &end_x, &end_y); |
518 | 196k | if (!h_spread) { |
519 | 0 | end_x = start_x; |
520 | 0 | } |
521 | 196k | if (!v_spread) { |
522 | 0 | end_y = start_y; |
523 | 0 | } |
524 | 196k | int grid_index = start_y * gridwidth_; |
525 | 1.02M | for (int y = start_y; y <= end_y; ++y, grid_index += gridwidth_) { |
526 | 5.37M | for (int x = start_x; x <= end_x; ++x) { |
527 | 4.54M | grid_[grid_index + x].add_sorted(SortByBoxLeft<BBC>, true, bbox); |
528 | 4.54M | } |
529 | 826k | } |
530 | 196k | } Unexecuted instantiation: tesseract::BBGrid<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::InsertBBox(bool, bool, tesseract::ColPartition*) Unexecuted instantiation: tesseract::BBGrid<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::InsertBBox(bool, bool, tesseract::BLOBNBOX*) Unexecuted instantiation: tesseract::BBGrid<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::InsertBBox(bool, bool, tesseract::ColSegment*) tesseract::BBGrid<tesseract::WordWithBox, tesseract::WordWithBox_CLIST, tesseract::ConsList<tesseract::WordWithBox>::Iterator>::InsertBBox(bool, bool, tesseract::WordWithBox*) Line | Count | Source | 513 | 196k | void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::InsertBBox(bool h_spread, bool v_spread, BBC *bbox) { | 514 | 196k | TBOX box = bbox->bounding_box(); | 515 | 196k | int start_x, start_y, end_x, end_y; | 516 | 196k | GridCoords(box.left(), box.bottom(), &start_x, &start_y); | 517 | 196k | GridCoords(box.right(), box.top(), &end_x, &end_y); | 518 | 196k | if (!h_spread) { | 519 | 0 | end_x = start_x; | 520 | 0 | } | 521 | 196k | if (!v_spread) { | 522 | 0 | end_y = start_y; | 523 | 0 | } | 524 | 196k | int grid_index = start_y * gridwidth_; | 525 | 1.02M | for (int y = start_y; y <= end_y; ++y, grid_index += gridwidth_) { | 526 | 5.37M | for (int x = start_x; x <= end_x; ++x) { | 527 | 4.54M | grid_[grid_index + x].add_sorted(SortByBoxLeft<BBC>, true, bbox); | 528 | 4.54M | } | 529 | 826k | } | 530 | 196k | } |
|
531 | | |
532 | | // Using a pix from TraceOutlineOnReducedPix or TraceBlockOnReducedPix, in |
533 | | // which each pixel corresponds to a grid cell, insert a bbox into every |
534 | | // place in the grid where the corresponding pixel is 1. The Pix is handled |
535 | | // upside-down to match the Tesseract coordinate system. (As created by |
536 | | // TraceOutlineOnReducedPix or TraceBlockOnReducedPix.) |
537 | | // (0, 0) in the pix corresponds to (left, bottom) in the |
538 | | // grid (in grid coords), and the pix works up the grid from there. |
539 | | // WARNING: InsertPixPtBBox may invalidate an active GridSearch. Call |
540 | | // RepositionIterator() on any GridSearches that are active on this grid. |
541 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
542 | | void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::InsertPixPtBBox(int left, int bottom, Image pix, BBC *bbox) { |
543 | | int width = pixGetWidth(pix); |
544 | | int height = pixGetHeight(pix); |
545 | | for (int y = 0; y < height; ++y) { |
546 | | l_uint32 *data = pixGetData(pix) + y * pixGetWpl(pix); |
547 | | for (int x = 0; x < width; ++x) { |
548 | | if (Image::getDataBit(data, x)) { |
549 | | grid_[(bottom + y) * gridwidth_ + x + left].add_sorted(SortByBoxLeft<BBC>, true, bbox); |
550 | | } |
551 | | } |
552 | | } |
553 | | } |
554 | | |
555 | | // Remove the bbox from the grid. |
556 | | // WARNING: Any GridSearch operating on this grid could be invalidated! |
557 | | // If a GridSearch is operating, call GridSearch::RemoveBBox() instead. |
558 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
559 | 0 | void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::RemoveBBox(BBC *bbox) { |
560 | 0 | TBOX box = bbox->bounding_box(); |
561 | 0 | int start_x, start_y, end_x, end_y; |
562 | 0 | GridCoords(box.left(), box.bottom(), &start_x, &start_y); |
563 | 0 | GridCoords(box.right(), box.top(), &end_x, &end_y); |
564 | 0 | int grid_index = start_y * gridwidth_; |
565 | 0 | for (int y = start_y; y <= end_y; ++y, grid_index += gridwidth_) { |
566 | 0 | for (int x = start_x; x <= end_x; ++x) { |
567 | 0 | BBC_C_IT it(&grid_[grid_index + x]); |
568 | 0 | for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) { |
569 | 0 | if (it.data() == bbox) { |
570 | 0 | it.extract(); |
571 | 0 | } |
572 | 0 | } |
573 | 0 | } |
574 | 0 | } |
575 | 0 | } Unexecuted instantiation: tesseract::BBGrid<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::RemoveBBox(tesseract::ColPartition*) Unexecuted instantiation: tesseract::BBGrid<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::RemoveBBox(tesseract::BLOBNBOX*) Unexecuted instantiation: tesseract::BBGrid<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::RemoveBBox(tesseract::ColSegment*) |
576 | | |
577 | | // Returns true if the given rectangle has no overlapping elements. |
578 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
579 | | bool BBGrid<BBC, BBC_CLIST, BBC_C_IT>::RectangleEmpty(const TBOX &rect) { |
580 | | GridSearch<BBC, BBC_CLIST, BBC_C_IT> rsearch(this); |
581 | | rsearch.StartRectSearch(rect); |
582 | | return rsearch.NextRectSearch() == nullptr; |
583 | | } |
584 | | |
585 | | // Returns an IntGrid showing the number of elements in each cell. |
586 | | // Returned IntGrid must be deleted after use. |
587 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
588 | 0 | IntGrid *BBGrid<BBC, BBC_CLIST, BBC_C_IT>::CountCellElements() { |
589 | 0 | auto *intgrid = new IntGrid(gridsize(), bleft(), tright()); |
590 | 0 | for (int y = 0; y < gridheight(); ++y) { |
591 | 0 | for (int x = 0; x < gridwidth(); ++x) { |
592 | 0 | int cell_count = grid_[y * gridwidth() + x].length(); |
593 | 0 | intgrid->SetGridCell(x, y, cell_count); |
594 | 0 | } |
595 | 0 | } |
596 | 0 | return intgrid; |
597 | 0 | } |
598 | | |
599 | | #ifndef GRAPHICS_DISABLED |
600 | | template <class G> |
601 | | class TabEventHandler : public SVEventHandler { |
602 | | public: |
603 | | explicit TabEventHandler(G *grid) : grid_(grid) {} |
604 | | void Notify(const SVEvent *sv_event) override { |
605 | | if (sv_event->type == SVET_CLICK) { |
606 | | grid_->HandleClick(sv_event->x, sv_event->y); |
607 | | } |
608 | | } |
609 | | |
610 | | private: |
611 | | G *grid_; |
612 | | }; |
613 | | |
614 | | // Make a window of an appropriate size to display things in the grid. |
615 | | // Position the window at the given x,y. |
616 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
617 | | ScrollView *BBGrid<BBC, BBC_CLIST, BBC_C_IT>::MakeWindow(int x, int y, const char *window_name) { |
618 | | auto tab_win = |
619 | | new ScrollView(window_name, x, y, tright_.x() - bleft_.x(), tright_.y() - bleft_.y(), |
620 | | tright_.x() - bleft_.x(), tright_.y() - bleft_.y(), true); |
621 | | auto *handler = new TabEventHandler<BBGrid<BBC, BBC_CLIST, BBC_C_IT>>(this); |
622 | | tab_win->AddEventHandler(handler); |
623 | | tab_win->Pen(ScrollView::GREY); |
624 | | tab_win->Rectangle(0, 0, tright_.x() - bleft_.x(), tright_.y() - bleft_.y()); |
625 | | return tab_win; |
626 | | } |
627 | | |
628 | | // Create a window at (x,y) and display the bounding boxes of the |
629 | | // BLOBNBOXes in this grid. |
630 | | // Use of this function requires an additional member of the BBC class: |
631 | | // ScrollView::Color BBC::BoxColor() const. |
632 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
633 | | void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::DisplayBoxes(ScrollView *tab_win) { |
634 | | tab_win->Pen(ScrollView::BLUE); |
635 | | tab_win->Brush(ScrollView::NONE); |
636 | | |
637 | | // For every bbox in the grid, display it. |
638 | | GridSearch<BBC, BBC_CLIST, BBC_C_IT> gsearch(this); |
639 | | gsearch.StartFullSearch(); |
640 | | BBC *bbox; |
641 | | while ((bbox = gsearch.NextFullSearch()) != nullptr) { |
642 | | const TBOX &box = bbox->bounding_box(); |
643 | | int left_x = box.left(); |
644 | | int right_x = box.right(); |
645 | | int top_y = box.top(); |
646 | | int bottom_y = box.bottom(); |
647 | | ScrollView::Color box_color = bbox->BoxColor(); |
648 | | tab_win->Pen(box_color); |
649 | | tab_win->Rectangle(left_x, bottom_y, right_x, top_y); |
650 | | } |
651 | | tab_win->Update(); |
652 | | } |
653 | | |
654 | | #endif // !GRAPHICS_DISABLED |
655 | | |
656 | | // ASSERT_HOST that every cell contains no more than one copy of each entry. |
657 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
658 | 0 | void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::AssertNoDuplicates() { |
659 | | // Process all grid cells. |
660 | 0 | for (int i = gridwidth_ * gridheight_ - 1; i >= 0; --i) { |
661 | | // Iterate over all elements excent the last. |
662 | 0 | for (BBC_C_IT it(&grid_[i]); !it.at_last(); it.forward()) { |
663 | 0 | BBC *ptr = it.data(); |
664 | 0 | BBC_C_IT it2(it); |
665 | | // None of the rest of the elements in the list should equal ptr. |
666 | 0 | for (it2.forward(); !it2.at_first(); it2.forward()) { |
667 | 0 | ASSERT_HOST(it2.data() != ptr); |
668 | 0 | } |
669 | 0 | } |
670 | 0 | } |
671 | 0 | } |
672 | | |
673 | | // Handle a click event in a display window. |
674 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
675 | 0 | void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::HandleClick(int x, int y) { |
676 | 0 | tprintf("Click at (%d, %d)\n", x, y); |
677 | 0 | } Unexecuted instantiation: tesseract::BBGrid<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::HandleClick(int, int) Unexecuted instantiation: tesseract::BBGrid<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::HandleClick(int, int) Unexecuted instantiation: tesseract::BBGrid<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::HandleClick(int, int) Unexecuted instantiation: tesseract::BBGrid<tesseract::WordWithBox, tesseract::WordWithBox_CLIST, tesseract::ConsList<tesseract::WordWithBox>::Iterator>::HandleClick(int, int) |
678 | | |
679 | | /////////////////////////////////////////////////////////////////////// |
680 | | // GridSearch IMPLEMENTATION. |
681 | | /////////////////////////////////////////////////////////////////////// |
682 | | |
683 | | // Start a new full search. Will iterate all stored blobs. |
684 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
685 | 0 | void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::StartFullSearch() { |
686 | | // Full search uses x_ and y_ as the current grid |
687 | | // cell being searched. |
688 | 0 | CommonStart(grid_->bleft_.x(), grid_->tright_.y()); |
689 | 0 | } Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::StartFullSearch() Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::StartFullSearch() Unexecuted instantiation: tesseract::GridSearch<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::StartFullSearch() |
690 | | |
691 | | // Return the next bbox in the search or nullptr if done. |
692 | | // The other searches will return a box that overlaps the grid cell |
693 | | // thereby duplicating boxes, but NextFullSearch only returns each box once. |
694 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
695 | 0 | BBC *GridSearch<BBC, BBC_CLIST, BBC_C_IT>::NextFullSearch() { |
696 | 0 | int x; |
697 | 0 | int y; |
698 | 0 | do { |
699 | 0 | while (it_.cycled_list()) { |
700 | 0 | ++x_; |
701 | 0 | if (x_ >= grid_->gridwidth_) { |
702 | 0 | --y_; |
703 | 0 | if (y_ < 0) { |
704 | 0 | return CommonEnd(); |
705 | 0 | } |
706 | 0 | x_ = 0; |
707 | 0 | } |
708 | 0 | SetIterator(); |
709 | 0 | } |
710 | 0 | CommonNext(); |
711 | 0 | TBOX box = previous_return_->bounding_box(); |
712 | 0 | grid_->GridCoords(box.left(), box.bottom(), &x, &y); |
713 | 0 | } while (x != x_ || y != y_); |
714 | 0 | return previous_return_; |
715 | 0 | } Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::NextFullSearch() Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::NextFullSearch() Unexecuted instantiation: tesseract::GridSearch<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::NextFullSearch() |
716 | | |
717 | | // Start a new radius search. |
718 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
719 | 0 | void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::StartRadSearch(int x, int y, int max_radius) { |
720 | | // Rad search uses x_origin_ and y_origin_ as the center of the circle. |
721 | | // The radius_ is the radius of the (diamond-shaped) circle and |
722 | | // rad_index/rad_dir_ combine to determine the position around it. |
723 | 0 | max_radius_ = max_radius; |
724 | 0 | radius_ = 0; |
725 | 0 | rad_index_ = 0; |
726 | 0 | rad_dir_ = 3; |
727 | 0 | CommonStart(x, y); |
728 | 0 | } Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::StartRadSearch(int, int, int) Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::StartRadSearch(int, int, int) |
729 | | |
730 | | // Return the next bbox in the radius search or nullptr if the |
731 | | // maximum radius has been reached. |
732 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
733 | 0 | BBC *GridSearch<BBC, BBC_CLIST, BBC_C_IT>::NextRadSearch() { |
734 | 0 | for (;;) { |
735 | 0 | while (it_.cycled_list()) { |
736 | 0 | ++rad_index_; |
737 | 0 | if (rad_index_ >= radius_) { |
738 | 0 | ++rad_dir_; |
739 | 0 | rad_index_ = 0; |
740 | 0 | if (rad_dir_ >= 4) { |
741 | 0 | ++radius_; |
742 | 0 | if (radius_ > max_radius_) { |
743 | 0 | return CommonEnd(); |
744 | 0 | } |
745 | 0 | rad_dir_ = 0; |
746 | 0 | } |
747 | 0 | } |
748 | 0 | ICOORD offset = C_OUTLINE::chain_step(rad_dir_); |
749 | 0 | offset *= radius_ - rad_index_; |
750 | 0 | offset += C_OUTLINE::chain_step(rad_dir_ + 1) * rad_index_; |
751 | 0 | x_ = x_origin_ + offset.x(); |
752 | 0 | y_ = y_origin_ + offset.y(); |
753 | 0 | if (x_ >= 0 && x_ < grid_->gridwidth_ && y_ >= 0 && y_ < grid_->gridheight_) { |
754 | 0 | SetIterator(); |
755 | 0 | } |
756 | 0 | } |
757 | 0 | CommonNext(); |
758 | 0 | if (!unique_mode_) { |
759 | 0 | break; |
760 | 0 | } |
761 | 0 | auto inserted = returns_.insert(previous_return_); |
762 | 0 | if (inserted.second) { |
763 | 0 | break; |
764 | 0 | } |
765 | 0 | } |
766 | 0 | return previous_return_; |
767 | 0 | } Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::NextRadSearch() Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::NextRadSearch() |
768 | | |
769 | | // Start a new left or right-looking search. Will search to the side |
770 | | // for a box that vertically overlaps the given vertical line segment. |
771 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
772 | 0 | void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::StartSideSearch(int x, int ymin, int ymax) { |
773 | | // Right search records the x in x_origin_, the ymax in y_origin_ |
774 | | // and the size of the vertical strip to search in radius_. |
775 | | // To guarantee finding overlapping objects of up to twice the |
776 | | // given size, double the height. |
777 | 0 | radius_ = ((ymax - ymin) * 2 + grid_->gridsize_ - 1) / grid_->gridsize_; |
778 | 0 | rad_index_ = 0; |
779 | 0 | CommonStart(x, ymax); |
780 | 0 | } Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::StartSideSearch(int, int, int) Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::StartSideSearch(int, int, int) |
781 | | |
782 | | // Return the next bbox in the side search or nullptr if the |
783 | | // edge has been reached. Searches left to right or right to left |
784 | | // according to the flag. |
785 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
786 | 0 | BBC *GridSearch<BBC, BBC_CLIST, BBC_C_IT>::NextSideSearch(bool right_to_left) { |
787 | 0 | for (;;) { |
788 | 0 | while (it_.cycled_list()) { |
789 | 0 | ++rad_index_; |
790 | 0 | if (rad_index_ > radius_) { |
791 | 0 | if (right_to_left) { |
792 | 0 | --x_; |
793 | 0 | } else { |
794 | 0 | ++x_; |
795 | 0 | } |
796 | 0 | rad_index_ = 0; |
797 | 0 | if (x_ < 0 || x_ >= grid_->gridwidth_) { |
798 | 0 | return CommonEnd(); |
799 | 0 | } |
800 | 0 | } |
801 | 0 | y_ = y_origin_ - rad_index_; |
802 | 0 | if (y_ >= 0 && y_ < grid_->gridheight_) { |
803 | 0 | SetIterator(); |
804 | 0 | } |
805 | 0 | } |
806 | 0 | CommonNext(); |
807 | 0 | if (!unique_mode_) { |
808 | 0 | break; |
809 | 0 | } |
810 | 0 | auto inserted = returns_.insert(previous_return_); |
811 | 0 | if (inserted.second) { |
812 | 0 | break; |
813 | 0 | } |
814 | 0 | } |
815 | 0 | return previous_return_; |
816 | 0 | } Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::NextSideSearch(bool) Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::NextSideSearch(bool) |
817 | | |
818 | | // Start a vertical-looking search. Will search up or down |
819 | | // for a box that horizontally overlaps the given line segment. |
820 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
821 | 0 | void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::StartVerticalSearch(int xmin, int xmax, int y) { |
822 | | // Right search records the xmin in x_origin_, the y in y_origin_ |
823 | | // and the size of the horizontal strip to search in radius_. |
824 | 0 | radius_ = (xmax - xmin + grid_->gridsize_ - 1) / grid_->gridsize_; |
825 | 0 | rad_index_ = 0; |
826 | 0 | CommonStart(xmin, y); |
827 | 0 | } Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::StartVerticalSearch(int, int, int) Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::StartVerticalSearch(int, int, int) |
828 | | |
829 | | // Return the next bbox in the vertical search or nullptr if the |
830 | | // edge has been reached. Searches top to bottom or bottom to top |
831 | | // according to the flag. |
832 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
833 | 0 | BBC *GridSearch<BBC, BBC_CLIST, BBC_C_IT>::NextVerticalSearch(bool top_to_bottom) { |
834 | 0 | for (;;) { |
835 | 0 | while (it_.cycled_list()) { |
836 | 0 | ++rad_index_; |
837 | 0 | if (rad_index_ > radius_) { |
838 | 0 | if (top_to_bottom) { |
839 | 0 | --y_; |
840 | 0 | } else { |
841 | 0 | ++y_; |
842 | 0 | } |
843 | 0 | rad_index_ = 0; |
844 | 0 | if (y_ < 0 || y_ >= grid_->gridheight_) { |
845 | 0 | return CommonEnd(); |
846 | 0 | } |
847 | 0 | } |
848 | 0 | x_ = x_origin_ + rad_index_; |
849 | 0 | if (x_ >= 0 && x_ < grid_->gridwidth_) { |
850 | 0 | SetIterator(); |
851 | 0 | } |
852 | 0 | } |
853 | 0 | CommonNext(); |
854 | 0 | if (!unique_mode_) { |
855 | 0 | break; |
856 | 0 | } |
857 | 0 | auto inserted = returns_.insert(previous_return_); |
858 | 0 | if (inserted.second) { |
859 | 0 | break; |
860 | 0 | } |
861 | 0 | } |
862 | 0 | return previous_return_; |
863 | 0 | } Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::NextVerticalSearch(bool) Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::NextVerticalSearch(bool) |
864 | | |
865 | | // Start a rectangular search. Will search for a box that overlaps the |
866 | | // given rectangle. |
867 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
868 | 0 | void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::StartRectSearch(const TBOX &rect) { |
869 | | // Rect search records the xmin in x_origin_, the ymin in y_origin_ |
870 | | // and the xmax in max_radius_. |
871 | | // The search proceeds left to right, top to bottom. |
872 | 0 | rect_ = rect; |
873 | 0 | CommonStart(rect.left(), rect.top()); |
874 | 0 | grid_->GridCoords(rect.right(), rect.bottom(), // - rect.height(), |
875 | 0 | &max_radius_, &y_origin_); |
876 | 0 | } Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::StartRectSearch(tesseract::TBOX const&) Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::StartRectSearch(tesseract::TBOX const&) Unexecuted instantiation: tesseract::GridSearch<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::StartRectSearch(tesseract::TBOX const&) Unexecuted instantiation: tesseract::GridSearch<tesseract::WordWithBox, tesseract::WordWithBox_CLIST, tesseract::ConsList<tesseract::WordWithBox>::Iterator>::StartRectSearch(tesseract::TBOX const&) |
877 | | |
878 | | // Return the next bbox in the rectangular search or nullptr if complete. |
879 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
880 | 0 | BBC *GridSearch<BBC, BBC_CLIST, BBC_C_IT>::NextRectSearch() { |
881 | 0 | for (;;) { |
882 | 0 | while (it_.cycled_list()) { |
883 | 0 | ++x_; |
884 | 0 | if (x_ > max_radius_) { |
885 | 0 | --y_; |
886 | 0 | x_ = x_origin_; |
887 | 0 | if (y_ < y_origin_) { |
888 | 0 | return CommonEnd(); |
889 | 0 | } |
890 | 0 | } |
891 | 0 | SetIterator(); |
892 | 0 | } |
893 | 0 | CommonNext(); |
894 | 0 | if (!rect_.overlap(previous_return_->bounding_box())) { |
895 | 0 | continue; |
896 | 0 | } |
897 | 0 | if (!unique_mode_) { |
898 | 0 | break; |
899 | 0 | } |
900 | 0 | auto inserted = returns_.insert(previous_return_); |
901 | 0 | if (inserted.second) { |
902 | 0 | break; |
903 | 0 | } |
904 | 0 | } |
905 | 0 | return previous_return_; |
906 | 0 | } Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::NextRectSearch() Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::NextRectSearch() Unexecuted instantiation: tesseract::GridSearch<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::NextRectSearch() Unexecuted instantiation: tesseract::GridSearch<tesseract::WordWithBox, tesseract::WordWithBox_CLIST, tesseract::ConsList<tesseract::WordWithBox>::Iterator>::NextRectSearch() |
907 | | |
908 | | // Remove the last returned BBC. Will not invalidate this. May invalidate |
909 | | // any other concurrent GridSearch on the same grid. If any others are |
910 | | // in use, call RepositionIterator on those, to continue without harm. |
911 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
912 | 0 | void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::RemoveBBox() { |
913 | 0 | if (previous_return_ != nullptr) { |
914 | | // Remove all instances of previous_return_ from the list, so the iterator |
915 | | // remains valid after removal from the rest of the grid cells. |
916 | | // if previous_return_ is not on the list, then it has been removed already. |
917 | 0 | BBC *prev_data = nullptr; |
918 | 0 | BBC *new_previous_return = nullptr; |
919 | 0 | it_.move_to_first(); |
920 | 0 | for (it_.mark_cycle_pt(); !it_.cycled_list();) { |
921 | 0 | if (it_.data() == previous_return_) { |
922 | 0 | new_previous_return = prev_data; |
923 | 0 | it_.extract(); |
924 | 0 | it_.forward(); |
925 | 0 | next_return_ = it_.cycled_list() ? nullptr : it_.data(); |
926 | 0 | } else { |
927 | 0 | prev_data = it_.data(); |
928 | 0 | it_.forward(); |
929 | 0 | } |
930 | 0 | } |
931 | 0 | grid_->RemoveBBox(previous_return_); |
932 | 0 | previous_return_ = new_previous_return; |
933 | 0 | RepositionIterator(); |
934 | 0 | } |
935 | 0 | } Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::RemoveBBox() Unexecuted instantiation: tesseract::GridSearch<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::RemoveBBox() |
936 | | |
937 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
938 | 0 | void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::RepositionIterator() { |
939 | | // Something was deleted, so we have little choice but to clear the |
940 | | // returns list. |
941 | 0 | returns_.clear(); |
942 | | // Reset the iterator back to one past the previous return. |
943 | | // If the previous_return_ is no longer in the list, then |
944 | | // next_return_ serves as a backup. |
945 | 0 | it_.move_to_first(); |
946 | | // Special case, the first element was removed and reposition |
947 | | // iterator was called. In this case, the data is fine, but the |
948 | | // cycle point is not. Detect it and return. |
949 | 0 | if (!it_.empty() && it_.data() == next_return_) { |
950 | 0 | it_.mark_cycle_pt(); |
951 | 0 | return; |
952 | 0 | } |
953 | 0 | for (it_.mark_cycle_pt(); !it_.cycled_list(); it_.forward()) { |
954 | 0 | if (it_.data() == previous_return_ || it_.data_relative(1) == next_return_) { |
955 | 0 | CommonNext(); |
956 | 0 | return; |
957 | 0 | } |
958 | 0 | } |
959 | | // We ran off the end of the list. Move to a new cell next time. |
960 | 0 | previous_return_ = nullptr; |
961 | 0 | next_return_ = nullptr; |
962 | 0 | } Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::RepositionIterator() Unexecuted instantiation: tesseract::GridSearch<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::RepositionIterator() |
963 | | |
964 | | // Factored out helper to start a search. |
965 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
966 | 0 | void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::CommonStart(int x, int y) { |
967 | 0 | grid_->GridCoords(x, y, &x_origin_, &y_origin_); |
968 | 0 | x_ = x_origin_; |
969 | 0 | y_ = y_origin_; |
970 | 0 | SetIterator(); |
971 | 0 | previous_return_ = nullptr; |
972 | 0 | next_return_ = it_.empty() ? nullptr : it_.data(); |
973 | 0 | returns_.clear(); |
974 | 0 | } Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::CommonStart(int, int) Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::CommonStart(int, int) Unexecuted instantiation: tesseract::GridSearch<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::CommonStart(int, int) Unexecuted instantiation: tesseract::GridSearch<tesseract::WordWithBox, tesseract::WordWithBox_CLIST, tesseract::ConsList<tesseract::WordWithBox>::Iterator>::CommonStart(int, int) |
975 | | |
976 | | // Factored out helper to complete a next search. |
977 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
978 | 0 | BBC *GridSearch<BBC, BBC_CLIST, BBC_C_IT>::CommonNext() { |
979 | 0 | previous_return_ = it_.data(); |
980 | 0 | it_.forward(); |
981 | 0 | next_return_ = it_.cycled_list() ? nullptr : it_.data(); |
982 | 0 | return previous_return_; |
983 | 0 | } Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::CommonNext() Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::CommonNext() Unexecuted instantiation: tesseract::GridSearch<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::CommonNext() Unexecuted instantiation: tesseract::GridSearch<tesseract::WordWithBox, tesseract::WordWithBox_CLIST, tesseract::ConsList<tesseract::WordWithBox>::Iterator>::CommonNext() |
984 | | |
985 | | // Factored out final return when search is exhausted. |
986 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
987 | 0 | BBC *GridSearch<BBC, BBC_CLIST, BBC_C_IT>::CommonEnd() { |
988 | 0 | previous_return_ = nullptr; |
989 | 0 | next_return_ = nullptr; |
990 | 0 | return nullptr; |
991 | 0 | } Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::CommonEnd() Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::CommonEnd() Unexecuted instantiation: tesseract::GridSearch<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::CommonEnd() Unexecuted instantiation: tesseract::GridSearch<tesseract::WordWithBox, tesseract::WordWithBox_CLIST, tesseract::ConsList<tesseract::WordWithBox>::Iterator>::CommonEnd() |
992 | | |
993 | | // Factored out function to set the iterator to the current x_, y_ |
994 | | // grid coords and mark the cycle pt. |
995 | | template <class BBC, class BBC_CLIST, class BBC_C_IT> |
996 | 0 | void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::SetIterator() { |
997 | 0 | it_ = &(grid_->grid_[y_ * grid_->gridwidth_ + x_]); |
998 | 0 | it_.mark_cycle_pt(); |
999 | 0 | } Unexecuted instantiation: tesseract::GridSearch<tesseract::ColPartition, tesseract::ColPartition_CLIST, tesseract::ConsList<tesseract::ColPartition>::Iterator>::SetIterator() Unexecuted instantiation: tesseract::GridSearch<tesseract::BLOBNBOX, tesseract::BLOBNBOX_CLIST, tesseract::ConsList<tesseract::BLOBNBOX>::Iterator>::SetIterator() Unexecuted instantiation: tesseract::GridSearch<tesseract::ColSegment, tesseract::ColSegment_CLIST, tesseract::ConsList<tesseract::ColSegment>::Iterator>::SetIterator() Unexecuted instantiation: tesseract::GridSearch<tesseract::WordWithBox, tesseract::WordWithBox_CLIST, tesseract::ConsList<tesseract::WordWithBox>::Iterator>::SetIterator() |
1000 | | |
1001 | | } // namespace tesseract. |
1002 | | |
1003 | | #endif // TESSERACT_TEXTORD_BBGRID_H_ |