Tesseract  3.02
tesseract-ocr/textord/tabvector.h
Go to the documentation of this file.
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__