Tesseract 3.01
|
00001 00002 // File: tabvector.h 00003 // Description: Class to hold a near-vertical vector representing a tab-stop. 00004 // Author: Ray Smith 00005 // Created: Thu Apr 10 16:25:01 PST 2008 00006 // 00007 // (C) Copyright 2008, Google Inc. 00008 // Licensed under the Apache License, Version 2.0 (the "License"); 00009 // you may not use this file except in compliance with the License. 00010 // You may obtain a copy of the License at 00011 // http://www.apache.org/licenses/LICENSE-2.0 00012 // Unless required by applicable law or agreed to in writing, software 00013 // distributed under the License is distributed on an "AS IS" BASIS, 00014 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00015 // See the License for the specific language governing permissions and 00016 // limitations under the License. 00017 // 00019 00020 #ifndef TESSERACT_TEXTORD_TABVECTOR_H__ 00021 #define TESSERACT_TEXTORD_TABVECTOR_H__ 00022 00023 #include "clst.h" 00024 #include "elst.h" 00025 #include "elst2.h" 00026 #include "rect.h" 00027 #include "bbgrid.h" 00028 00029 class BLOBNBOX; 00030 class ScrollView; 00031 00032 CLISTIZEH(BLOBNBOX) 00033 00034 namespace tesseract { 00035 00036 00037 extern double_VAR_H(textord_tabvector_vertical_gap_fraction, 0.5, 00038 "Max fraction of mean blob width allowed for vertical gaps in vertical text"); 00039 extern double_VAR_H(textord_tabvector_vertical_box_ratio, 0.5, 00040 "Fraction of box matches required to declare a line vertical"); 00041 00042 // The alignment type that a tab vector represents. 00043 // Keep this enum synced with kAlignmentNames in tabvector.cpp. 00044 enum TabAlignment { 00045 TA_LEFT_ALIGNED, 00046 TA_LEFT_RAGGED, 00047 TA_CENTER_JUSTIFIED, 00048 TA_RIGHT_ALIGNED, 00049 TA_RIGHT_RAGGED, 00050 TA_SEPARATOR, 00051 TA_COUNT 00052 }; 00053 00054 // Forward declarations. The classes use their own list types, so we 00055 // need to make the list types first. 00056 class TabFind; 00057 class TabVector; 00058 class TabConstraint; 00059 typedef BBGrid<BLOBNBOX, BLOBNBOX_CLIST, BLOBNBOX_C_IT> BlobGrid; 00060 typedef GridSearch<BLOBNBOX, BLOBNBOX_CLIST, BLOBNBOX_C_IT> BlobGridSearch; 00061 00062 ELIST2IZEH(TabVector) 00063 CLISTIZEH(TabVector) 00064 ELISTIZEH(TabConstraint) 00065 00066 // TabConstraint is a totally self-contained class to maintain 00067 // a list of [min,max] constraints, each referring to a TabVector. 00068 // The constraints are manipulated through static methods that act 00069 // on a list of constraints. The list itself is cooperatively owned 00070 // by the TabVectors of the constraints on the list and managed 00071 // by implicit reference counting via the elements of the list. 00072 class TabConstraint : public ELIST_LINK { 00073 public: 00074 TabConstraint() { 00075 // This empty constructor is here only so that the class can be ELISTIZED. 00076 // TODO(rays) change deep_copy in elst.h line 955 to take a callback copier 00077 // and eliminate CLASSNAME##_copier. 00078 } 00079 00080 // Create a constraint for the top or bottom of this TabVector. 00081 static void CreateConstraint(TabVector* vector, bool is_top); 00082 00083 // Test to see if the constraints are compatible enough to merge. 00084 static bool CompatibleConstraints(TabConstraint_LIST* list1, 00085 TabConstraint_LIST* list2); 00086 00087 // Merge the lists of constraints and update the TabVector pointers. 00088 // The second list is deleted. 00089 static void MergeConstraints(TabConstraint_LIST* list1, 00090 TabConstraint_LIST* list2); 00091 00092 // Set all the tops and bottoms as appropriate to a mean of the 00093 // constrained range. Delete all the constraints and list. 00094 static void ApplyConstraints(TabConstraint_LIST* constraints); 00095 00096 private: 00097 TabConstraint(TabVector* vector, bool is_top); 00098 00099 // Get the max of the mins and the min of the maxes. 00100 static void GetConstraints(TabConstraint_LIST* constraints, 00101 int* y_min, int* y_max); 00102 00103 // The TabVector this constraint applies to. 00104 TabVector* vector_; 00105 // If true then we refer to the top of the vector_. 00106 bool is_top_; 00107 // The allowed range of this vector_. 00108 int y_min_; 00109 int y_max_; 00110 }; 00111 00112 // Class to hold information about a single vector 00113 // that represents a tab stop or a rule line. 00114 class TabVector : public ELIST2_LINK { 00115 public: 00116 TabVector() { 00117 // TODO(rays) fix this in elst.h line 1076, where it should use the 00118 // copy constructor instead of operator=. 00119 } 00120 ~TabVector(); 00121 00122 // Public factory to build a TabVector from a list of boxes. 00123 // The TabVector will be of the given alignment type. 00124 // The input vertical vector is used in fitting, and the output 00125 // vertical_x, vertical_y have the resulting line vector added to them 00126 // if the alignment is not ragged. 00127 // The extended_start_y and extended_end_y are the maximum possible 00128 // extension to the line segment that can be used to align with others. 00129 // The input CLIST of BLOBNBOX good_points is consumed and taken over. 00130 static TabVector* FitVector(TabAlignment alignment, ICOORD vertical, 00131 int extended_start_y, int extended_end_y, 00132 BLOBNBOX_CLIST* good_points, 00133 int* vertical_x, int* vertical_y); 00134 00135 // Build a ragged TabVector by copying another's direction, shifting it 00136 // to match the given blob, and making its initial extent the height 00137 // of the blob, but its extended bounds from the bounds of the original. 00138 TabVector(const TabVector& src, TabAlignment alignment, 00139 const ICOORD& vertical_skew, BLOBNBOX* blob); 00140 00141 // Copies basic attributes of a tab vector for simple operations. 00142 // Copies things such startpt, endpt, range, width. 00143 // Does not copy things such as partners, boxes, or constraints. 00144 // This is useful if you only need vector information for processing, such 00145 // as in the table detection code. 00146 TabVector* ShallowCopy() const; 00147 00148 // Simple accessors. 00149 const ICOORD& startpt() const { 00150 return startpt_; 00151 } 00152 const ICOORD& endpt() const { 00153 return endpt_; 00154 } 00155 int extended_ymax() const { 00156 return extended_ymax_; 00157 } 00158 int extended_ymin() const { 00159 return extended_ymin_; 00160 } 00161 int sort_key() const { 00162 return sort_key_; 00163 } 00164 int mean_width() const { 00165 return mean_width_; 00166 } 00167 void set_top_constraints(TabConstraint_LIST* constraints) { 00168 top_constraints_ = constraints; 00169 } 00170 void set_bottom_constraints(TabConstraint_LIST* constraints) { 00171 bottom_constraints_ = constraints; 00172 } 00173 TabVector_CLIST* partners() { 00174 return &partners_; 00175 } 00176 void set_startpt(const ICOORD& start) { 00177 startpt_ = start; 00178 } 00179 void set_endpt(const ICOORD& end) { 00180 endpt_ = end; 00181 } 00182 00183 // Inline quasi-accessors that require some computation. 00184 00185 // Compute the x coordinate at the given y coordinate. 00186 int XAtY(int y) const { 00187 int height = endpt_.y() - startpt_.y(); 00188 if (height != 0) 00189 return (y - startpt_.y()) * (endpt_.x() - startpt_.x()) / height + 00190 startpt_.x(); 00191 else 00192 return startpt_.x(); 00193 } 00194 00195 // Compute the vertical overlap with the other TabVector. 00196 int VOverlap(const TabVector& other) const { 00197 return MIN(other.endpt_.y(), endpt_.y()) - 00198 MAX(other.startpt_.y(), startpt_.y()); 00199 } 00200 // Compute the vertical overlap with the given y bounds. 00201 int VOverlap(int top_y, int bottom_y) const { 00202 return MIN(top_y, endpt_.y()) - MAX(bottom_y, startpt_.y()); 00203 } 00204 // Compute the extended vertical overlap with the given y bounds. 00205 int ExtendedOverlap(int top_y, int bottom_y) const { 00206 return MIN(top_y, extended_ymax_) - MAX(bottom_y, extended_ymin_); 00207 } 00208 00209 // Return true if this is a left tab stop, either aligned, or ragged. 00210 bool IsLeftTab() const { 00211 return alignment_ == TA_LEFT_ALIGNED || alignment_ == TA_LEFT_RAGGED; 00212 } 00213 // Return true if this is a right tab stop, either aligned, or ragged. 00214 bool IsRightTab() const { 00215 return alignment_ == TA_RIGHT_ALIGNED || alignment_ == TA_RIGHT_RAGGED; 00216 } 00217 // Return true if this is a separator. 00218 bool IsSeparator() const { 00219 return alignment_ == TA_SEPARATOR; 00220 } 00221 // Return true if this is a center aligned tab stop. 00222 bool IsCenterTab() const { 00223 return alignment_ == TA_CENTER_JUSTIFIED; 00224 } 00225 // Return true if this is a ragged tab top, either left or right. 00226 bool IsRagged() const { 00227 return alignment_ == TA_LEFT_RAGGED || alignment_ == TA_RIGHT_RAGGED; 00228 } 00229 00230 // Return true if this vector is to the left of the other in terms 00231 // of sort_key_. 00232 bool IsLeftOf(const TabVector& other) const { 00233 return sort_key_ < other.sort_key_; 00234 } 00235 00236 // Return true if the vector has no partners. 00237 bool Partnerless() { 00238 return partners_.empty(); 00239 } 00240 00241 // Return the number of tab boxes in this vector. 00242 int BoxCount() { 00243 return boxes_.length(); 00244 } 00245 00246 // Lock the vector from refits by clearing the boxes_ list. 00247 void Freeze() { 00248 boxes_.shallow_clear(); 00249 } 00250 00251 // Flip x and y on the ends so a vector can be created from flipped input. 00252 void XYFlip() { 00253 int x = startpt_.y(); 00254 startpt_.set_y(startpt_.x()); 00255 startpt_.set_x(x); 00256 x = endpt_.y(); 00257 endpt_.set_y(endpt_.x()); 00258 endpt_.set_x(x); 00259 } 00260 00261 // Separate function to compute the sort key for a given coordinate pair. 00262 static int SortKey(const ICOORD& vertical, int x, int y) { 00263 ICOORD pt(x, y); 00264 return pt * vertical; 00265 } 00266 00267 // Return the x at the given y for the given sort key. 00268 static int XAtY(const ICOORD& vertical, int sort_key, int y) { 00269 if (vertical.y() != 0) 00270 return (vertical.x() * y + sort_key) / vertical.y(); 00271 else 00272 return sort_key; 00273 } 00274 00275 // Sort function for E2LIST::sort to sort by sort_key_. 00276 static int SortVectorsByKey(const void* v1, const void* v2) { 00277 const TabVector* tv1 = *reinterpret_cast<const TabVector* const *>(v1); 00278 const TabVector* tv2 = *reinterpret_cast<const TabVector* const *>(v2); 00279 return tv1->sort_key_ - tv2->sort_key_; 00280 } 00281 00282 // More complex members. 00283 00284 // Extend this vector to include the supplied blob if it doesn't 00285 // already have it. 00286 void ExtendToBox(BLOBNBOX* blob); 00287 00288 // Set the ycoord of the start and move the xcoord to match. 00289 void SetYStart(int start_y); 00290 // Set the ycoord of the end and move the xcoord to match. 00291 void SetYEnd(int end_y); 00292 00293 // Rotate the ends by the given vector. 00294 void Rotate(const FCOORD& rotation); 00295 00296 // Setup the initial constraints, being the limits of 00297 // the vector and the extended ends. 00298 void SetupConstraints(); 00299 00300 // Setup the constraints between the partners of this TabVector. 00301 void SetupPartnerConstraints(); 00302 00303 // Setup the constraints between this and its partner. 00304 void SetupPartnerConstraints(TabVector* partner); 00305 00306 // Use the constraints to modify the top and bottom. 00307 void ApplyConstraints(); 00308 00309 // Merge close tab vectors of the same side that overlap. 00310 static void MergeSimilarTabVectors(const ICOORD& vertical, 00311 TabVector_LIST* vectors, BlobGrid* grid); 00312 00313 // Return true if this vector is the same side, overlaps, and close 00314 // enough to the other to be merged. 00315 bool SimilarTo(const ICOORD& vertical, 00316 const TabVector& other, BlobGrid* grid) const; 00317 00318 // Eat the other TabVector into this and delete it. 00319 void MergeWith(const ICOORD& vertical, TabVector* other); 00320 00321 // Add a new element to the list of partner TabVectors. 00322 // Partners must be added in order of increasing y coordinate of the text line 00323 // that makes them partners. 00324 // Groups of identical partners are merged into one. 00325 void AddPartner(TabVector* partner); 00326 00327 // Return true if other is a partner of this. 00328 bool IsAPartner(const TabVector* other); 00329 00330 // Print basic information about this tab vector. 00331 void Print(const char* prefix); 00332 00333 // Print basic information about this tab vector and every box in it. 00334 void Debug(const char* prefix); 00335 00336 // Draw this tabvector in place in the given window. 00337 void Display(ScrollView* tab_win); 00338 00339 // Refit the line and/or re-evaluate the vector if the dirty flags are set. 00340 void FitAndEvaluateIfNeeded(const ICOORD& vertical, TabFind* finder); 00341 00342 // Evaluate the vector in terms of coverage of its length by good-looking 00343 // box edges. A good looking box is one where its nearest neighbour on the 00344 // inside is nearer than half the distance its nearest neighbour on the 00345 // outside of the putative column. Bad boxes are removed from the line. 00346 // A second pass then further filters boxes by requiring that the gutter 00347 // width be a minimum fraction of the mean gutter along the line. 00348 void Evaluate(const ICOORD& vertical, TabFind* finder); 00349 00350 // (Re)Fit a line to the stored points. Returns false if the line 00351 // is degenerate. Althougth the TabVector code mostly doesn't care about the 00352 // direction of lines, XAtY would give silly results for a horizontal line. 00353 // The class is mostly aimed at use for vertical lines representing 00354 // horizontal tab stops. 00355 bool Fit(ICOORD vertical, bool force_parallel); 00356 00357 // Return the partner of this TabVector if the vector qualifies as 00358 // being a vertical text line, otherwise NULL. 00359 TabVector* VerticalTextlinePartner(); 00360 00361 // Return the matching tabvector if there is exactly one partner, or 00362 // NULL otherwise. This can be used after matching is done, eg. by 00363 // VerticalTextlinePartner(), without checking if the line is vertical. 00364 TabVector* GetSinglePartner(); 00365 00366 private: 00367 // Constructor is private as the static factory is the external way 00368 // to build a TabVector. 00369 TabVector(int extended_ymin, int extended_ymax, 00370 TabAlignment alignment, BLOBNBOX_CLIST* boxes); 00371 00372 // Delete this, but first, repoint all the partners to point to 00373 // replacement. If replacement is NULL, then partner relationships 00374 // are removed. 00375 void Delete(TabVector* replacement); 00376 00377 private: 00378 // The bottom of the tab line. 00379 ICOORD startpt_; 00380 // The top of the tab line. 00381 ICOORD endpt_; 00382 // The lowest y that the vector might extend to. 00383 int extended_ymin_; 00384 // The highest y that the vector might extend to. 00385 int extended_ymax_; 00386 // Perpendicular distance of vector from a given vertical for sorting. 00387 int sort_key_; 00388 // Result of Evaluate 0-100. Coverage of line with good boxes. 00389 int percent_score_; 00390 // The mean width of the blobs. Meaningful only for separator lines. 00391 int mean_width_; 00392 // True if the boxes_ list has been modified, so a refit is needed. 00393 bool needs_refit_; 00394 // True if a fit has been done, so re-evaluation is needed. 00395 bool needs_evaluation_; 00396 // The type of this TabVector. 00397 TabAlignment alignment_; 00398 // The list of boxes whose edges are aligned at this TabVector. 00399 BLOBNBOX_CLIST boxes_; 00400 // List of TabVectors that have a connection with this via a text line. 00401 TabVector_CLIST partners_; 00402 // Constraints used to resolve the exact location of the top and bottom 00403 // of the tab line. 00404 TabConstraint_LIST* top_constraints_; 00405 TabConstraint_LIST* bottom_constraints_; 00406 }; 00407 00408 } // namespace tesseract. 00409 00410 #endif // TESSERACT_TEXTORD_TABVECTOR_H__