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