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