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