Tesseract  3.02
tesseract-ocr/textord/colpartition.h
Go to the documentation of this file.
00001 
00002 // File:        colpartition.h
00003 // Description: Class to hold partitions of the page that correspond
00004 //              roughly to text lines.
00005 // Author:      Ray Smith
00006 // Created:     Thu Aug 14 10:50:01 PDT 2008
00007 //
00008 // (C) Copyright 2008, 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_COLPARTITION_H__
00022 #define TESSERACT_TEXTORD_COLPARTITION_H__
00023 
00024 #include "bbgrid.h"
00025 #include "blobbox.h"       // For BlobRegionType.
00026 #include "ndminx.h"
00027 #include "ocrblock.h"
00028 #include "rect.h"           // For TBOX.
00029 #include "scrollview.h"
00030 #include "tabfind.h"        // For WidthCallback.
00031 #include "tabvector.h"      // For BLOBNBOX_CLIST.
00032 
00033 namespace tesseract {
00034 
00035 // Number of colors in the color1, color2 arrays.
00036 const int kRGBRMSColors = 4;
00037 
00038 class ColPartition;
00039 class ColPartitionSet;
00040 class ColPartitionGrid;
00041 class WorkingPartSet;
00042 class WorkingPartSet_LIST;
00043 
00044 // An enum to indicate how a partition sits on the columns.
00045 // The order of flowing/heading/pullout must be kept consistent with
00046 // PolyBlockType.
00047 enum ColumnSpanningType {
00048   CST_NOISE,        // Strictly between columns.
00049   CST_FLOWING,      // Strictly within a single column.
00050   CST_HEADING,      // Spans multiple columns.
00051   CST_PULLOUT,      // Touches multiple columns, but doesn't span them.
00052   CST_COUNT         // Number of entries.
00053 };
00054 
00055 ELIST2IZEH(ColPartition)
00056 CLISTIZEH(ColPartition)
00057 
00067 class ColPartition : public ELIST2_LINK {
00068  public:
00069   ColPartition() {
00070     // This empty constructor is here only so that the class can be ELISTIZED.
00071     // TODO(rays) change deep_copy in elst.h line 955 to take a callback copier
00072     // and eliminate CLASSNAME##_copier.
00073   }
00078   ColPartition(BlobRegionType blob_type, const ICOORD& vertical);
00083   static ColPartition* MakeLinePartition(BlobRegionType blob_type,
00084                                          const ICOORD& vertical,
00085                                          int left, int bottom,
00086                                          int right, int top);
00087 
00088   // Constructs and returns a fake ColPartition with a single fake BLOBNBOX,
00089   // all made from a single TBOX.
00090   // WARNING: Despite being on C_LISTs, the BLOBNBOX owns the C_BLOB and
00091   // the ColPartition owns the BLOBNBOX!!!
00092   // Call DeleteBoxes before deleting the ColPartition.
00093   static ColPartition* FakePartition(const TBOX& box,
00094                                      PolyBlockType block_type,
00095                                      BlobRegionType blob_type,
00096                                      BlobTextFlowType flow);
00097 
00098   // Constructs and returns a ColPartition with the given real BLOBNBOX,
00099   // and sets it up to be a "big" partition (single-blob partition bigger
00100   // than the surrounding text that may be a dropcap, two or more vertically
00101   // touching characters, or some graphic element.
00102   // If the given list is not NULL, the partition is also added to the list.
00103   static ColPartition* MakeBigPartition(BLOBNBOX* box,
00104                                         ColPartition_LIST* big_part_list);
00105 
00106   ~ColPartition();
00107 
00108   // Simple accessors.
00109   const TBOX& bounding_box() const {
00110     return bounding_box_;
00111   }
00112   int left_margin() const {
00113     return left_margin_;
00114   }
00115   void set_left_margin(int margin) {
00116     left_margin_ = margin;
00117   }
00118   int right_margin() const {
00119     return right_margin_;
00120   }
00121   void set_right_margin(int margin) {
00122     right_margin_ = margin;
00123   }
00124   int median_top() const {
00125     return median_top_;
00126   }
00127   int median_bottom() const {
00128     return median_bottom_;
00129   }
00130   int median_left() const {
00131     return median_left_;
00132   }
00133   int median_right() const {
00134     return median_right_;
00135   }
00136   int median_size() const {
00137     return median_size_;
00138   }
00139   void set_median_size(int size) {
00140     median_size_ = size;
00141   }
00142   int median_width() const {
00143     return median_width_;
00144   }
00145   void set_median_width(int width) {
00146     median_width_ = width;
00147   }
00148   BlobRegionType blob_type() const {
00149     return blob_type_;
00150   }
00151   void set_blob_type(BlobRegionType t) {
00152     blob_type_ = t;
00153   }
00154   BlobTextFlowType flow() const {
00155     return flow_;
00156   }
00157   void set_flow(BlobTextFlowType f) {
00158     flow_ = f;
00159   }
00160   int good_blob_score() const {
00161     return good_blob_score_;
00162   }
00163   bool good_width() const {
00164     return good_width_;
00165   }
00166   bool good_column() const {
00167     return good_column_;
00168   }
00169   bool left_key_tab() const {
00170     return left_key_tab_;
00171   }
00172   int left_key() const {
00173     return left_key_;
00174   }
00175   bool right_key_tab() const {
00176     return right_key_tab_;
00177   }
00178   int right_key() const {
00179     return right_key_;
00180   }
00181   PolyBlockType type() const {
00182     return type_;
00183   }
00184   void set_type(PolyBlockType t) {
00185     type_ = t;
00186   }
00187   BLOBNBOX_CLIST* boxes() {
00188     return &boxes_;
00189   }
00190   int boxes_count() const {
00191     return boxes_.length();
00192   }
00193   void set_vertical(const ICOORD& v) {
00194     vertical_ = v;
00195   }
00196   ColPartition_CLIST* upper_partners() {
00197     return &upper_partners_;
00198   }
00199   ColPartition_CLIST* lower_partners() {
00200     return &lower_partners_;
00201   }
00202   void set_working_set(WorkingPartSet* working_set) {
00203     working_set_ = working_set;
00204   }
00205   bool block_owned() const {
00206     return block_owned_;
00207   }
00208   void set_block_owned(bool owned) {
00209     block_owned_ = owned;
00210   }
00211   bool desperately_merged() const {
00212     return desperately_merged_;
00213   }
00214   ColPartitionSet* column_set() const {
00215     return column_set_;
00216   }
00217   void set_side_step(int step) {
00218     side_step_ = step;
00219   }
00220   int bottom_spacing() const {
00221     return bottom_spacing_;
00222   }
00223   void set_bottom_spacing(int spacing) {
00224     bottom_spacing_ = spacing;
00225   }
00226   int top_spacing() const {
00227     return top_spacing_;
00228   }
00229   void set_top_spacing(int spacing) {
00230     top_spacing_ = spacing;
00231   }
00232 
00233   void set_table_type() {
00234     if (type_ != PT_TABLE) {
00235       type_before_table_ = type_;
00236       type_ = PT_TABLE;
00237     }
00238   }
00239   void clear_table_type() {
00240     if (type_ == PT_TABLE)
00241       type_ = type_before_table_;
00242   }
00243   bool inside_table_column() {
00244     return inside_table_column_;
00245   }
00246   void set_inside_table_column(bool val) {
00247     inside_table_column_ = val;
00248   }
00249   ColPartition* nearest_neighbor_above() const {
00250     return nearest_neighbor_above_;
00251   }
00252   void set_nearest_neighbor_above(ColPartition* part) {
00253     nearest_neighbor_above_ = part;
00254   }
00255   ColPartition* nearest_neighbor_below() const {
00256     return nearest_neighbor_below_;
00257   }
00258   void set_nearest_neighbor_below(ColPartition* part) {
00259     nearest_neighbor_below_ = part;
00260   }
00261   int space_above() const {
00262     return space_above_;
00263   }
00264   void set_space_above(int space) {
00265     space_above_ = space;
00266   }
00267   int space_below() const {
00268     return space_below_;
00269   }
00270   void set_space_below(int space) {
00271     space_below_ = space;
00272   }
00273   int space_to_left() const {
00274     return space_to_left_;
00275   }
00276   void set_space_to_left(int space) {
00277     space_to_left_ = space;
00278   }
00279   int space_to_right() const {
00280     return space_to_right_;
00281   }
00282   void set_space_to_right(int space) {
00283     space_to_right_ = space;
00284   }
00285   uinT8* color1() {
00286     return color1_;
00287   }
00288   uinT8* color2() {
00289     return color2_;
00290   }
00291   bool owns_blobs() const {
00292     return owns_blobs_;
00293   }
00294   void set_owns_blobs(bool owns_blobs) {
00295     // Do NOT change ownership flag when there are blobs in the list.
00296     // Immediately set the ownership flag when creating copies.
00297     ASSERT_HOST(boxes_.empty());
00298     owns_blobs_ = owns_blobs;
00299   }
00300 
00301   // Inline quasi-accessors that require some computation.
00302 
00303   // Returns the middle y-coord of the bounding box.
00304   int MidY() const {
00305     return (bounding_box_.top() + bounding_box_.bottom()) / 2;
00306   }
00307   // Returns the middle y-coord of the median top and bottom.
00308   int MedianY() const {
00309     return (median_top_ + median_bottom_) / 2;
00310   }
00311   // Returns the middle x-coord of the bounding box.
00312   int MidX() const {
00313     return (bounding_box_.left() + bounding_box_.right()) / 2;
00314   }
00315   // Returns the sort key at any given x,y.
00316   int SortKey(int x, int y) const {
00317     return TabVector::SortKey(vertical_, x, y);
00318   }
00319   // Returns the x corresponding to the sortkey, y pair.
00320   int XAtY(int sort_key, int y) const {
00321     return TabVector::XAtY(vertical_, sort_key, y);
00322   }
00323   // Returns the x difference between the two sort keys.
00324   int KeyWidth(int left_key, int right_key) const {
00325     return (right_key - left_key) / vertical_.y();
00326   }
00327   // Returns the column width between the left and right keys.
00328   int ColumnWidth() const {
00329     return KeyWidth(left_key_, right_key_);
00330   }
00331   // Returns the sort key of the box left edge.
00332   int BoxLeftKey() const {
00333     return SortKey(bounding_box_.left(), MidY());
00334   }
00335   // Returns the sort key of the box right edge.
00336   int BoxRightKey() const {
00337     return SortKey(bounding_box_.right(), MidY());
00338   }
00339   // Returns the left edge at the given y, using the sort key.
00340   int LeftAtY(int y) const {
00341     return XAtY(left_key_, y);
00342   }
00343   // Returns the right edge at the given y, using the sort key.
00344   int RightAtY(int y) const {
00345     return XAtY(right_key_, y);
00346   }
00347   // Returns true if the right edge of this is to the left of the right
00348   // edge of other.
00349   bool IsLeftOf(const ColPartition& other) const {
00350     return bounding_box_.right() < other.bounding_box_.right();
00351   }
00352   // Returns true if the partition contains the given x coordinate at the y.
00353   bool ColumnContains(int x, int y) const {
00354     return LeftAtY(y) - 1 <= x && x <= RightAtY(y) + 1;
00355   }
00356   // Returns true if there are no blobs in the list.
00357   bool IsEmpty() const {
00358     return boxes_.empty();
00359   }
00360   // Returns true if there is a single blob in the list.
00361   bool IsSingleton() const {
00362     return boxes_.singleton();
00363   }
00364   // Returns true if this and other overlap horizontally by bounding box.
00365   bool HOverlaps(const ColPartition& other) const {
00366     return bounding_box_.x_overlap(other.bounding_box_);
00367   }
00368   // Returns true if this and other's bounding boxes overlap vertically.
00369   // TODO(rays) Make HOverlaps and VOverlaps truly symmetric.
00370   bool VOverlaps(const ColPartition& other) const {
00371     return bounding_box_.y_gap(other.bounding_box_) < 0;
00372   }
00373   // Returns the vertical overlap (by median) of this and other.
00374   // WARNING! Only makes sense on horizontal partitions!
00375   int VCoreOverlap(const ColPartition& other) const {
00376     return MIN(median_top_, other.median_top_) -
00377            MAX(median_bottom_, other.median_bottom_);
00378   }
00379   // Returns the horizontal overlap (by median) of this and other.
00380   // WARNING! Only makes sense on vertical partitions!
00381   int HCoreOverlap(const ColPartition& other) const {
00382     return MIN(median_right_, other.median_right_) -
00383            MAX(median_left_, other.median_left_);
00384   }
00385   // Returns true if this and other overlap significantly vertically.
00386   // WARNING! Only makes sense on horizontal partitions!
00387   bool VSignificantCoreOverlap(const ColPartition& other) const {
00388     int overlap = VCoreOverlap(other);
00389     int height = MIN(median_top_ - median_bottom_,
00390                      other.median_top_ - other.median_bottom_);
00391     return overlap * 3 > height;
00392   }
00393   // Returns true if this and other can be combined without putting a
00394   // horizontal step in either left or right edge of the resulting block.
00395   bool WithinSameMargins(const ColPartition& other) const {
00396     return left_margin_ <= other.bounding_box_.left() &&
00397            bounding_box_.left() >= other.left_margin_ &&
00398            bounding_box_.right() <= other.right_margin_ &&
00399            right_margin_ >= other.bounding_box_.right();
00400   }
00401   // Returns true if the region types (aligned_text_) match.
00402   // Lines never match anything, as they should never be merged or chained.
00403   bool TypesMatch(const ColPartition& other) const {
00404     return TypesMatch(blob_type_, other.blob_type_);
00405   }
00406   static bool TypesMatch(BlobRegionType type1, BlobRegionType type2) {
00407     return (type1 == type2 || type1 == BRT_UNKNOWN || type2 == BRT_UNKNOWN) &&
00408            !BLOBNBOX::IsLineType(type1) && !BLOBNBOX::IsLineType(type2);
00409   }
00410 
00411   // Returns true if the types are similar to each other.
00412   static bool TypesSimilar(PolyBlockType type1, PolyBlockType type2) {
00413     return (type1 == type2 ||
00414             (type1 == PT_FLOWING_TEXT && type2 == PT_INLINE_EQUATION) ||
00415             (type2 == PT_FLOWING_TEXT && type1 == PT_INLINE_EQUATION));
00416   }
00417 
00418   // Returns true if partitions is of horizontal line type
00419   bool IsLineType() const {
00420     return PTIsLineType(type_);
00421   }
00422   // Returns true if partitions is of image type
00423   bool IsImageType() const {
00424     return PTIsImageType(type_);
00425   }
00426   // Returns true if partitions is of text type
00427   bool IsTextType() const {
00428     return PTIsTextType(type_);
00429   }
00430   // Returns true if the partition is of an exclusively vertical type.
00431   bool IsVerticalType() const {
00432     return blob_type_ == BRT_VERT_TEXT || blob_type_ == BRT_VLINE;
00433   }
00434   // Returns true if the partition is of a definite horizontal type.
00435   bool IsHorizontalType() const {
00436     return blob_type_ == BRT_TEXT || blob_type_ == BRT_HLINE;
00437   }
00438   // Returns true is the partition is of a type that cannot be merged.
00439   bool IsUnMergeableType() const {
00440     return BLOBNBOX::UnMergeableType(blob_type_) || type_ == PT_NOISE;
00441   }
00442   // Returns true if this partition is a vertical line
00443   // TODO(nbeato): Use PartitionType enum when Ray's code is submitted.
00444   bool IsVerticalLine() const {
00445     return IsVerticalType() && IsLineType();
00446   }
00447   // Returns true if this partition is a horizontal line
00448   // TODO(nbeato): Use PartitionType enum when Ray's code is submitted.
00449   bool IsHorizontalLine() const {
00450     return IsHorizontalType() && IsLineType();
00451   }
00452 
00453   // Adds the given box to the partition, updating the partition bounds.
00454   // The list of boxes in the partition is updated, ensuring that no box is
00455   // recorded twice, and the boxes are kept in increasing left position.
00456   void AddBox(BLOBNBOX* box);
00457 
00458   // Removes the given box from the partition, updating the bounds.
00459   void RemoveBox(BLOBNBOX* box);
00460 
00461   // Returns the tallest box in the partition, as measured perpendicular to the
00462   // presumed flow of text.
00463   BLOBNBOX* BiggestBox();
00464 
00465   // Returns the bounding box excluding the given box.
00466   TBOX BoundsWithoutBox(BLOBNBOX* box);
00467 
00468   // Claims the boxes in the boxes_list by marking them with a this owner
00469   // pointer.
00470   void ClaimBoxes();
00471 
00472   // NULL the owner of the blobs in this partition, so they can be deleted
00473   // independently of the ColPartition.
00474   void DisownBoxes();
00475 
00476   // Delete the boxes that this partition owns.
00477   void DeleteBoxes();
00478 
00479   // Reflects the partition in the y-axis, assuming that its blobs have
00480   // already been done. Corrects only a limited part of the members, since
00481   // this function is assumed to be used shortly after initial creation, which
00482   // is before a lot of the members are used.
00483   void ReflectInYAxis();
00484 
00485   // Returns true if this is a legal partition - meaning that the conditions
00486   // left_margin <= bounding_box left
00487   // left_key <= bounding box left key
00488   // bounding box left <= bounding box right
00489   // and likewise for right margin and key
00490   // are all met.
00491   bool IsLegal();
00492 
00493   // Returns true if the left and right edges are approximately equal.
00494   bool MatchingColumns(const ColPartition& other) const;
00495 
00496   // Returns true if the colors match for two text partitions.
00497   bool MatchingTextColor(const ColPartition& other) const;
00498 
00499   // Returns true if the sizes match for two text partitions,
00500   // taking orientation into account
00501   bool MatchingSizes(const ColPartition& other) const;
00502 
00503   // Returns true if there is no tabstop violation in merging this and other.
00504   bool ConfirmNoTabViolation(const ColPartition& other) const;
00505 
00506   // Returns true if other has a similar stroke width to this.
00507   bool MatchingStrokeWidth(const ColPartition& other,
00508                            double fractional_tolerance,
00509                            double constant_tolerance) const;
00510   // Returns true if candidate is an acceptable diacritic base char merge
00511   // with this as the diacritic.
00512   bool OKDiacriticMerge(const ColPartition& candidate, bool debug) const;
00513 
00514   // Sets the sort key using either the tab vector, or the bounding box if
00515   // the tab vector is NULL. If the tab_vector lies inside the bounding_box,
00516   // use the edge of the box as a key any way.
00517   void SetLeftTab(const TabVector* tab_vector);
00518   void SetRightTab(const TabVector* tab_vector);
00519 
00520   // Copies the left/right tab from the src partition, but if take_box is
00521   // true, copies the box instead and uses that as a key.
00522   void CopyLeftTab(const ColPartition& src, bool take_box);
00523   void CopyRightTab(const ColPartition& src, bool take_box);
00524 
00525   // Returns the left rule line x coord of the leftmost blob.
00526   int LeftBlobRule() const;
00527   // Returns the right rule line x coord of the rightmost blob.
00528   int RightBlobRule() const;
00529 
00530   // Returns the density value for a particular BlobSpecialTextType.
00531   float SpecialBlobsDensity(const BlobSpecialTextType type) const;
00532   // Returns the number of blobs for a  particular BlobSpecialTextType.
00533   int SpecialBlobsCount(const BlobSpecialTextType type);
00534   // Set the density value for a particular BlobSpecialTextType, should ONLY be
00535   // used for debugging or testing. In production code, use
00536   // ComputeSpecialBlobsDensity instead.
00537   void SetSpecialBlobsDensity(
00538       const BlobSpecialTextType type, const float density);
00539   // Compute the SpecialTextType density of blobs, where we assume
00540   // that the SpecialTextType in the boxes_ has been set.
00541   void ComputeSpecialBlobsDensity();
00542 
00543   // Add a partner above if upper, otherwise below.
00544   // Add them uniquely and keep the list sorted by box left.
00545   // Partnerships are added symmetrically to partner and this.
00546   void AddPartner(bool upper, ColPartition* partner);
00547   // Removes the partner from this, but does not remove this from partner.
00548   // This asymmetric removal is so as not to mess up the iterator that is
00549   // working on partner's partner list.
00550   void RemovePartner(bool upper, ColPartition* partner);
00551   // Returns the partner if the given partner is a singleton, otherwise NULL.
00552   ColPartition* SingletonPartner(bool upper);
00553 
00554   // Merge with the other partition and delete it.
00555   void Absorb(ColPartition* other, WidthCallback* cb);
00556 
00557   // Returns true if the overlap between this and the merged pair of
00558   // merge candidates is sufficiently trivial to be allowed.
00559   // The merged box can graze the edge of this by the ok_box_overlap
00560   // if that exceeds the margin to the median top and bottom.
00561   bool OKMergeOverlap(const ColPartition& merge1, const ColPartition& merge2,
00562                       int ok_box_overlap, bool debug);
00563 
00564   // Find the blob at which to split this to minimize the overlap with the
00565   // given box. Returns the first blob to go in the second partition.
00566   BLOBNBOX* OverlapSplitBlob(const TBOX& box);
00567 
00568   // Split this partition keeping the first half in this and returning
00569   // the second half.
00570   // Splits by putting the split_blob and the blobs that follow
00571   // in the second half, and the rest in the first half.
00572   ColPartition* SplitAtBlob(BLOBNBOX* split_blob);
00573 
00574   // Splits this partition at the given x coordinate, returning the right
00575   // half and keeping the left half in this.
00576   ColPartition* SplitAt(int split_x);
00577 
00578   // Recalculates all the coordinate limits of the partition.
00579   void ComputeLimits();
00580 
00581   // Returns the number of boxes that overlap the given box.
00582   int CountOverlappingBoxes(const TBOX& box);
00583 
00584   // Computes and sets the type_, first_column_, last_column_ and column_set_.
00585   // resolution refers to the ppi resolution of the image.
00586   void SetPartitionType(int resolution, ColPartitionSet* columns);
00587 
00588   // Returns the PartitionType from the current BlobRegionType and a column
00589   // flow spanning type ColumnSpanningType, generated by
00590   // ColPartitionSet::SpanningType, that indicates how the partition sits
00591   // in the columns.
00592   PolyBlockType PartitionType(ColumnSpanningType flow) const;
00593 
00594   // Returns the first and last column touched by this partition.
00595   // resolution refers to the ppi resolution of the image.
00596   void ColumnRange(int resolution, ColPartitionSet* columns,
00597                    int* first_col, int* last_col);
00598 
00599   // Sets the internal flags good_width_ and good_column_.
00600   void SetColumnGoodness(WidthCallback* cb);
00601 
00602   // Determines whether the blobs in this partition mostly represent
00603   // a leader (fixed pitch sequence) and sets the member blobs accordingly.
00604   // Note that height is assumed to have been tested elsewhere, and that this
00605   // function will find most fixed-pitch text as leader without a height filter.
00606   // Leader detection is limited to sequences of identical width objects,
00607   // such as .... or ----, so patterns, such as .-.-.-.-. will not be found.
00608   bool MarkAsLeaderIfMonospaced();
00609   // Given the result of TextlineProjection::EvaluateColPartition, (positive for
00610   // horizontal text, negative for vertical text, and near zero for non-text),
00611   // sets the blob_type_ and flow_ for this partition to indicate whether it
00612   // is strongly or weakly vertical or horizontal text, or non-text.
00613   void SetRegionAndFlowTypesFromProjectionValue(int value);
00614 
00615   // Sets all blobs with the partition blob type and flow, but never overwrite
00616   // leader blobs, as we need to be able to identify them later.
00617   void SetBlobTypes();
00618 
00619   // Returns true if a decent baseline can be fitted through the blobs.
00620   // Works for both horizontal and vertical text.
00621   bool HasGoodBaseline();
00622 
00623   // Adds this ColPartition to a matching WorkingPartSet if one can be found,
00624   // otherwise starts a new one in the appropriate column, ending the previous.
00625   void AddToWorkingSet(const ICOORD& bleft, const ICOORD& tright,
00626                        int resolution, ColPartition_LIST* used_parts,
00627                        WorkingPartSet_LIST* working_set);
00628 
00629   // From the given block_parts list, builds one or more BLOCKs and
00630   // corresponding TO_BLOCKs, such that the line spacing is uniform in each.
00631   // Created blocks are appended to the end of completed_blocks and to_blocks.
00632   // The used partitions are put onto used_parts, as they may still be referred
00633   // to in the partition grid. bleft, tright and resolution are the bounds
00634   // and resolution of the original image.
00635   static void LineSpacingBlocks(const ICOORD& bleft, const ICOORD& tright,
00636                                 int resolution,
00637                                 ColPartition_LIST* block_parts,
00638                                 ColPartition_LIST* used_parts,
00639                                 BLOCK_LIST* completed_blocks,
00640                                 TO_BLOCK_LIST* to_blocks);
00641   // Constructs a block from the given list of partitions.
00642   // Arguments are as LineSpacingBlocks above.
00643   static TO_BLOCK* MakeBlock(const ICOORD& bleft, const ICOORD& tright,
00644                              ColPartition_LIST* block_parts,
00645                              ColPartition_LIST* used_parts);
00646 
00647   // Constructs a block from the given list of vertical text partitions.
00648   // Currently only creates rectangular blocks.
00649   static TO_BLOCK* MakeVerticalTextBlock(const ICOORD& bleft,
00650                                          const ICOORD& tright,
00651                                          ColPartition_LIST* block_parts,
00652                                          ColPartition_LIST* used_parts);
00653 
00654 
00655   // Returns a copy of everything except the list of boxes. The resulting
00656   // ColPartition is only suitable for keeping in a column candidate list.
00657   ColPartition* ShallowCopy() const;
00658   // Returns a copy of everything with a shallow copy of the blobs.
00659   // The blobs are still owned by their original parent, so they are
00660   // treated as read-only.
00661   ColPartition* CopyButDontOwnBlobs();
00662 
00663   // Provides a color for BBGrid to draw the rectangle.
00664   ScrollView::Color  BoxColor() const;
00665 
00666   // Prints debug information on this.
00667   void Print() const;
00668   // Prints debug information on the colors.
00669   void PrintColors();
00670 
00671   // Sets the types of all partitions in the run to be the max of the types.
00672   void SmoothPartnerRun(int working_set_count);
00673 
00674   // Cleans up the partners of the given type so that there is at most
00675   // one partner. This makes block creation simpler.
00676   // If get_desperate is true, goes to more desperate merge methods
00677   // to merge flowing text before breaking partnerships.
00678   void RefinePartners(PolyBlockType type, bool get_desparate,
00679                       ColPartitionGrid* grid);
00680 
00681   // Returns true if this column partition is in the same column as
00682   // part. This function will only work after the SetPartitionType function
00683   // has been called on both column partitions. This is useful for
00684   // doing a SideSearch when you want things in the same page column.
00685   bool IsInSameColumnAs(const ColPartition& part) const;
00686 
00687   // Sets the column bounds. Primarily used in testing.
00688   void set_first_column(int column) {
00689     first_column_ = column;
00690   }
00691   void set_last_column(int column) {
00692     last_column_ = column;
00693   }
00694 
00695  private:
00696   // enum to refer to the entries in a neigbourhood of lines.
00697   // Used by SmoothSpacings to test for blips with OKSpacingBlip.
00698   enum SpacingNeighbourhood {
00699     PN_ABOVE2,
00700     PN_ABOVE1,
00701     PN_UPPER,
00702     PN_LOWER,
00703     PN_BELOW1,
00704     PN_BELOW2,
00705     PN_COUNT
00706   };
00707 
00708   // Cleans up the partners above if upper is true, else below.
00709   // If get_desperate is true, goes to more desperate merge methods
00710   // to merge flowing text before breaking partnerships.
00711   void RefinePartnersInternal(bool upper, bool get_desperate,
00712                               ColPartitionGrid* grid);
00713   // Restricts the partners to only desirable types. For text and BRT_HLINE this
00714   // means the same type_ , and for image types it means any image type.
00715   void RefinePartnersByType(bool upper, ColPartition_CLIST* partners);
00716   // Remove transitive partnerships: this<->a, and a<->b and this<->b.
00717   // Gets rid of this<->b, leaving a clean chain.
00718   // Also if we have this<->a and a<->this, then gets rid of this<->a, as
00719   // this has multiple partners.
00720   void RefinePartnerShortcuts(bool upper, ColPartition_CLIST* partners);
00721   // If multiple text partners can be merged, then do so.
00722   // If desperate is true, then an increase in overlap with the merge is
00723   // allowed. If the overlap increases, then the desperately_merged_ flag
00724   // is set, indicating that the textlines probably need to be regenerated
00725   // by aggressive line fitting/splitting, as there are probably vertically
00726   // joined blobs that cross textlines.
00727   void RefineTextPartnersByMerge(bool upper, bool desperate,
00728                                  ColPartition_CLIST* partners,
00729                                  ColPartitionGrid* grid);
00730   // Keep the partner with the biggest overlap.
00731   void RefinePartnersByOverlap(bool upper, ColPartition_CLIST* partners);
00732 
00733   // Return true if bbox belongs better in this than other.
00734   bool ThisPartitionBetter(BLOBNBOX* bbox, const ColPartition& other);
00735 
00736   // Smoothes the spacings in the list into groups of equal linespacing.
00737   // resolution is the resolution of the original image, used as a basis
00738   // for thresholds in change of spacing. page_height is in pixels.
00739   static void SmoothSpacings(int resolution, int page_height,
00740                              ColPartition_LIST* parts);
00741 
00742   // Returns true if the parts array of pointers to partitions matches the
00743   // condition for a spacing blip. See SmoothSpacings for what this means
00744   // and how it is used.
00745   static bool OKSpacingBlip(int resolution, int median_spacing,
00746                             ColPartition** parts);
00747 
00748   // Returns true if both the top and bottom spacings of this match the given
00749   // spacing to within suitable margins dictated by the image resolution.
00750   bool SpacingEqual(int spacing, int resolution) const;
00751 
00752   // Returns true if both the top and bottom spacings of this and other
00753   // match to within suitable margins dictated by the image resolution.
00754   bool SpacingsEqual(const ColPartition& other, int resolution) const;
00755 
00756   // Returns true if the sum spacing of this and other match the given
00757   // spacing (or twice the given spacing) to within a suitable margin dictated
00758   // by the image resolution.
00759   bool SummedSpacingOK(const ColPartition& other,
00760                        int spacing, int resolution) const;
00761 
00762   // Returns a suitable spacing margin that can be applied to bottoms of
00763   // text lines, based on the resolution and the stored side_step_.
00764   int BottomSpacingMargin(int resolution) const;
00765 
00766   // Returns a suitable spacing margin that can be applied to tops of
00767   // text lines, based on the resolution and the stored side_step_.
00768   int TopSpacingMargin(int resolution) const;
00769 
00770   // Returns true if the median text sizes of this and other agree to within
00771   // a reasonable multiplicative factor.
00772   bool SizesSimilar(const ColPartition& other) const;
00773 
00774   // Computes and returns in start, end a line segment formed from a
00775   // forwards-iterated group of left edges of partitions that satisfy the
00776   // condition that the rightmost left margin is to the left of the
00777   // leftmost left bounding box edge.
00778   // TODO(rays) Not good enough. Needs improving to tightly wrap text in both
00779   // directions, and to loosely wrap images.
00780   static void LeftEdgeRun(ColPartition_IT* part_it,
00781                           ICOORD* start, ICOORD* end);
00782   // Computes and returns in start, end a line segment formed from a
00783   // backwards-iterated group of right edges of partitions that satisfy the
00784   // condition that the leftmost right margin is to the right of the
00785   // rightmost right bounding box edge.
00786   // TODO(rays) Not good enough. Needs improving to tightly wrap text in both
00787   // directions, and to loosely wrap images.
00788   static void RightEdgeRun(ColPartition_IT* part_it,
00789                            ICOORD* start, ICOORD* end);
00790 
00791   // The margins are determined by the position of the nearest vertically
00792   // overlapping neighbour to the side. They indicate the maximum extent
00793   // that the block/column may be extended without touching something else.
00794   // Leftmost coordinate that the region may occupy over the y limits.
00795   int left_margin_;
00796   // Rightmost coordinate that the region may occupy over the y limits.
00797   int right_margin_;
00798   // Bounding box of all blobs in the partition.
00799   TBOX bounding_box_;
00800   // Median top and bottom of blobs in this partition.
00801   int median_bottom_;
00802   int median_top_;
00803   // Median height of blobs in this partition.
00804   // TODO(rays) rename median_height_.
00805   int median_size_;
00806   // Median left and right of blobs in this partition.
00807   int median_left_;
00808   int median_right_;
00809   // Median width of blobs in this partition.
00810   int median_width_;
00811   // blob_region_type_ for the blobs in this partition.
00812   BlobRegionType blob_type_;
00813   BlobTextFlowType flow_;  // Quality of text flow.
00814   // Total of GoodTextBlob results for all blobs in the partition.
00815   int good_blob_score_;
00816   // True if this partition has a common width.
00817   bool good_width_;
00818   // True if this is a good column candidate.
00819   bool good_column_;
00820   // True if the left_key_ is from a tab vector.
00821   bool left_key_tab_;
00822   // True if the right_key_ is from a tab vector.
00823   bool right_key_tab_;
00824   // Left and right sort keys for the edges of the partition.
00825   // If the respective *_key_tab_ is true then this key came from a tab vector.
00826   // If not, then the class promises to keep the key equal to the sort key
00827   // for the respective edge of the bounding box at the MidY, so that
00828   // LeftAtY and RightAtY always returns an x coordinate on the line parallel
00829   // to vertical_ through the bounding box edge at MidY.
00830   int left_key_;
00831   int right_key_;
00832   // Type of this partition after looking at its relation to the columns.
00833   PolyBlockType type_;
00834   // All boxes in the partition stored in increasing left edge coordinate.
00835   BLOBNBOX_CLIST boxes_;
00836   // The global vertical skew direction.
00837   ICOORD vertical_;
00838   // The partitions above that matched this.
00839   ColPartition_CLIST upper_partners_;
00840   // The partitions below that matched this.
00841   ColPartition_CLIST lower_partners_;
00842   // The WorkingPartSet it lives in while blocks are being made.
00843   WorkingPartSet* working_set_;
00844   // Flag is true when AddBox is sorting vertically, false otherwise.
00845   bool last_add_was_vertical_;
00846   // True when the partition's ownership has been taken from the grid and
00847   // placed in a working set, or, after that, in the good_parts_ list.
00848   bool block_owned_;
00849   // Flag to indicate that this partition was subjected to a desperate merge,
00850   // and therefore the textlines need rebuilding.
00851   bool desperately_merged_;
00852   // The first and last column that this partition applies to.
00853   // Flowing partitions (see type_) will have an equal first and last value
00854   // of the form 2n + 1, where n is the zero-based index into the partitions
00855   // in column_set_. (See ColPartitionSet::GetColumnByIndex).
00856   // Heading partitions will have unequal values of the same form.
00857   // Pullout partitions will have equal values, but may have even values,
00858   // indicating placement between columns.
00859   int first_column_;
00860   int last_column_;
00861   // Column_set_ is the column layout applicable to this ColPartition.
00862   ColPartitionSet* column_set_;
00863   // Linespacing data.
00864   int side_step_;       // Median y-shift to next blob on same line.
00865   int top_spacing_;     // Line spacing from median_top_.
00866   int bottom_spacing_;  // Line spacing from median_bottom_.
00867 
00868   // Type of this partition before considering it as a table cell. This is
00869   // used to revert the type if a partition is first marked as a table cell but
00870   // later filtering steps decide it does not belong to a table
00871   PolyBlockType type_before_table_;
00872   bool inside_table_column_;  // Check whether the current partition has been
00873                               // assigned to a table column
00874   // Nearest neighbor above with major x-overlap
00875   ColPartition* nearest_neighbor_above_;
00876   // Nearest neighbor below with major x-overlap
00877   ColPartition* nearest_neighbor_below_;
00878   int space_above_;      // Distance from nearest_neighbor_above
00879   int space_below_;      // Distance from nearest_neighbor_below
00880   int space_to_left_;    // Distance from the left edge of the column
00881   int space_to_right_;   // Distance from the right edge of the column
00882   // Color foreground/background data.
00883   uinT8 color1_[kRGBRMSColors];
00884   uinT8 color2_[kRGBRMSColors];
00885   bool owns_blobs_;  // Does the partition own its blobs?
00886   // The density of special blobs.
00887   float special_blobs_densities_[BSTT_COUNT];
00888 };
00889 
00890 // Typedef it now in case it becomes a class later.
00891 typedef GridSearch<ColPartition,
00892                    ColPartition_CLIST,
00893                    ColPartition_C_IT> ColPartitionGridSearch;
00894 
00895 }  // namespace tesseract.
00896 
00897 #endif  // TESSERACT_TEXTORD_COLPARTITION_H__