tesseract  3.03
/usr/local/google/home/jbreiden/tesseract-ocr-read-only/textord/bbgrid.h
Go to the documentation of this file.
00001 
00002 // File:        bbgrid.h
00003 // Description: Class to hold BLOBNBOXs in a grid for fast access
00004 //              to neighbours.
00005 // Author:      Ray Smith
00006 // Created:     Wed Jun 06 17:22:01 PDT 2007
00007 //
00008 // (C) Copyright 2007, Google Inc.
00009 // Licensed under the Apache License, Version 2.0 (the "License");
00010 // you may not use this file except in compliance with the License.
00011 // You may obtain a copy of the License at
00012 // http://www.apache.org/licenses/LICENSE-2.0
00013 // Unless required by applicable law or agreed to in writing, software
00014 // distributed under the License is distributed on an "AS IS" BASIS,
00015 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00016 // See the License for the specific language governing permissions and
00017 // limitations under the License.
00018 //
00020 
00021 #ifndef TESSERACT_TEXTORD_BBGRID_H__
00022 #define TESSERACT_TEXTORD_BBGRID_H__
00023 
00024 #include "clst.h"
00025 #include "coutln.h"
00026 #include "hashfn.h"
00027 #include "rect.h"
00028 #include "scrollview.h"
00029 
00030 #include "allheaders.h"
00031 
00032 class BLOCK;
00033 
00034 namespace tesseract {
00035 
00036 // Helper function to return a scaled Pix with one pixel per grid cell,
00037 // set (black) where the given outline enters the corresponding grid cell,
00038 // and clear where the outline does not touch the grid cell.
00039 // Also returns the grid coords of the bottom-left of the Pix, in *left
00040 // and *bottom, which corresponds to (0, 0) on the Pix.
00041 // Note that the Pix is used upside-down, with (0, 0) being the bottom-left.
00042 Pix* TraceOutlineOnReducedPix(C_OUTLINE* outline, int gridsize,
00043                               ICOORD bleft, int* left, int* bottom);
00044 // As TraceOutlineOnReducedPix above, but on a BLOCK instead of a C_OUTLINE.
00045 Pix* TraceBlockOnReducedPix(BLOCK* block, int gridsize,
00046                             ICOORD bleft, int* left, int* bottom);
00047 
00048 template<class BBC, class BBC_CLIST, class BBC_C_IT> class GridSearch;
00049 
00050 // The GridBase class is the base class for BBGrid and IntGrid.
00051 // It holds the geometry and scale of the grid.
00052 class GridBase {
00053  public:
00054   GridBase();
00055   GridBase(int gridsize, const ICOORD& bleft, const ICOORD& tright);
00056   virtual ~GridBase();
00057 
00058   // (Re)Initialize the grid. The gridsize is the size in pixels of each cell,
00059   // and bleft, tright are the bounding box of everything to go in it.
00060   void Init(int gridsize, const ICOORD& bleft, const ICOORD& tright);
00061 
00062   // Simple accessors.
00063   int gridsize() const {
00064     return gridsize_;
00065   }
00066   int gridwidth() const {
00067     return gridwidth_;
00068   }
00069   int gridheight() const {
00070     return gridheight_;
00071   }
00072   const ICOORD& bleft() const {
00073     return bleft_;
00074   }
00075   const ICOORD& tright() const {
00076     return tright_;
00077   }
00078   // Compute the given grid coordinates from image coords.
00079   void GridCoords(int x, int y, int* grid_x, int* grid_y) const;
00080 
00081   // Clip the given grid coordinates to fit within the grid.
00082   void ClipGridCoords(int* x, int* y) const;
00083 
00084  protected:
00085   // TODO(rays) Make these private and migrate to the accessors in subclasses.
00086   int gridsize_;     // Pixel size of each grid cell.
00087   int gridwidth_;    // Size of the grid in cells.
00088   int gridheight_;
00089   int gridbuckets_;  // Total cells in grid.
00090   ICOORD bleft_;     // Pixel coords of bottom-left of grid.
00091   ICOORD tright_;    // Pixel coords of top-right of grid.
00092 
00093  private:
00094 };
00095 
00096 // The IntGrid maintains a single int for each cell in a grid.
00097 class IntGrid : public GridBase {
00098  public:
00099   IntGrid();
00100   IntGrid(int gridsize, const ICOORD& bleft, const ICOORD& tright);
00101   virtual ~IntGrid();
00102 
00103   // (Re)Initialize the grid. The gridsize is the size in pixels of each cell,
00104   // and bleft, tright are the bounding box of everything to go in it.
00105   void Init(int gridsize, const ICOORD& bleft, const ICOORD& tright);
00106 
00107   // Clear all the ints in the grid to zero.
00108   void Clear();
00109 
00110   // Rotate the grid by rotation, keeping cell contents.
00111   // rotation must be a multiple of 90 degrees.
00112   // NOTE: due to partial cells, cell coverage in the rotated grid will be
00113   // inexact. This is why there is no Rotate for the generic BBGrid.
00114   void Rotate(const FCOORD& rotation);
00115 
00116   // Returns a new IntGrid containing values equal to the sum of all the
00117   // neighbouring cells. The returned grid must be deleted after use.
00118   IntGrid* NeighbourhoodSum() const;
00119 
00120   int GridCellValue(int grid_x, int grid_y) const {
00121     ClipGridCoords(&grid_x, &grid_y);
00122     return grid_[grid_y * gridwidth_ + grid_x];
00123   }
00124   void SetGridCell(int grid_x, int grid_y, int value) {
00125     ASSERT_HOST(grid_x >= 0 && grid_x < gridwidth());
00126     ASSERT_HOST(grid_y >= 0 && grid_y < gridheight());
00127     grid_[grid_y * gridwidth_ + grid_x] = value;
00128   }
00129   // Returns true if more than half the area of the rect is covered by grid
00130   // cells that are over the theshold.
00131   bool RectMostlyOverThreshold(const TBOX& rect, int threshold) const;
00132 
00133   // Returns true if any cell value in the given rectangle is zero.
00134   bool AnyZeroInRect(const TBOX& rect) const;
00135 
00136   // Returns a full-resolution binary pix in which each cell over the given
00137   // threshold is filled as a black square. pixDestroy after use.
00138   Pix* ThresholdToPix(int threshold) const;
00139 
00140  private:
00141   int* grid_;  // 2-d array of ints.
00142 };
00143 
00144 // The BBGrid class holds C_LISTs of template classes BBC (bounding box class)
00145 // in a grid for fast neighbour access.
00146 // The BBC class must have a member const TBOX& bounding_box() const.
00147 // The BBC class must have been CLISTIZEH'ed elsewhere to make the
00148 // list class BBC_CLIST and the iterator BBC_C_IT.
00149 // Use of C_LISTs enables BBCs to exist in multiple cells simultaneously.
00150 // As a consequence, ownership of BBCs is assumed to be elsewhere and
00151 // persistent for at least the life of the BBGrid, or at least until Clear is
00152 // called which removes all references to inserted objects without actually
00153 // deleting them.
00154 // Most uses derive a class from a specific instantiation of BBGrid,
00155 // thereby making most of the ugly template notation go away.
00156 // The friend class GridSearch, with the same template arguments, is
00157 // used to search a grid efficiently in one of several search patterns.
00158 template<class BBC, class BBC_CLIST, class BBC_C_IT> class BBGrid
00159   : public GridBase {
00160   friend class GridSearch<BBC, BBC_CLIST, BBC_C_IT>;
00161  public:
00162   BBGrid();
00163   BBGrid(int gridsize, const ICOORD& bleft, const ICOORD& tright);
00164   virtual ~BBGrid();
00165 
00166   // (Re)Initialize the grid. The gridsize is the size in pixels of each cell,
00167   // and bleft, tright are the bounding box of everything to go in it.
00168   void Init(int gridsize, const ICOORD& bleft, const ICOORD& tright);
00169 
00170   // Empty all the lists but leave the grid itself intact.
00171   void Clear();
00172   // Deallocate the data in the lists but otherwise leave the lists and the grid
00173   // intact.
00174   void ClearGridData(void (*free_method)(BBC*));
00175 
00176   // Insert a bbox into the appropriate place in the grid.
00177   // If h_spread, then all cells covered horizontally by the box are
00178   // used, otherwise, just the bottom-left. Similarly for v_spread.
00179   // WARNING: InsertBBox may invalidate an active GridSearch. Call
00180   // RepositionIterator() on any GridSearches that are active on this grid.
00181   void InsertBBox(bool h_spread, bool v_spread, BBC* bbox);
00182 
00183   // Using a pix from TraceOutlineOnReducedPix or TraceBlockOnReducedPix, in
00184   // which each pixel corresponds to a grid cell, insert a bbox into every
00185   // place in the grid where the corresponding pixel is 1. The Pix is handled
00186   // upside-down to match the Tesseract coordinate system. (As created by
00187   // TraceOutlineOnReducedPix or TraceBlockOnReducedPix.)
00188   // (0, 0) in the pix corresponds to (left, bottom) in the
00189   // grid (in grid coords), and the pix works up the grid from there.
00190   // WARNING: InsertPixPtBBox may invalidate an active GridSearch. Call
00191   // RepositionIterator() on any GridSearches that are active on this grid.
00192   void InsertPixPtBBox(int left, int bottom, Pix* pix, BBC* bbox);
00193 
00194   // Remove the bbox from the grid.
00195   // WARNING: Any GridSearch operating on this grid could be invalidated!
00196   // If a GridSearch is operating, call GridSearch::RemoveBBox() instead.
00197   void RemoveBBox(BBC* bbox);
00198 
00199   // Returns true if the given rectangle has no overlapping elements.
00200   bool RectangleEmpty(const TBOX& rect);
00201 
00202   // Returns an IntGrid showing the number of elements in each cell.
00203   // Returned IntGrid must be deleted after use.
00204   IntGrid* CountCellElements();
00205 
00206   // Make a window of an appropriate size to display things in the grid.
00207   ScrollView* MakeWindow(int x, int y, const char* window_name);
00208 
00209   // Display the bounding boxes of the BLOBNBOXes in this grid.
00210   // Use of this function requires an additional member of the BBC class:
00211   // ScrollView::Color BBC::BoxColor() const.
00212   void DisplayBoxes(ScrollView* window);
00213 
00214   // ASSERT_HOST that every cell contains no more than one copy of each entry.
00215   void AssertNoDuplicates();
00216 
00217   // Handle a click event in a display window.
00218   virtual void HandleClick(int x, int y);
00219 
00220  protected:
00221   BBC_CLIST* grid_;  // 2-d array of CLISTS of BBC elements.
00222 
00223  private:
00224 };
00225 
00226 // Hash functor for generic pointers.
00227 template<typename T> struct PtrHash {
00228   size_t operator()(const T* ptr) const {
00229     return reinterpret_cast<size_t>(ptr) / sizeof(T);
00230   }
00231 };
00232 
00233 
00234 // The GridSearch class enables neighbourhood searching on a BBGrid.
00235 template<class BBC, class BBC_CLIST, class BBC_C_IT> class GridSearch {
00236  public:
00237   GridSearch(BBGrid<BBC, BBC_CLIST, BBC_C_IT>* grid)
00238       : grid_(grid), unique_mode_(false),
00239         previous_return_(NULL), next_return_(NULL) {
00240   }
00241 
00242   // Get the grid x, y coords of the most recently returned BBC.
00243   int GridX() const {
00244     return x_;
00245   }
00246   int GridY() const {
00247     return y_;
00248   }
00249 
00250   // Sets the search mode to return a box only once.
00251   // Efficiency warning: Implementation currently uses a squared-order
00252   // search in the number of returned elements. Use only where a small
00253   // number of elements are spread over a wide area, eg ColPartitions.
00254   void SetUniqueMode(bool mode) {
00255     unique_mode_ = mode;
00256   }
00257   // TODO(rays) Replace calls to ReturnedSeedElement with SetUniqueMode.
00258   // It only works if the search includes the bottom-left corner.
00259   // Apart from full search, all other searches return a box several
00260   // times if the box is inserted with h_spread or v_spread.
00261   // This method will return true for only one occurrence of each box
00262   // that was inserted with both h_spread and v_spread as true.
00263   // It will usually return false for boxes that were not inserted with
00264   // both h_spread=true and v_spread=true
00265   bool ReturnedSeedElement() const {
00266     TBOX box = previous_return_->bounding_box();
00267     int x_center = (box.left()+box.right())/2;
00268     int y_center = (box.top()+box.bottom())/2;
00269     int grid_x, grid_y;
00270     grid_->GridCoords(x_center, y_center, &grid_x, &grid_y);
00271     return (x_ == grid_x) && (y_ == grid_y);
00272   }
00273 
00274   // Various searching iterations... Note that these iterations
00275   // all share data members, so you can't run more than one iteration
00276   // in parallel in a single GridSearch instance, but multiple instances
00277   // can search the same BBGrid in parallel.
00278   // Note that all the searches can return blobs that may not exactly
00279   // match the search conditions, since they return everything in the
00280   // covered grid cells. It is up to the caller to check for
00281   // appropriateness.
00282   // TODO(rays) NextRectSearch only returns valid elements. Make the other
00283   // searches test before return also and remove the tests from code
00284   // that uses GridSearch.
00285 
00286   // Start a new full search. Will iterate all stored blobs, from the top.
00287   // If the blobs have been inserted using InsertBBox, (not InsertPixPtBBox)
00288   // then the full search guarantees to return each blob in the grid once.
00289   // Other searches may return a blob more than once if they have been
00290   // inserted using h_spread or v_spread.
00291   void StartFullSearch();
00292   // Return the next bbox in the search or NULL if done.
00293   BBC* NextFullSearch();
00294 
00295   // Start a new radius search. Will search in a spiral upto a
00296   // given maximum radius in grid cells from the given center in pixels.
00297   void StartRadSearch(int x, int y, int max_radius);
00298   // Return the next bbox in the radius search or NULL if the
00299   // maximum radius has been reached.
00300   BBC* NextRadSearch();
00301 
00302   // Start a new left or right-looking search. Will search to the side
00303   // for a box that vertically overlaps the given vertical line segment.
00304   // CAVEAT: This search returns all blobs from the cells to the side
00305   // of the start, and somewhat below, since there is no guarantee
00306   // that there may not be a taller object in a lower cell. The
00307   // blobs returned will include all those that vertically overlap and
00308   // are no more than twice as high, but may also include some that do
00309   // not overlap and some that are more than twice as high.
00310   void StartSideSearch(int x, int ymin, int ymax);
00311   // Return the next bbox in the side search or NULL if the
00312   // edge has been reached. Searches left to right or right to left
00313   // according to the flag.
00314   BBC* NextSideSearch(bool right_to_left);
00315 
00316   // Start a vertical-looking search. Will search up or down
00317   // for a box that horizontally overlaps the given line segment.
00318   void StartVerticalSearch(int xmin, int xmax, int y);
00319   // Return the next bbox in the vertical search or NULL if the
00320   // edge has been reached. Searches top to bottom or bottom to top
00321   // according to the flag.
00322   BBC* NextVerticalSearch(bool top_to_bottom);
00323 
00324   // Start a rectangular search. Will search for a box that overlaps the
00325   // given rectangle.
00326   void StartRectSearch(const TBOX& rect);
00327   // Return the next bbox in the rectangular search or NULL if complete.
00328   BBC* NextRectSearch();
00329 
00330   // Remove the last returned BBC. Will not invalidate this. May invalidate
00331   // any other concurrent GridSearch on the same grid. If any others are
00332   // in use, call RepositionIterator on those, to continue without harm.
00333   void RemoveBBox();
00334   void RepositionIterator();
00335 
00336  private:
00337   // Factored out helper to start a search.
00338   void CommonStart(int x, int y);
00339   // Factored out helper to complete a next search.
00340   BBC* CommonNext();
00341   // Factored out final return when search is exhausted.
00342   BBC* CommonEnd();
00343   // Factored out function to set the iterator to the current x_, y_
00344   // grid coords and mark the cycle pt.
00345   void SetIterator();
00346 
00347  private:
00348   // The grid we are searching.
00349   BBGrid<BBC, BBC_CLIST, BBC_C_IT>* grid_;
00350   // For executing a search. The different search algorithms use these in
00351   // different ways, but most use x_origin_ and y_origin_ as the start position.
00352   int x_origin_;
00353   int y_origin_;
00354   int max_radius_;
00355   int radius_;
00356   int rad_index_;
00357   int rad_dir_;
00358   TBOX rect_;
00359   int x_;  // The current location in grid coords, of the current search.
00360   int y_;
00361   bool unique_mode_;
00362   BBC* previous_return_;  // Previous return from Next*.
00363   BBC* next_return_;  // Current value of it_.data() used for repositioning.
00364   // An iterator over the list at (x_, y_) in the grid_.
00365   BBC_C_IT it_;
00366   // Set of unique returned elements used when unique_mode_ is true.
00367   unordered_set<BBC*, PtrHash<BBC> > returns_;
00368 };
00369 
00370 // Sort function to sort a BBC by bounding_box().left().
00371 template<class BBC>
00372 int SortByBoxLeft(const void* void1, const void* void2) {
00373   // The void*s are actually doubly indirected, so get rid of one level.
00374   const BBC* p1 = *reinterpret_cast<const BBC* const *>(void1);
00375   const BBC* p2 = *reinterpret_cast<const BBC* const *>(void2);
00376   int result = p1->bounding_box().left() - p2->bounding_box().left();
00377   if (result != 0)
00378     return result;
00379   result = p1->bounding_box().right() - p2->bounding_box().right();
00380   if (result != 0)
00381     return result;
00382   result = p1->bounding_box().bottom() - p2->bounding_box().bottom();
00383   if (result != 0)
00384     return result;
00385   return p1->bounding_box().top() - p2->bounding_box().top();
00386 }
00387 
00388 // Sort function to sort a BBC by bounding_box().right() in right-to-left order.
00389 template<class BBC>
00390 int SortRightToLeft(const void* void1, const void* void2) {
00391   // The void*s are actually doubly indirected, so get rid of one level.
00392   const BBC* p1 = *reinterpret_cast<const BBC* const *>(void1);
00393   const BBC* p2 = *reinterpret_cast<const BBC* const *>(void2);
00394   int result = p2->bounding_box().right() - p1->bounding_box().right();
00395   if (result != 0)
00396     return result;
00397   result = p2->bounding_box().left() - p1->bounding_box().left();
00398   if (result != 0)
00399     return result;
00400   result = p1->bounding_box().bottom() - p2->bounding_box().bottom();
00401   if (result != 0)
00402     return result;
00403   return p1->bounding_box().top() - p2->bounding_box().top();
00404 }
00405 
00406 // Sort function to sort a BBC by bounding_box().bottom().
00407 template<class BBC>
00408 int SortByBoxBottom(const void* void1, const void* void2) {
00409   // The void*s are actually doubly indirected, so get rid of one level.
00410   const BBC* p1 = *reinterpret_cast<const BBC* const *>(void1);
00411   const BBC* p2 = *reinterpret_cast<const BBC* const *>(void2);
00412   int result = p1->bounding_box().bottom() - p2->bounding_box().bottom();
00413   if (result != 0)
00414     return result;
00415   result =  p1->bounding_box().top() - p2->bounding_box().top();
00416   if (result != 0)
00417     return result;
00418   result = p1->bounding_box().left() - p2->bounding_box().left();
00419   if (result != 0)
00420     return result;
00421   return p1->bounding_box().right() - p2->bounding_box().right();
00422 }
00423 
00425 // BBGrid IMPLEMENTATION.
00427 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00428 BBGrid<BBC, BBC_CLIST, BBC_C_IT>::BBGrid() : grid_(NULL) {
00429 }
00430 
00431 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00432 BBGrid<BBC, BBC_CLIST, BBC_C_IT>::BBGrid(
00433   int gridsize, const ICOORD& bleft, const ICOORD& tright)
00434     : grid_(NULL) {
00435   Init(gridsize, bleft, tright);
00436 }
00437 
00438 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00439 BBGrid<BBC, BBC_CLIST, BBC_C_IT>::~BBGrid() {
00440   if (grid_ != NULL)
00441     delete [] grid_;
00442 }
00443 
00444 // (Re)Initialize the grid. The gridsize is the size in pixels of each cell,
00445 // and bleft, tright are the bounding box of everything to go in it.
00446 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00447 void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::Init(int gridsize,
00448                                             const ICOORD& bleft,
00449                                             const ICOORD& tright) {
00450   GridBase::Init(gridsize, bleft, tright);
00451   if (grid_ != NULL)
00452     delete [] grid_;
00453   grid_ = new BBC_CLIST[gridbuckets_];
00454 }
00455 
00456 // Clear all lists, but leave the array of lists present.
00457 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00458 void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::Clear() {
00459   for (int i = 0; i < gridbuckets_; ++i) {
00460     grid_[i].shallow_clear();
00461   }
00462 }
00463 
00464 // Deallocate the data in the lists but otherwise leave the lists and the grid
00465 // intact.
00466 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00467 void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::ClearGridData(
00468     void (*free_method)(BBC*)) {
00469   if (grid_ == NULL) return;
00470   GridSearch<BBC, BBC_CLIST, BBC_C_IT> search(this);
00471   search.StartFullSearch();
00472   BBC* bb;
00473   BBC_CLIST bb_list;
00474   BBC_C_IT it(&bb_list);
00475   while ((bb = search.NextFullSearch()) != NULL) {
00476     it.add_after_then_move(bb);
00477   }
00478   for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
00479     free_method(it.data());
00480   }
00481 }
00482 
00483 // Insert a bbox into the appropriate place in the grid.
00484 // If h_spread, then all cells covered horizontally by the box are
00485 // used, otherwise, just the bottom-left. Similarly for v_spread.
00486 // WARNING: InsertBBox may invalidate an active GridSearch. Call
00487 // RepositionIterator() on any GridSearches that are active on this grid.
00488 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00489 void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::InsertBBox(bool h_spread, bool v_spread,
00490                                                   BBC* bbox) {
00491   TBOX box = bbox->bounding_box();
00492   int start_x, start_y, end_x, end_y;
00493   GridCoords(box.left(), box.bottom(), &start_x, &start_y);
00494   GridCoords(box.right(), box.top(), &end_x, &end_y);
00495   if (!h_spread)
00496     end_x = start_x;
00497   if (!v_spread)
00498     end_y = start_y;
00499   int grid_index = start_y * gridwidth_;
00500   for (int y = start_y; y <= end_y; ++y, grid_index += gridwidth_) {
00501     for (int x = start_x; x <= end_x; ++x) {
00502       grid_[grid_index + x].add_sorted(SortByBoxLeft<BBC>, true, bbox);
00503     }
00504   }
00505 }
00506 
00507 // Using a pix from TraceOutlineOnReducedPix or TraceBlockOnReducedPix, in
00508 // which each pixel corresponds to a grid cell, insert a bbox into every
00509 // place in the grid where the corresponding pixel is 1. The Pix is handled
00510 // upside-down to match the Tesseract coordinate system. (As created by
00511 // TraceOutlineOnReducedPix or TraceBlockOnReducedPix.)
00512 // (0, 0) in the pix corresponds to (left, bottom) in the
00513 // grid (in grid coords), and the pix works up the grid from there.
00514 // WARNING: InsertPixPtBBox may invalidate an active GridSearch. Call
00515 // RepositionIterator() on any GridSearches that are active on this grid.
00516 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00517 void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::InsertPixPtBBox(int left, int bottom,
00518                                                        Pix* pix, BBC* bbox) {
00519   int width = pixGetWidth(pix);
00520   int height = pixGetHeight(pix);
00521   for (int y = 0; y < height; ++y) {
00522     l_uint32* data = pixGetData(pix) + y * pixGetWpl(pix);
00523     for (int x = 0; x < width; ++x) {
00524       if (GET_DATA_BIT(data, x)) {
00525         grid_[(bottom + y) * gridwidth_ + x + left].
00526           add_sorted(SortByBoxLeft<BBC>, true, bbox);
00527       }
00528     }
00529   }
00530 }
00531 
00532 // Remove the bbox from the grid.
00533 // WARNING: Any GridSearch operating on this grid could be invalidated!
00534 // If a GridSearch is operating, call GridSearch::RemoveBBox() instead.
00535 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00536 void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::RemoveBBox(BBC* bbox) {
00537   TBOX box = bbox->bounding_box();
00538   int start_x, start_y, end_x, end_y;
00539   GridCoords(box.left(), box.bottom(), &start_x, &start_y);
00540   GridCoords(box.right(), box.top(), &end_x, &end_y);
00541   int grid_index = start_y * gridwidth_;
00542   for (int y = start_y; y <= end_y; ++y, grid_index += gridwidth_) {
00543     for (int x = start_x; x <= end_x; ++x) {
00544       BBC_C_IT it(&grid_[grid_index + x]);
00545       for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
00546         if (it.data() == bbox)
00547           it.extract();
00548       }
00549     }
00550   }
00551 }
00552 
00553 // Returns true if the given rectangle has no overlapping elements.
00554 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00555 bool BBGrid<BBC, BBC_CLIST, BBC_C_IT>::RectangleEmpty(const TBOX& rect) {
00556   GridSearch<BBC, BBC_CLIST, BBC_C_IT> rsearch(this);
00557   rsearch.StartRectSearch(rect);
00558   return rsearch.NextRectSearch() == NULL;
00559 }
00560 
00561 // Returns an IntGrid showing the number of elements in each cell.
00562 // Returned IntGrid must be deleted after use.
00563 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00564 IntGrid* BBGrid<BBC, BBC_CLIST, BBC_C_IT>::CountCellElements() {
00565   IntGrid* intgrid = new IntGrid(gridsize(), bleft(), tright());
00566   for (int y = 0; y < gridheight(); ++y) {
00567     for (int x = 0; x < gridwidth(); ++x) {
00568       int cell_count = grid_[y * gridwidth() + x].length();
00569       intgrid->SetGridCell(x, y, cell_count);
00570     }
00571   }
00572   return intgrid;
00573 }
00574 
00575 
00576 template<class G> class TabEventHandler : public SVEventHandler {
00577  public:
00578   explicit TabEventHandler(G* grid) : grid_(grid) {
00579   }
00580   void Notify(const SVEvent* sv_event) {
00581     if (sv_event->type == SVET_CLICK) {
00582       grid_->HandleClick(sv_event->x, sv_event->y);
00583     }
00584   }
00585  private:
00586   G* grid_;
00587 };
00588 
00589 // Make a window of an appropriate size to display things in the grid.
00590 // Position the window at the given x,y.
00591 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00592 ScrollView* BBGrid<BBC, BBC_CLIST, BBC_C_IT>::MakeWindow(
00593     int x, int y, const char* window_name) {
00594   ScrollView* tab_win = NULL;
00595 #ifndef GRAPHICS_DISABLED
00596   tab_win = new ScrollView(window_name, x, y,
00597                            tright_.x() - bleft_.x(),
00598                            tright_.y() - bleft_.y(),
00599                            tright_.x() - bleft_.x(),
00600                            tright_.y() - bleft_.y(),
00601                            true);
00602   TabEventHandler<BBGrid<BBC, BBC_CLIST, BBC_C_IT> >* handler =
00603     new TabEventHandler<BBGrid<BBC, BBC_CLIST, BBC_C_IT> >(this);
00604   tab_win->AddEventHandler(handler);
00605   tab_win->Pen(ScrollView::GREY);
00606   tab_win->Rectangle(0, 0, tright_.x() - bleft_.x(), tright_.y() - bleft_.y());
00607 #endif
00608   return tab_win;
00609 }
00610 
00611 // Create a window at (x,y) and display the bounding boxes of the
00612 // BLOBNBOXes in this grid.
00613 // Use of this function requires an additional member of the BBC class:
00614 // ScrollView::Color BBC::BoxColor() const.
00615 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00616 void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::DisplayBoxes(ScrollView* tab_win) {
00617 #ifndef GRAPHICS_DISABLED
00618   tab_win->Pen(ScrollView::BLUE);
00619   tab_win->Brush(ScrollView::NONE);
00620 
00621   // For every bbox in the grid, display it.
00622   GridSearch<BBC, BBC_CLIST, BBC_C_IT> gsearch(this);
00623   gsearch.StartFullSearch();
00624   BBC* bbox;
00625   while ((bbox = gsearch.NextFullSearch()) != NULL) {
00626     TBOX box = bbox->bounding_box();
00627     int left_x = box.left();
00628     int right_x = box.right();
00629     int top_y = box.top();
00630     int bottom_y = box.bottom();
00631     ScrollView::Color box_color = bbox->BoxColor();
00632     tab_win->Pen(box_color);
00633     tab_win->Rectangle(left_x, bottom_y, right_x, top_y);
00634   }
00635   tab_win->Update();
00636 #endif
00637 }
00638 
00639 // ASSERT_HOST that every cell contains no more than one copy of each entry.
00640 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00641 void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::AssertNoDuplicates() {
00642   // Process all grid cells.
00643   for (int i = gridwidth_ * gridheight_ - 1; i >= 0; --i) {
00644     // Iterate over all elements excent the last.
00645     for (BBC_C_IT it(&grid_[i]); !it.at_last(); it.forward()) {
00646       BBC* ptr = it.data();
00647       BBC_C_IT it2(it);
00648       // None of the rest of the elements in the list should equal ptr.
00649       for (it2.forward(); !it2.at_first(); it2.forward()) {
00650         ASSERT_HOST(it2.data() != ptr);
00651       }
00652     }
00653   }
00654 }
00655 
00656 // Handle a click event in a display window.
00657 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00658 void BBGrid<BBC, BBC_CLIST, BBC_C_IT>::HandleClick(int x, int y) {
00659   tprintf("Click at (%d, %d)\n", x, y);
00660 }
00661 
00663 // GridSearch IMPLEMENTATION.
00665 
00666 // Start a new full search. Will iterate all stored blobs.
00667 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00668 void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::StartFullSearch() {
00669   // Full search uses x_ and y_ as the current grid
00670   // cell being searched.
00671   CommonStart(grid_->bleft_.x(), grid_->tright_.y());
00672 }
00673 
00674 // Return the next bbox in the search or NULL if done.
00675 // The other searches will return a box that overlaps the grid cell
00676 // thereby duplicating boxes, but NextFullSearch only returns each box once.
00677 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00678 BBC* GridSearch<BBC, BBC_CLIST, BBC_C_IT>::NextFullSearch() {
00679   int x;
00680   int y;
00681   do {
00682     while (it_.cycled_list()) {
00683       ++x_;
00684       if (x_ >= grid_->gridwidth_) {
00685         --y_;
00686         if (y_ < 0)
00687           return CommonEnd();
00688         x_ = 0;
00689       }
00690       SetIterator();
00691     }
00692     CommonNext();
00693     TBOX box = previous_return_->bounding_box();
00694     grid_->GridCoords(box.left(), box.bottom(), &x, &y);
00695   } while (x != x_ || y != y_);
00696   return previous_return_;
00697 }
00698 
00699 // Start a new radius search.
00700 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00701 void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::StartRadSearch(int x, int y,
00702                                                           int max_radius) {
00703   // Rad search uses x_origin_ and y_origin_ as the center of the circle.
00704   // The radius_ is the radius of the (diamond-shaped) circle and
00705   // rad_index/rad_dir_ combine to determine the position around it.
00706   max_radius_ = max_radius;
00707   radius_ = 0;
00708   rad_index_ = 0;
00709   rad_dir_ = 3;
00710   CommonStart(x, y);
00711 }
00712 
00713 // Return the next bbox in the radius search or NULL if the
00714 // maximum radius has been reached.
00715 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00716 BBC* GridSearch<BBC, BBC_CLIST, BBC_C_IT>::NextRadSearch() {
00717   do {
00718     while (it_.cycled_list()) {
00719       ++rad_index_;
00720       if (rad_index_ >= radius_) {
00721         ++rad_dir_;
00722         rad_index_ = 0;
00723         if (rad_dir_ >= 4) {
00724           ++radius_;
00725           if (radius_ > max_radius_)
00726             return CommonEnd();
00727           rad_dir_ = 0;
00728         }
00729       }
00730       ICOORD offset = C_OUTLINE::chain_step(rad_dir_);
00731       offset *= radius_ - rad_index_;
00732       offset += C_OUTLINE::chain_step(rad_dir_ + 1) * rad_index_;
00733       x_ = x_origin_ + offset.x();
00734       y_ = y_origin_ + offset.y();
00735       if (x_ >= 0 && x_ < grid_->gridwidth_ &&
00736           y_ >= 0 && y_ < grid_->gridheight_)
00737         SetIterator();
00738     }
00739     CommonNext();
00740   } while (unique_mode_ && returns_.find(previous_return_) != returns_.end());
00741   if (unique_mode_)
00742     returns_.insert(previous_return_);
00743   return previous_return_;
00744 }
00745 
00746 // Start a new left or right-looking search. Will search to the side
00747 // for a box that vertically overlaps the given vertical line segment.
00748 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00749 void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::StartSideSearch(int x,
00750                                                            int ymin, int ymax) {
00751   // Right search records the x in x_origin_, the ymax in y_origin_
00752   // and the size of the vertical strip to search in radius_.
00753   // To guarantee finding overlapping objects of upto twice the
00754   // given size, double the height.
00755   radius_ = ((ymax - ymin) * 2 + grid_->gridsize_ - 1) / grid_->gridsize_;
00756   rad_index_ = 0;
00757   CommonStart(x, ymax);
00758 }
00759 
00760 // Return the next bbox in the side search or NULL if the
00761 // edge has been reached. Searches left to right or right to left
00762 // according to the flag.
00763 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00764 BBC* GridSearch<BBC, BBC_CLIST, BBC_C_IT>::NextSideSearch(bool right_to_left) {
00765   do {
00766     while (it_.cycled_list()) {
00767       ++rad_index_;
00768       if (rad_index_ > radius_) {
00769         if (right_to_left)
00770           --x_;
00771         else
00772           ++x_;
00773         rad_index_ = 0;
00774         if (x_ < 0 || x_ >= grid_->gridwidth_)
00775           return CommonEnd();
00776       }
00777       y_ = y_origin_ - rad_index_;
00778       if (y_ >= 0 && y_ < grid_->gridheight_)
00779         SetIterator();
00780     }
00781     CommonNext();
00782   } while (unique_mode_ && returns_.find(previous_return_) != returns_.end());
00783   if (unique_mode_)
00784     returns_.insert(previous_return_);
00785   return previous_return_;
00786 }
00787 
00788 // Start a vertical-looking search. Will search up or down
00789 // for a box that horizontally overlaps the given line segment.
00790 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00791 void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::StartVerticalSearch(int xmin,
00792                                                                int xmax,
00793                                                                int y) {
00794   // Right search records the xmin in x_origin_, the y in y_origin_
00795   // and the size of the horizontal strip to search in radius_.
00796   radius_ = (xmax - xmin + grid_->gridsize_ - 1) / grid_->gridsize_;
00797   rad_index_ = 0;
00798   CommonStart(xmin, y);
00799 }
00800 
00801 // Return the next bbox in the vertical search or NULL if the
00802 // edge has been reached. Searches top to bottom or bottom to top
00803 // according to the flag.
00804 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00805 BBC* GridSearch<BBC, BBC_CLIST, BBC_C_IT>::NextVerticalSearch(
00806     bool top_to_bottom) {
00807   do {
00808     while (it_.cycled_list()) {
00809       ++rad_index_;
00810       if (rad_index_ > radius_) {
00811         if (top_to_bottom)
00812           --y_;
00813         else
00814           ++y_;
00815         rad_index_ = 0;
00816         if (y_ < 0 || y_ >= grid_->gridheight_)
00817           return CommonEnd();
00818       }
00819       x_ = x_origin_ + rad_index_;
00820       if (x_ >= 0 && x_ < grid_->gridwidth_)
00821         SetIterator();
00822     }
00823     CommonNext();
00824   } while (unique_mode_ && returns_.find(previous_return_) != returns_.end());
00825   if (unique_mode_)
00826     returns_.insert(previous_return_);
00827   return previous_return_;
00828 }
00829 
00830 // Start a rectangular search. Will search for a box that overlaps the
00831 // given rectangle.
00832 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00833 void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::StartRectSearch(const TBOX& rect) {
00834   // Rect search records the xmin in x_origin_, the ymin in y_origin_
00835   // and the xmax in max_radius_.
00836   // The search proceeds left to right, top to bottom.
00837   rect_ = rect;
00838   CommonStart(rect.left(), rect.top());
00839   grid_->GridCoords(rect.right(), rect.bottom(),  // - rect.height(),
00840                     &max_radius_, &y_origin_);
00841 }
00842 
00843 // Return the next bbox in the rectangular search or NULL if complete.
00844 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00845 BBC* GridSearch<BBC, BBC_CLIST, BBC_C_IT>::NextRectSearch() {
00846   do {
00847     while (it_.cycled_list()) {
00848       ++x_;
00849       if (x_ > max_radius_) {
00850         --y_;
00851         x_ = x_origin_;
00852         if (y_ < y_origin_)
00853           return CommonEnd();
00854       }
00855       SetIterator();
00856     }
00857     CommonNext();
00858   } while (!rect_.overlap(previous_return_->bounding_box()) ||
00859            (unique_mode_ && returns_.find(previous_return_) != returns_.end()));
00860   if (unique_mode_)
00861     returns_.insert(previous_return_);
00862   return previous_return_;
00863 }
00864 
00865 // Remove the last returned BBC. Will not invalidate this. May invalidate
00866 // any other concurrent GridSearch on the same grid. If any others are
00867 // in use, call RepositionIterator on those, to continue without harm.
00868 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00869 void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::RemoveBBox() {
00870   if (previous_return_ != NULL) {
00871     // Remove all instances of previous_return_ from the list, so the iterator
00872     // remains valid after removal from the rest of the grid cells.
00873     // if previous_return_ is not on the list, then it has been removed already.
00874     BBC* prev_data = NULL;
00875     BBC* new_previous_return = NULL;
00876     it_.move_to_first();
00877     for (it_.mark_cycle_pt(); !it_.cycled_list();) {
00878       if (it_.data() ==  previous_return_) {
00879         new_previous_return = prev_data;
00880         it_.extract();
00881         it_.forward();
00882         next_return_ = it_.cycled_list() ? NULL : it_.data();
00883       } else {
00884         prev_data = it_.data();
00885         it_.forward();
00886       }
00887     }
00888     grid_->RemoveBBox(previous_return_);
00889     previous_return_ = new_previous_return;
00890     RepositionIterator();
00891   }
00892 }
00893 
00894 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00895 void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::RepositionIterator() {
00896   // Something was deleted, so we have little choice but to clear the
00897   // returns list.
00898   returns_.clear();
00899   // Reset the iterator back to one past the previous return.
00900   // If the previous_return_ is no longer in the list, then
00901   // next_return_ serves as a backup.
00902   it_.move_to_first();
00903   // Special case, the first element was removed and reposition
00904   // iterator was called. In this case, the data is fine, but the
00905   // cycle point is not. Detect it and return.
00906   if (!it_.empty() && it_.data() == next_return_) {
00907     it_.mark_cycle_pt();
00908     return;
00909   }
00910   for (it_.mark_cycle_pt(); !it_.cycled_list(); it_.forward()) {
00911     if (it_.data() == previous_return_ ||
00912         it_.data_relative(1) == next_return_) {
00913       CommonNext();
00914       return;
00915     }
00916   }
00917   // We ran off the end of the list. Move to a new cell next time.
00918   previous_return_ = NULL;
00919   next_return_ = NULL;
00920 }
00921 
00922 // Factored out helper to start a search.
00923 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00924 void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::CommonStart(int x, int y) {
00925   grid_->GridCoords(x, y, &x_origin_, &y_origin_);
00926   x_ = x_origin_;
00927   y_ = y_origin_;
00928   SetIterator();
00929   previous_return_ = NULL;
00930   next_return_ = it_.empty() ? NULL : it_.data();
00931   returns_.clear();
00932 }
00933 
00934 // Factored out helper to complete a next search.
00935 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00936 BBC* GridSearch<BBC, BBC_CLIST, BBC_C_IT>::CommonNext() {
00937   previous_return_ = it_.data();
00938   it_.forward();
00939   next_return_ = it_.cycled_list() ? NULL : it_.data();
00940   return previous_return_;
00941 }
00942 
00943 // Factored out final return when search is exhausted.
00944 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00945 BBC* GridSearch<BBC, BBC_CLIST, BBC_C_IT>::CommonEnd() {
00946   previous_return_ = NULL;
00947   next_return_ = NULL;
00948   return NULL;
00949 }
00950 
00951 // Factored out function to set the iterator to the current x_, y_
00952 // grid coords and mark the cycle pt.
00953 template<class BBC, class BBC_CLIST, class BBC_C_IT>
00954 void GridSearch<BBC, BBC_CLIST, BBC_C_IT>::SetIterator() {
00955   it_= &(grid_->grid_[y_ * grid_->gridwidth_ + x_]);
00956   it_.mark_cycle_pt();
00957 }
00958 
00959 }  // namespace tesseract.
00960 
00961 #endif  // TESSERACT_TEXTORD_BBGRID_H__
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines