tesseract
3.03
|
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__