tesseract  4.00.00dev
colpartition.h
Go to the documentation of this file.
1 // File: colpartition.h
3 // Description: Class to hold partitions of the page that correspond
4 // roughly to text lines.
5 // Author: Ray Smith
6 // Created: Thu Aug 14 10:50:01 PDT 2008
7 //
8 // (C) Copyright 2008, Google Inc.
9 // Licensed under the Apache License, Version 2.0 (the "License");
10 // you may not use this file except in compliance with the License.
11 // You may obtain a copy of the License at
12 // http://www.apache.org/licenses/LICENSE-2.0
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
20 
21 #ifndef TESSERACT_TEXTORD_COLPARTITION_H_
22 #define TESSERACT_TEXTORD_COLPARTITION_H_
23 
24 #include "bbgrid.h"
25 #include "blobbox.h" // For BlobRegionType.
26 #include "ndminx.h"
27 #include "ocrblock.h"
28 #include "rect.h" // For TBOX.
29 #include "scrollview.h"
30 #include "tabfind.h" // For WidthCallback.
31 #include "tabvector.h" // For BLOBNBOX_CLIST.
32 
33 namespace tesseract {
34 
35 // Number of colors in the color1, color2 arrays.
36 const int kRGBRMSColors = 4;
37 
38 class ColPartition;
39 class ColPartitionSet;
40 class ColPartitionGrid;
41 class WorkingPartSet;
42 class WorkingPartSet_LIST;
43 
44 // An enum to indicate how a partition sits on the columns.
45 // The order of flowing/heading/pullout must be kept consistent with
46 // PolyBlockType.
48  CST_NOISE, // Strictly between columns.
49  CST_FLOWING, // Strictly within a single column.
50  CST_HEADING, // Spans multiple columns.
51  CST_PULLOUT, // Touches multiple columns, but doesn't span them.
52  CST_COUNT // Number of entries.
53 };
54 
57 
58 
67 class ColPartition : public ELIST2_LINK {
68  public:
70  // This empty constructor is here only so that the class can be ELISTIZED.
71  // TODO(rays) change deep_copy in elst.h line 955 to take a callback copier
72  // and eliminate CLASSNAME##_copier.
73  }
78  ColPartition(BlobRegionType blob_type, const ICOORD& vertical);
83  static ColPartition* MakeLinePartition(BlobRegionType blob_type,
84  const ICOORD& vertical,
85  int left, int bottom,
86  int right, int top);
87 
88  // Constructs and returns a fake ColPartition with a single fake BLOBNBOX,
89  // all made from a single TBOX.
90  // WARNING: Despite being on C_LISTs, the BLOBNBOX owns the C_BLOB and
91  // the ColPartition owns the BLOBNBOX!!!
92  // Call DeleteBoxes before deleting the ColPartition.
93  static ColPartition* FakePartition(const TBOX& box,
94  PolyBlockType block_type,
95  BlobRegionType blob_type,
96  BlobTextFlowType flow);
97 
98  // Constructs and returns a ColPartition with the given real BLOBNBOX,
99  // and sets it up to be a "big" partition (single-blob partition bigger
100  // than the surrounding text that may be a dropcap, two or more vertically
101  // touching characters, or some graphic element.
102  // If the given list is not NULL, the partition is also added to the list.
103  static ColPartition* MakeBigPartition(BLOBNBOX* box,
104  ColPartition_LIST* big_part_list);
105 
106  ~ColPartition();
107 
108  // Simple accessors.
109  const TBOX& bounding_box() const {
110  return bounding_box_;
111  }
112  int left_margin() const {
113  return left_margin_;
114  }
115  void set_left_margin(int margin) {
116  left_margin_ = margin;
117  }
118  int right_margin() const {
119  return right_margin_;
120  }
121  void set_right_margin(int margin) {
122  right_margin_ = margin;
123  }
124  int median_top() const {
125  return median_top_;
126  }
127  int median_bottom() const {
128  return median_bottom_;
129  }
130  int median_left() const {
131  return median_left_;
132  }
133  int median_right() const {
134  return median_right_;
135  }
136  int median_size() const {
137  return median_size_;
138  }
139  void set_median_size(int size) {
140  median_size_ = size;
141  }
142  int median_width() const {
143  return median_width_;
144  }
145  void set_median_width(int width) {
146  median_width_ = width;
147  }
149  return blob_type_;
150  }
152  blob_type_ = t;
153  }
155  return flow_;
156  }
158  flow_ = f;
159  }
160  int good_blob_score() const {
161  return good_blob_score_;
162  }
163  bool good_width() const {
164  return good_width_;
165  }
166  bool good_column() const {
167  return good_column_;
168  }
169  bool left_key_tab() const {
170  return left_key_tab_;
171  }
172  int left_key() const {
173  return left_key_;
174  }
175  bool right_key_tab() const {
176  return right_key_tab_;
177  }
178  int right_key() const {
179  return right_key_;
180  }
181  PolyBlockType type() const {
182  return type_;
183  }
185  type_ = t;
186  }
187  BLOBNBOX_CLIST* boxes() {
188  return &boxes_;
189  }
190  int boxes_count() const {
191  return boxes_.length();
192  }
193  void set_vertical(const ICOORD& v) {
194  vertical_ = v;
195  }
196  ColPartition_CLIST* upper_partners() {
197  return &upper_partners_;
198  }
199  ColPartition_CLIST* lower_partners() {
200  return &lower_partners_;
201  }
202  void set_working_set(WorkingPartSet* working_set) {
203  working_set_ = working_set;
204  }
205  bool block_owned() const {
206  return block_owned_;
207  }
208  void set_block_owned(bool owned) {
209  block_owned_ = owned;
210  }
211  bool desperately_merged() const {
212  return desperately_merged_;
213  }
215  return column_set_;
216  }
217  void set_side_step(int step) {
218  side_step_ = step;
219  }
220  int bottom_spacing() const {
221  return bottom_spacing_;
222  }
223  void set_bottom_spacing(int spacing) {
224  bottom_spacing_ = spacing;
225  }
226  int top_spacing() const {
227  return top_spacing_;
228  }
229  void set_top_spacing(int spacing) {
230  top_spacing_ = spacing;
231  }
232 
233  void set_table_type() {
234  if (type_ != PT_TABLE) {
235  type_before_table_ = type_;
236  type_ = PT_TABLE;
237  }
238  }
240  if (type_ == PT_TABLE)
241  type_ = type_before_table_;
242  }
244  return inside_table_column_;
245  }
246  void set_inside_table_column(bool val) {
247  inside_table_column_ = val;
248  }
250  return nearest_neighbor_above_;
251  }
253  nearest_neighbor_above_ = part;
254  }
256  return nearest_neighbor_below_;
257  }
259  nearest_neighbor_below_ = part;
260  }
261  int space_above() const {
262  return space_above_;
263  }
264  void set_space_above(int space) {
265  space_above_ = space;
266  }
267  int space_below() const {
268  return space_below_;
269  }
270  void set_space_below(int space) {
271  space_below_ = space;
272  }
273  int space_to_left() const {
274  return space_to_left_;
275  }
276  void set_space_to_left(int space) {
277  space_to_left_ = space;
278  }
279  int space_to_right() const {
280  return space_to_right_;
281  }
282  void set_space_to_right(int space) {
283  space_to_right_ = space;
284  }
286  return color1_;
287  }
289  return color2_;
290  }
291  bool owns_blobs() const {
292  return owns_blobs_;
293  }
294  void set_owns_blobs(bool owns_blobs) {
295  // Do NOT change ownership flag when there are blobs in the list.
296  // Immediately set the ownership flag when creating copies.
297  ASSERT_HOST(boxes_.empty());
298  owns_blobs_ = owns_blobs;
299  }
300 
301  // Inline quasi-accessors that require some computation.
302 
303  // Returns the middle y-coord of the bounding box.
304  int MidY() const {
305  return (bounding_box_.top() + bounding_box_.bottom()) / 2;
306  }
307  // Returns the middle y-coord of the median top and bottom.
308  int MedianY() const {
309  return (median_top_ + median_bottom_) / 2;
310  }
311  // Returns the middle x-coord of the bounding box.
312  int MidX() const {
313  return (bounding_box_.left() + bounding_box_.right()) / 2;
314  }
315  // Returns the sort key at any given x,y.
316  int SortKey(int x, int y) const {
317  return TabVector::SortKey(vertical_, x, y);
318  }
319  // Returns the x corresponding to the sortkey, y pair.
320  int XAtY(int sort_key, int y) const {
321  return TabVector::XAtY(vertical_, sort_key, y);
322  }
323  // Returns the x difference between the two sort keys.
324  int KeyWidth(int left_key, int right_key) const {
325  return (right_key - left_key) / vertical_.y();
326  }
327  // Returns the column width between the left and right keys.
328  int ColumnWidth() const {
329  return KeyWidth(left_key_, right_key_);
330  }
331  // Returns the sort key of the box left edge.
332  int BoxLeftKey() const {
333  return SortKey(bounding_box_.left(), MidY());
334  }
335  // Returns the sort key of the box right edge.
336  int BoxRightKey() const {
337  return SortKey(bounding_box_.right(), MidY());
338  }
339  // Returns the left edge at the given y, using the sort key.
340  int LeftAtY(int y) const {
341  return XAtY(left_key_, y);
342  }
343  // Returns the right edge at the given y, using the sort key.
344  int RightAtY(int y) const {
345  return XAtY(right_key_, y);
346  }
347  // Returns true if the right edge of this is to the left of the right
348  // edge of other.
349  bool IsLeftOf(const ColPartition& other) const {
350  return bounding_box_.right() < other.bounding_box_.right();
351  }
352  // Returns true if the partition contains the given x coordinate at the y.
353  bool ColumnContains(int x, int y) const {
354  return LeftAtY(y) - 1 <= x && x <= RightAtY(y) + 1;
355  }
356  // Returns true if there are no blobs in the list.
357  bool IsEmpty() const {
358  return boxes_.empty();
359  }
360  // Returns true if there is a single blob in the list.
361  bool IsSingleton() const {
362  return boxes_.singleton();
363  }
364  // Returns true if this and other overlap horizontally by bounding box.
365  bool HOverlaps(const ColPartition& other) const {
366  return bounding_box_.x_overlap(other.bounding_box_);
367  }
368  // Returns true if this and other's bounding boxes overlap vertically.
369  // TODO(rays) Make HOverlaps and VOverlaps truly symmetric.
370  bool VOverlaps(const ColPartition& other) const {
371  return bounding_box_.y_gap(other.bounding_box_) < 0;
372  }
373  // Returns the vertical overlap (by median) of this and other.
374  // WARNING! Only makes sense on horizontal partitions!
375  int VCoreOverlap(const ColPartition& other) const {
376  return MIN(median_top_, other.median_top_) -
377  MAX(median_bottom_, other.median_bottom_);
378  }
379  // Returns the horizontal overlap (by median) of this and other.
380  // WARNING! Only makes sense on vertical partitions!
381  int HCoreOverlap(const ColPartition& other) const {
382  return MIN(median_right_, other.median_right_) -
383  MAX(median_left_, other.median_left_);
384  }
385  // Returns true if this and other overlap significantly vertically.
386  // WARNING! Only makes sense on horizontal partitions!
387  bool VSignificantCoreOverlap(const ColPartition& other) const {
388  int overlap = VCoreOverlap(other);
389  int height = MIN(median_top_ - median_bottom_,
390  other.median_top_ - other.median_bottom_);
391  return overlap * 3 > height;
392  }
393  // Returns true if this and other can be combined without putting a
394  // horizontal step in either left or right edge of the resulting block.
395  bool WithinSameMargins(const ColPartition& other) const {
396  return left_margin_ <= other.bounding_box_.left() &&
397  bounding_box_.left() >= other.left_margin_ &&
398  bounding_box_.right() <= other.right_margin_ &&
399  right_margin_ >= other.bounding_box_.right();
400  }
401  // Returns true if the region types (aligned_text_) match.
402  // Lines never match anything, as they should never be merged or chained.
403  bool TypesMatch(const ColPartition& other) const {
404  return TypesMatch(blob_type_, other.blob_type_);
405  }
406  static bool TypesMatch(BlobRegionType type1, BlobRegionType type2) {
407  return (type1 == type2 || type1 == BRT_UNKNOWN || type2 == BRT_UNKNOWN) &&
408  !BLOBNBOX::IsLineType(type1) && !BLOBNBOX::IsLineType(type2);
409  }
410 
411  // Returns true if the types are similar to each other.
412  static bool TypesSimilar(PolyBlockType type1, PolyBlockType type2) {
413  return (type1 == type2 ||
414  (type1 == PT_FLOWING_TEXT && type2 == PT_INLINE_EQUATION) ||
415  (type2 == PT_FLOWING_TEXT && type1 == PT_INLINE_EQUATION));
416  }
417 
418  // Returns true if partitions is of horizontal line type
419  bool IsLineType() const {
420  return PTIsLineType(type_);
421  }
422  // Returns true if partitions is of image type
423  bool IsImageType() const {
424  return PTIsImageType(type_);
425  }
426  // Returns true if partitions is of text type
427  bool IsTextType() const {
428  return PTIsTextType(type_);
429  }
430  // Returns true if partitions is of pullout(inter-column) type
431  bool IsPulloutType() const {
432  return PTIsPulloutType(type_);
433  }
434  // Returns true if the partition is of an exclusively vertical type.
435  bool IsVerticalType() const {
436  return blob_type_ == BRT_VERT_TEXT || blob_type_ == BRT_VLINE;
437  }
438  // Returns true if the partition is of a definite horizontal type.
439  bool IsHorizontalType() const {
440  return blob_type_ == BRT_TEXT || blob_type_ == BRT_HLINE;
441  }
442  // Returns true is the partition is of a type that cannot be merged.
443  bool IsUnMergeableType() const {
444  return BLOBNBOX::UnMergeableType(blob_type_) || type_ == PT_NOISE;
445  }
446  // Returns true if this partition is a vertical line
447  // TODO(nbeato): Use PartitionType enum when Ray's code is submitted.
448  bool IsVerticalLine() const {
449  return IsVerticalType() && IsLineType();
450  }
451  // Returns true if this partition is a horizontal line
452  // TODO(nbeato): Use PartitionType enum when Ray's code is submitted.
453  bool IsHorizontalLine() const {
454  return IsHorizontalType() && IsLineType();
455  }
456 
457  // Adds the given box to the partition, updating the partition bounds.
458  // The list of boxes in the partition is updated, ensuring that no box is
459  // recorded twice, and the boxes are kept in increasing left position.
460  void AddBox(BLOBNBOX* box);
461 
462  // Removes the given box from the partition, updating the bounds.
463  void RemoveBox(BLOBNBOX* box);
464 
465  // Returns the tallest box in the partition, as measured perpendicular to the
466  // presumed flow of text.
467  BLOBNBOX* BiggestBox();
468 
469  // Returns the bounding box excluding the given box.
470  TBOX BoundsWithoutBox(BLOBNBOX* box);
471 
472  // Claims the boxes in the boxes_list by marking them with a this owner
473  // pointer.
474  void ClaimBoxes();
475 
476  // NULL the owner of the blobs in this partition, so they can be deleted
477  // independently of the ColPartition.
478  void DisownBoxes();
479  // NULL the owner of the blobs in this partition that are owned by this
480  // partition, so they can be deleted independently of the ColPartition.
481  // Any blobs that are not owned by this partition get to keep their owner
482  // without an assert failure.
483  void DisownBoxesNoAssert();
484  // NULLs the owner of the blobs in this partition that are owned by this
485  // partition and not leader blobs, removing them from the boxes_ list, thus
486  // turning this partition back to a leader partition if it contains a leader,
487  // or otherwise leaving it empty. Returns true if any boxes remain.
488  bool ReleaseNonLeaderBoxes();
489 
490  // Delete the boxes that this partition owns.
491  void DeleteBoxes();
492 
493  // Reflects the partition in the y-axis, assuming that its blobs have
494  // already been done. Corrects only a limited part of the members, since
495  // this function is assumed to be used shortly after initial creation, which
496  // is before a lot of the members are used.
497  void ReflectInYAxis();
498 
499  // Returns true if this is a legal partition - meaning that the conditions
500  // left_margin <= bounding_box left
501  // left_key <= bounding box left key
502  // bounding box left <= bounding box right
503  // and likewise for right margin and key
504  // are all met.
505  bool IsLegal();
506 
507  // Returns true if the left and right edges are approximately equal.
508  bool MatchingColumns(const ColPartition& other) const;
509 
510  // Returns true if the colors match for two text partitions.
511  bool MatchingTextColor(const ColPartition& other) const;
512 
513  // Returns true if the sizes match for two text partitions,
514  // taking orientation into account
515  bool MatchingSizes(const ColPartition& other) const;
516 
517  // Returns true if there is no tabstop violation in merging this and other.
518  bool ConfirmNoTabViolation(const ColPartition& other) const;
519 
520  // Returns true if other has a similar stroke width to this.
521  bool MatchingStrokeWidth(const ColPartition& other,
522  double fractional_tolerance,
523  double constant_tolerance) const;
524  // Returns true if candidate is an acceptable diacritic base char merge
525  // with this as the diacritic.
526  bool OKDiacriticMerge(const ColPartition& candidate, bool debug) const;
527 
528  // Sets the sort key using either the tab vector, or the bounding box if
529  // the tab vector is NULL. If the tab_vector lies inside the bounding_box,
530  // use the edge of the box as a key any way.
531  void SetLeftTab(const TabVector* tab_vector);
532  void SetRightTab(const TabVector* tab_vector);
533 
534  // Copies the left/right tab from the src partition, but if take_box is
535  // true, copies the box instead and uses that as a key.
536  void CopyLeftTab(const ColPartition& src, bool take_box);
537  void CopyRightTab(const ColPartition& src, bool take_box);
538 
539  // Returns the left rule line x coord of the leftmost blob.
540  int LeftBlobRule() const;
541  // Returns the right rule line x coord of the rightmost blob.
542  int RightBlobRule() const;
543 
544  // Returns the density value for a particular BlobSpecialTextType.
545  float SpecialBlobsDensity(const BlobSpecialTextType type) const;
546  // Returns the number of blobs for a particular BlobSpecialTextType.
547  int SpecialBlobsCount(const BlobSpecialTextType type);
548  // Set the density value for a particular BlobSpecialTextType, should ONLY be
549  // used for debugging or testing. In production code, use
550  // ComputeSpecialBlobsDensity instead.
551  void SetSpecialBlobsDensity(
552  const BlobSpecialTextType type, const float density);
553  // Compute the SpecialTextType density of blobs, where we assume
554  // that the SpecialTextType in the boxes_ has been set.
555  void ComputeSpecialBlobsDensity();
556 
557  // Add a partner above if upper, otherwise below.
558  // Add them uniquely and keep the list sorted by box left.
559  // Partnerships are added symmetrically to partner and this.
560  void AddPartner(bool upper, ColPartition* partner);
561  // Removes the partner from this, but does not remove this from partner.
562  // This asymmetric removal is so as not to mess up the iterator that is
563  // working on partner's partner list.
564  void RemovePartner(bool upper, ColPartition* partner);
565  // Returns the partner if the given partner is a singleton, otherwise NULL.
566  ColPartition* SingletonPartner(bool upper);
567 
568  // Merge with the other partition and delete it.
569  void Absorb(ColPartition* other, WidthCallback* cb);
570 
571  // Returns true if the overlap between this and the merged pair of
572  // merge candidates is sufficiently trivial to be allowed.
573  // The merged box can graze the edge of this by the ok_box_overlap
574  // if that exceeds the margin to the median top and bottom.
575  bool OKMergeOverlap(const ColPartition& merge1, const ColPartition& merge2,
576  int ok_box_overlap, bool debug);
577 
578  // Find the blob at which to split this to minimize the overlap with the
579  // given box. Returns the first blob to go in the second partition.
580  BLOBNBOX* OverlapSplitBlob(const TBOX& box);
581 
582  // Split this partition keeping the first half in this and returning
583  // the second half.
584  // Splits by putting the split_blob and the blobs that follow
585  // in the second half, and the rest in the first half.
586  ColPartition* SplitAtBlob(BLOBNBOX* split_blob);
587 
588  // Splits this partition at the given x coordinate, returning the right
589  // half and keeping the left half in this.
590  ColPartition* SplitAt(int split_x);
591 
592  // Recalculates all the coordinate limits of the partition.
593  void ComputeLimits();
594 
595  // Returns the number of boxes that overlap the given box.
596  int CountOverlappingBoxes(const TBOX& box);
597 
598  // Computes and sets the type_, first_column_, last_column_ and column_set_.
599  // resolution refers to the ppi resolution of the image.
600  void SetPartitionType(int resolution, ColPartitionSet* columns);
601 
602  // Returns the PartitionType from the current BlobRegionType and a column
603  // flow spanning type ColumnSpanningType, generated by
604  // ColPartitionSet::SpanningType, that indicates how the partition sits
605  // in the columns.
606  PolyBlockType PartitionType(ColumnSpanningType flow) const;
607 
608  // Returns the first and last column touched by this partition.
609  // resolution refers to the ppi resolution of the image.
610  void ColumnRange(int resolution, ColPartitionSet* columns,
611  int* first_col, int* last_col);
612 
613  // Sets the internal flags good_width_ and good_column_.
614  void SetColumnGoodness(WidthCallback* cb);
615 
616  // Determines whether the blobs in this partition mostly represent
617  // a leader (fixed pitch sequence) and sets the member blobs accordingly.
618  // Note that height is assumed to have been tested elsewhere, and that this
619  // function will find most fixed-pitch text as leader without a height filter.
620  // Leader detection is limited to sequences of identical width objects,
621  // such as .... or ----, so patterns, such as .-.-.-.-. will not be found.
622  bool MarkAsLeaderIfMonospaced();
623  // Given the result of TextlineProjection::EvaluateColPartition, (positive for
624  // horizontal text, negative for vertical text, and near zero for non-text),
625  // sets the blob_type_ and flow_ for this partition to indicate whether it
626  // is strongly or weakly vertical or horizontal text, or non-text.
627  void SetRegionAndFlowTypesFromProjectionValue(int value);
628 
629  // Sets all blobs with the partition blob type and flow, but never overwrite
630  // leader blobs, as we need to be able to identify them later.
631  void SetBlobTypes();
632 
633  // Returns true if a decent baseline can be fitted through the blobs.
634  // Works for both horizontal and vertical text.
635  bool HasGoodBaseline();
636 
637  // Adds this ColPartition to a matching WorkingPartSet if one can be found,
638  // otherwise starts a new one in the appropriate column, ending the previous.
639  void AddToWorkingSet(const ICOORD& bleft, const ICOORD& tright,
640  int resolution, ColPartition_LIST* used_parts,
641  WorkingPartSet_LIST* working_set);
642 
643  // From the given block_parts list, builds one or more BLOCKs and
644  // corresponding TO_BLOCKs, such that the line spacing is uniform in each.
645  // Created blocks are appended to the end of completed_blocks and to_blocks.
646  // The used partitions are put onto used_parts, as they may still be referred
647  // to in the partition grid. bleft, tright and resolution are the bounds
648  // and resolution of the original image.
649  static void LineSpacingBlocks(const ICOORD& bleft, const ICOORD& tright,
650  int resolution,
651  ColPartition_LIST* block_parts,
652  ColPartition_LIST* used_parts,
653  BLOCK_LIST* completed_blocks,
654  TO_BLOCK_LIST* to_blocks);
655  // Constructs a block from the given list of partitions.
656  // Arguments are as LineSpacingBlocks above.
657  static TO_BLOCK* MakeBlock(const ICOORD& bleft, const ICOORD& tright,
658  ColPartition_LIST* block_parts,
659  ColPartition_LIST* used_parts);
660 
661  // Constructs a block from the given list of vertical text partitions.
662  // Currently only creates rectangular blocks.
663  static TO_BLOCK* MakeVerticalTextBlock(const ICOORD& bleft,
664  const ICOORD& tright,
665  ColPartition_LIST* block_parts,
666  ColPartition_LIST* used_parts);
667 
668  // Makes a TO_ROW matching this and moves all the blobs to it, transferring
669  // ownership to to returned TO_ROW.
670  TO_ROW* MakeToRow();
671 
672 
673  // Returns a copy of everything except the list of boxes. The resulting
674  // ColPartition is only suitable for keeping in a column candidate list.
675  ColPartition* ShallowCopy() const;
676  // Returns a copy of everything with a shallow copy of the blobs.
677  // The blobs are still owned by their original parent, so they are
678  // treated as read-only.
679  ColPartition* CopyButDontOwnBlobs();
680 
681  #ifndef GRAPHICS_DISABLED
682  // Provides a color for BBGrid to draw the rectangle.
683  ScrollView::Color BoxColor() const;
684  #endif // GRAPHICS_DISABLED
685 
686  // Prints debug information on this.
687  void Print() const;
688  // Prints debug information on the colors.
689  void PrintColors();
690 
691  // Sets the types of all partitions in the run to be the max of the types.
692  void SmoothPartnerRun(int working_set_count);
693 
694  // Cleans up the partners of the given type so that there is at most
695  // one partner. This makes block creation simpler.
696  // If get_desperate is true, goes to more desperate merge methods
697  // to merge flowing text before breaking partnerships.
698  void RefinePartners(PolyBlockType type, bool get_desperate,
699  ColPartitionGrid* grid);
700 
701  // Returns true if this column partition is in the same column as
702  // part. This function will only work after the SetPartitionType function
703  // has been called on both column partitions. This is useful for
704  // doing a SideSearch when you want things in the same page column.
705  bool IsInSameColumnAs(const ColPartition& part) const;
706 
707  // Sort function to sort by bounding box.
708  static int SortByBBox(const void* p1, const void* p2) {
709  const ColPartition* part1 =
710  *static_cast<const ColPartition* const*>(p1);
711  const ColPartition* part2 =
712  *static_cast<const ColPartition* const*>(p2);
713  int mid_y1 = part1->bounding_box_.y_middle();
714  int mid_y2 = part2->bounding_box_.y_middle();
715  if ((part2->bounding_box_.bottom() <= mid_y1 &&
716  mid_y1 <= part2->bounding_box_.top()) ||
717  (part1->bounding_box_.bottom() <= mid_y2 &&
718  mid_y2 <= part1->bounding_box_.top())) {
719  // Sort by increasing x.
720  return part1->bounding_box_.x_middle() - part2->bounding_box_.x_middle();
721  }
722  // Sort by decreasing y.
723  return mid_y2 - mid_y1;
724  }
725 
726  // Sets the column bounds. Primarily used in testing.
727  void set_first_column(int column) {
728  first_column_ = column;
729  }
730  void set_last_column(int column) {
731  last_column_ = column;
732  }
733 
734  private:
735  // enum to refer to the entries in a neighbourhood of lines.
736  // Used by SmoothSpacings to test for blips with OKSpacingBlip.
737  enum SpacingNeighbourhood {
738  PN_ABOVE2,
739  PN_ABOVE1,
740  PN_UPPER,
741  PN_LOWER,
742  PN_BELOW1,
743  PN_BELOW2,
744  PN_COUNT
745  };
746 
747  // Cleans up the partners above if upper is true, else below.
748  // If get_desperate is true, goes to more desperate merge methods
749  // to merge flowing text before breaking partnerships.
750  void RefinePartnersInternal(bool upper, bool get_desperate,
751  ColPartitionGrid* grid);
752  // Restricts the partners to only desirable types. For text and BRT_HLINE this
753  // means the same type_ , and for image types it means any image type.
754  void RefinePartnersByType(bool upper, ColPartition_CLIST* partners);
755  // Remove transitive partnerships: this<->a, and a<->b and this<->b.
756  // Gets rid of this<->b, leaving a clean chain.
757  // Also if we have this<->a and a<->this, then gets rid of this<->a, as
758  // this has multiple partners.
759  void RefinePartnerShortcuts(bool upper, ColPartition_CLIST* partners);
760  // If multiple text partners can be merged, then do so.
761  // If desperate is true, then an increase in overlap with the merge is
762  // allowed. If the overlap increases, then the desperately_merged_ flag
763  // is set, indicating that the textlines probably need to be regenerated
764  // by aggressive line fitting/splitting, as there are probably vertically
765  // joined blobs that cross textlines.
766  void RefineTextPartnersByMerge(bool upper, bool desperate,
767  ColPartition_CLIST* partners,
768  ColPartitionGrid* grid);
769  // Keep the partner with the biggest overlap.
770  void RefinePartnersByOverlap(bool upper, ColPartition_CLIST* partners);
771 
772  // Return true if bbox belongs better in this than other.
773  bool ThisPartitionBetter(BLOBNBOX* bbox, const ColPartition& other);
774 
775  // Smoothes the spacings in the list into groups of equal linespacing.
776  // resolution is the resolution of the original image, used as a basis
777  // for thresholds in change of spacing. page_height is in pixels.
778  static void SmoothSpacings(int resolution, int page_height,
779  ColPartition_LIST* parts);
780 
781  // Returns true if the parts array of pointers to partitions matches the
782  // condition for a spacing blip. See SmoothSpacings for what this means
783  // and how it is used.
784  static bool OKSpacingBlip(int resolution, int median_spacing,
785  ColPartition** parts);
786 
787  // Returns true if both the top and bottom spacings of this match the given
788  // spacing to within suitable margins dictated by the image resolution.
789  bool SpacingEqual(int spacing, int resolution) const;
790 
791  // Returns true if both the top and bottom spacings of this and other
792  // match to within suitable margins dictated by the image resolution.
793  bool SpacingsEqual(const ColPartition& other, int resolution) const;
794 
795  // Returns true if the sum spacing of this and other match the given
796  // spacing (or twice the given spacing) to within a suitable margin dictated
797  // by the image resolution.
798  bool SummedSpacingOK(const ColPartition& other,
799  int spacing, int resolution) const;
800 
801  // Returns a suitable spacing margin that can be applied to bottoms of
802  // text lines, based on the resolution and the stored side_step_.
803  int BottomSpacingMargin(int resolution) const;
804 
805  // Returns a suitable spacing margin that can be applied to tops of
806  // text lines, based on the resolution and the stored side_step_.
807  int TopSpacingMargin(int resolution) const;
808 
809  // Returns true if the median text sizes of this and other agree to within
810  // a reasonable multiplicative factor.
811  bool SizesSimilar(const ColPartition& other) const;
812 
813  // Computes and returns in start, end a line segment formed from a
814  // forwards-iterated group of left edges of partitions that satisfy the
815  // condition that the rightmost left margin is to the left of the
816  // leftmost left bounding box edge.
817  // TODO(rays) Not good enough. Needs improving to tightly wrap text in both
818  // directions, and to loosely wrap images.
819  static void LeftEdgeRun(ColPartition_IT* part_it,
820  ICOORD* start, ICOORD* end);
821  // Computes and returns in start, end a line segment formed from a
822  // backwards-iterated group of right edges of partitions that satisfy the
823  // condition that the leftmost right margin is to the right of the
824  // rightmost right bounding box edge.
825  // TODO(rays) Not good enough. Needs improving to tightly wrap text in both
826  // directions, and to loosely wrap images.
827  static void RightEdgeRun(ColPartition_IT* part_it,
828  ICOORD* start, ICOORD* end);
829 
830  // The margins are determined by the position of the nearest vertically
831  // overlapping neighbour to the side. They indicate the maximum extent
832  // that the block/column may be extended without touching something else.
833  // Leftmost coordinate that the region may occupy over the y limits.
834  int left_margin_;
835  // Rightmost coordinate that the region may occupy over the y limits.
836  int right_margin_;
837  // Bounding box of all blobs in the partition.
838  TBOX bounding_box_;
839  // Median top and bottom of blobs in this partition.
840  int median_bottom_;
841  int median_top_;
842  // Median height of blobs in this partition.
843  // TODO(rays) rename median_height_.
844  int median_size_;
845  // Median left and right of blobs in this partition.
846  int median_left_;
847  int median_right_;
848  // Median width of blobs in this partition.
849  int median_width_;
850  // blob_region_type_ for the blobs in this partition.
851  BlobRegionType blob_type_;
852  BlobTextFlowType flow_; // Quality of text flow.
853  // Total of GoodTextBlob results for all blobs in the partition.
854  int good_blob_score_;
855  // True if this partition has a common width.
856  bool good_width_;
857  // True if this is a good column candidate.
858  bool good_column_;
859  // True if the left_key_ is from a tab vector.
860  bool left_key_tab_;
861  // True if the right_key_ is from a tab vector.
862  bool right_key_tab_;
863  // Left and right sort keys for the edges of the partition.
864  // If the respective *_key_tab_ is true then this key came from a tab vector.
865  // If not, then the class promises to keep the key equal to the sort key
866  // for the respective edge of the bounding box at the MidY, so that
867  // LeftAtY and RightAtY always returns an x coordinate on the line parallel
868  // to vertical_ through the bounding box edge at MidY.
869  int left_key_;
870  int right_key_;
871  // Type of this partition after looking at its relation to the columns.
872  PolyBlockType type_;
873  // All boxes in the partition stored in increasing left edge coordinate.
874  BLOBNBOX_CLIST boxes_;
875  // The global vertical skew direction.
876  ICOORD vertical_;
877  // The partitions above that matched this.
878  ColPartition_CLIST upper_partners_;
879  // The partitions below that matched this.
880  ColPartition_CLIST lower_partners_;
881  // The WorkingPartSet it lives in while blocks are being made.
882  WorkingPartSet* working_set_;
883  // Flag is true when AddBox is sorting vertically, false otherwise.
884  bool last_add_was_vertical_;
885  // True when the partition's ownership has been taken from the grid and
886  // placed in a working set, or, after that, in the good_parts_ list.
887  bool block_owned_;
888  // Flag to indicate that this partition was subjected to a desperate merge,
889  // and therefore the textlines need rebuilding.
890  bool desperately_merged_;
891  // The first and last column that this partition applies to.
892  // Flowing partitions (see type_) will have an equal first and last value
893  // of the form 2n + 1, where n is the zero-based index into the partitions
894  // in column_set_. (See ColPartitionSet::GetColumnByIndex).
895  // Heading partitions will have unequal values of the same form.
896  // Pullout partitions will have equal values, but may have even values,
897  // indicating placement between columns.
898  int first_column_;
899  int last_column_;
900  // Column_set_ is the column layout applicable to this ColPartition.
901  ColPartitionSet* column_set_;
902  // Linespacing data.
903  int side_step_; // Median y-shift to next blob on same line.
904  int top_spacing_; // Line spacing from median_top_.
905  int bottom_spacing_; // Line spacing from median_bottom_.
906 
907  // Type of this partition before considering it as a table cell. This is
908  // used to revert the type if a partition is first marked as a table cell but
909  // later filtering steps decide it does not belong to a table
910  PolyBlockType type_before_table_;
911  bool inside_table_column_; // Check whether the current partition has been
912  // assigned to a table column
913  // Nearest neighbor above with major x-overlap
914  ColPartition* nearest_neighbor_above_;
915  // Nearest neighbor below with major x-overlap
916  ColPartition* nearest_neighbor_below_;
917  int space_above_; // Distance from nearest_neighbor_above
918  int space_below_; // Distance from nearest_neighbor_below
919  int space_to_left_; // Distance from the left edge of the column
920  int space_to_right_; // Distance from the right edge of the column
921  // Color foreground/background data.
922  uinT8 color1_[kRGBRMSColors];
923  uinT8 color2_[kRGBRMSColors];
924  bool owns_blobs_; // Does the partition own its blobs?
925  // The density of special blobs.
926  float special_blobs_densities_[BSTT_COUNT];
927 };
928 
929 // Typedef it now in case it becomes a class later.
930 typedef GridSearch<ColPartition,
931  ColPartition_CLIST,
932  ColPartition_C_IT> ColPartitionGridSearch;
933 
934 } // namespace tesseract.
935 
936 #endif // TESSERACT_TEXTORD_COLPARTITION_H_
void set_last_column(int column)
Definition: colpartition.h:730
bool PTIsLineType(PolyBlockType type)
Definition: publictypes.h:61
void set_median_size(int size)
Definition: colpartition.h:139
int XAtY(int sort_key, int y) const
Definition: colpartition.h:320
int bottom_spacing() const
Definition: colpartition.h:220
bool IsVerticalType() const
Definition: colpartition.h:435
Definition: capi.h:95
void set_space_below(int space)
Definition: colpartition.h:270
ColPartition * nearest_neighbor_below() const
Definition: colpartition.h:255
int SortKey(int x, int y) const
Definition: colpartition.h:316
int VCoreOverlap(const ColPartition &other) const
Definition: colpartition.h:375
void set_owns_blobs(bool owns_blobs)
Definition: colpartition.h:294
ColPartition_CLIST * upper_partners()
Definition: colpartition.h:196
void set_nearest_neighbor_below(ColPartition *part)
Definition: colpartition.h:258
bool VSignificantCoreOverlap(const ColPartition &other) const
Definition: colpartition.h:387
GridSearch< ColPartition, ColPartition_CLIST, ColPartition_C_IT > ColPartitionGridSearch
Definition: colpartition.h:932
bool IsLeftOf(const ColPartition &other) const
Definition: colpartition.h:349
int LeftAtY(int y) const
Definition: colpartition.h:340
voidpf void uLong size
Definition: ioapi.h:39
int y_middle() const
Definition: rect.h:84
bool desperately_merged() const
Definition: colpartition.h:211
BLOBNBOX_CLIST * boxes()
Definition: colpartition.h:187
bool IsUnMergeableType() const
Definition: colpartition.h:443
bool PTIsPulloutType(PolyBlockType type)
Definition: publictypes.h:77
bool ColumnContains(int x, int y) const
Definition: colpartition.h:353
void set_side_step(int step)
Definition: colpartition.h:217
PolyBlockType
Definition: publictypes.h:41
void set_first_column(int column)
Definition: colpartition.h:727
void set_flow(BlobTextFlowType f)
Definition: colpartition.h:157
ColPartition_CLIST * lower_partners()
Definition: colpartition.h:199
bool left_key_tab() const
Definition: colpartition.h:169
Definition: capi.h:94
bool IsHorizontalLine() const
Definition: colpartition.h:453
int space_to_right() const
Definition: colpartition.h:279
int RightAtY(int y) const
Definition: colpartition.h:344
bool good_column() const
Definition: colpartition.h:166
static bool TypesMatch(BlobRegionType type1, BlobRegionType type2)
Definition: colpartition.h:406
#define ASSERT_HOST(x)
Definition: errcode.h:84
void set_top_spacing(int spacing)
Definition: colpartition.h:229
void set_block_owned(bool owned)
Definition: colpartition.h:208
inT16 left() const
Definition: rect.h:68
void set_space_above(int space)
Definition: colpartition.h:264
ColPartition * nearest_neighbor_above() const
Definition: colpartition.h:249
static int SortByBBox(const void *p1, const void *p2)
Definition: colpartition.h:708
bool IsImageType() const
Definition: colpartition.h:423
void set_type(PolyBlockType t)
Definition: colpartition.h:184
const TBOX & bounding_box() const
Definition: colpartition.h:109
bool WithinSameMargins(const ColPartition &other) const
Definition: colpartition.h:395
void set_right_margin(int margin)
Definition: colpartition.h:121
#define ELIST2IZEH(CLASSNAME)
Definition: elst2.h:950
int KeyWidth(int left_key, int right_key) const
Definition: colpartition.h:324
static bool IsLineType(BlobRegionType type)
Definition: blobbox.h:411
BlobSpecialTextType
Definition: blobbox.h:81
void set_space_to_right(int space)
Definition: colpartition.h:282
PolyBlockType type() const
Definition: colpartition.h:181
void set_vertical(const ICOORD &v)
Definition: colpartition.h:193
bool HOverlaps(const ColPartition &other) const
Definition: colpartition.h:365
bool IsSingleton() const
Definition: colpartition.h:361
inT16 top() const
Definition: rect.h:54
#define MAX(x, y)
Definition: ndminx.h:24
void set_space_to_left(int space)
Definition: colpartition.h:276
const int kRGBRMSColors
Definition: colpartition.h:36
Definition: rect.h:30
#define MIN(x, y)
Definition: ndminx.h:28
bool block_owned() const
Definition: colpartition.h:205
static bool UnMergeableType(BlobRegionType type)
Definition: blobbox.h:415
int XAtY(int y) const
Definition: tabvector.h:189
void set_working_set(WorkingPartSet *working_set)
Definition: colpartition.h:202
void set_left_margin(int margin)
Definition: colpartition.h:115
bool IsPulloutType() const
Definition: colpartition.h:431
uint8_t uinT8
Definition: host.h:35
inT16 right() const
Definition: rect.h:75
void set_bottom_spacing(int spacing)
Definition: colpartition.h:223
bool PTIsImageType(PolyBlockType type)
Definition: publictypes.h:65
BlobTextFlowType
Definition: blobbox.h:99
bool PTIsTextType(PolyBlockType type)
Definition: publictypes.h:70
int good_blob_score() const
Definition: colpartition.h:160
void set_median_width(int width)
Definition: colpartition.h:145
inT16 bottom() const
Definition: rect.h:61
static bool TypesSimilar(PolyBlockType type1, PolyBlockType type2)
Definition: colpartition.h:412
bool right_key_tab() const
Definition: colpartition.h:175
BlobRegionType
Definition: blobbox.h:57
void set_inside_table_column(bool val)
Definition: colpartition.h:246
#define CLISTIZEH(CLASSNAME)
Definition: clst.h:901
double v[max]
bool IsHorizontalType() const
Definition: colpartition.h:439
void set_nearest_neighbor_above(ColPartition *part)
Definition: colpartition.h:252
ColPartitionSet * column_set() const
Definition: colpartition.h:214
static int SortKey(const ICOORD &vertical, int x, int y)
Definition: tabvector.h:280
bool VOverlaps(const ColPartition &other) const
Definition: colpartition.h:370
bool IsVerticalLine() const
Definition: colpartition.h:448
BlobTextFlowType flow() const
Definition: colpartition.h:154
BlobRegionType blob_type() const
Definition: colpartition.h:148
bool TypesMatch(const ColPartition &other) const
Definition: colpartition.h:403
int HCoreOverlap(const ColPartition &other) const
Definition: colpartition.h:381
int x_middle() const
Definition: rect.h:81
integer coordinate
Definition: points.h:30
void set_blob_type(BlobRegionType t)
Definition: colpartition.h:151