00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00020
00021 #ifndef TESSERACT_TEXTORD_COLPARTITION_H__
00022 #define TESSERACT_TEXTORD_COLPARTITION_H__
00023
00024 #include "bbgrid.h"
00025 #include "blobbox.h"
00026 #include "ndminx.h"
00027 #include "ocrblock.h"
00028 #include "rect.h"
00029 #include "scrollview.h"
00030 #include "tabfind.h"
00031 #include "tabvector.h"
00032
00033 namespace tesseract {
00034
00035
00036 const int kRGBRMSColors = 4;
00037
00038 class ColPartition;
00039 class ColPartitionSet;
00040 class ColPartitionGrid;
00041 class WorkingPartSet;
00042 class WorkingPartSet_LIST;
00043
00044
00045
00046
00047 enum ColumnSpanningType {
00048 CST_NOISE,
00049 CST_FLOWING,
00050 CST_HEADING,
00051 CST_PULLOUT,
00052 CST_COUNT
00053 };
00054
00055 ELIST2IZEH(ColPartition)
00056 CLISTIZEH(ColPartition)
00057
00067 class ColPartition : public ELIST2_LINK {
00068 public:
00069 ColPartition() {
00070
00071
00072
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
00089
00090
00091
00092
00093 static ColPartition* FakePartition(const TBOX& box,
00094 PolyBlockType block_type,
00095 BlobRegionType blob_type,
00096 BlobTextFlowType flow);
00097
00098
00099
00100
00101
00102
00103 static ColPartition* MakeBigPartition(BLOBNBOX* box,
00104 ColPartition_LIST* big_part_list);
00105
00106 ~ColPartition();
00107
00108
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
00296
00297 ASSERT_HOST(boxes_.empty());
00298 owns_blobs_ = owns_blobs;
00299 }
00300
00301
00302
00303
00304 int MidY() const {
00305 return (bounding_box_.top() + bounding_box_.bottom()) / 2;
00306 }
00307
00308 int MedianY() const {
00309 return (median_top_ + median_bottom_) / 2;
00310 }
00311
00312 int MidX() const {
00313 return (bounding_box_.left() + bounding_box_.right()) / 2;
00314 }
00315
00316 int SortKey(int x, int y) const {
00317 return TabVector::SortKey(vertical_, x, y);
00318 }
00319
00320 int XAtY(int sort_key, int y) const {
00321 return TabVector::XAtY(vertical_, sort_key, y);
00322 }
00323
00324 int KeyWidth(int left_key, int right_key) const {
00325 return (right_key - left_key) / vertical_.y();
00326 }
00327
00328 int ColumnWidth() const {
00329 return KeyWidth(left_key_, right_key_);
00330 }
00331
00332 int BoxLeftKey() const {
00333 return SortKey(bounding_box_.left(), MidY());
00334 }
00335
00336 int BoxRightKey() const {
00337 return SortKey(bounding_box_.right(), MidY());
00338 }
00339
00340 int LeftAtY(int y) const {
00341 return XAtY(left_key_, y);
00342 }
00343
00344 int RightAtY(int y) const {
00345 return XAtY(right_key_, y);
00346 }
00347
00348
00349 bool IsLeftOf(const ColPartition& other) const {
00350 return bounding_box_.right() < other.bounding_box_.right();
00351 }
00352
00353 bool ColumnContains(int x, int y) const {
00354 return LeftAtY(y) - 1 <= x && x <= RightAtY(y) + 1;
00355 }
00356
00357 bool IsEmpty() const {
00358 return boxes_.empty();
00359 }
00360
00361 bool IsSingleton() const {
00362 return boxes_.singleton();
00363 }
00364
00365 bool HOverlaps(const ColPartition& other) const {
00366 return bounding_box_.x_overlap(other.bounding_box_);
00367 }
00368
00369
00370 bool VOverlaps(const ColPartition& other) const {
00371 return bounding_box_.y_gap(other.bounding_box_) < 0;
00372 }
00373
00374
00375 int VCoreOverlap(const ColPartition& other) const {
00376 return MIN(median_top_, other.median_top_) -
00377 MAX(median_bottom_, other.median_bottom_);
00378 }
00379
00380
00381 int HCoreOverlap(const ColPartition& other) const {
00382 return MIN(median_right_, other.median_right_) -
00383 MAX(median_left_, other.median_left_);
00384 }
00385
00386
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
00394
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
00402
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
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
00419 bool IsLineType() const {
00420 return PTIsLineType(type_);
00421 }
00422
00423 bool IsImageType() const {
00424 return PTIsImageType(type_);
00425 }
00426
00427 bool IsTextType() const {
00428 return PTIsTextType(type_);
00429 }
00430
00431 bool IsVerticalType() const {
00432 return blob_type_ == BRT_VERT_TEXT || blob_type_ == BRT_VLINE;
00433 }
00434
00435 bool IsHorizontalType() const {
00436 return blob_type_ == BRT_TEXT || blob_type_ == BRT_HLINE;
00437 }
00438
00439 bool IsUnMergeableType() const {
00440 return BLOBNBOX::UnMergeableType(blob_type_) || type_ == PT_NOISE;
00441 }
00442
00443
00444 bool IsVerticalLine() const {
00445 return IsVerticalType() && IsLineType();
00446 }
00447
00448
00449 bool IsHorizontalLine() const {
00450 return IsHorizontalType() && IsLineType();
00451 }
00452
00453
00454
00455
00456 void AddBox(BLOBNBOX* box);
00457
00458
00459 void RemoveBox(BLOBNBOX* box);
00460
00461
00462
00463 BLOBNBOX* BiggestBox();
00464
00465
00466 TBOX BoundsWithoutBox(BLOBNBOX* box);
00467
00468
00469
00470 void ClaimBoxes();
00471
00472
00473
00474 void DisownBoxes();
00475
00476
00477 void DeleteBoxes();
00478
00479
00480
00481
00482
00483 void ReflectInYAxis();
00484
00485
00486
00487
00488
00489
00490
00491 bool IsLegal();
00492
00493
00494 bool MatchingColumns(const ColPartition& other) const;
00495
00496
00497 bool MatchingTextColor(const ColPartition& other) const;
00498
00499
00500
00501 bool MatchingSizes(const ColPartition& other) const;
00502
00503
00504 bool ConfirmNoTabViolation(const ColPartition& other) const;
00505
00506
00507 bool MatchingStrokeWidth(const ColPartition& other,
00508 double fractional_tolerance,
00509 double constant_tolerance) const;
00510
00511
00512 bool OKDiacriticMerge(const ColPartition& candidate, bool debug) const;
00513
00514
00515
00516
00517 void SetLeftTab(const TabVector* tab_vector);
00518 void SetRightTab(const TabVector* tab_vector);
00519
00520
00521
00522 void CopyLeftTab(const ColPartition& src, bool take_box);
00523 void CopyRightTab(const ColPartition& src, bool take_box);
00524
00525
00526 int LeftBlobRule() const;
00527
00528 int RightBlobRule() const;
00529
00530
00531 float SpecialBlobsDensity(const BlobSpecialTextType type) const;
00532
00533 int SpecialBlobsCount(const BlobSpecialTextType type);
00534
00535
00536
00537 void SetSpecialBlobsDensity(
00538 const BlobSpecialTextType type, const float density);
00539
00540
00541 void ComputeSpecialBlobsDensity();
00542
00543
00544
00545
00546 void AddPartner(bool upper, ColPartition* partner);
00547
00548
00549
00550 void RemovePartner(bool upper, ColPartition* partner);
00551
00552 ColPartition* SingletonPartner(bool upper);
00553
00554
00555 void Absorb(ColPartition* other, WidthCallback* cb);
00556
00557
00558
00559
00560
00561 bool OKMergeOverlap(const ColPartition& merge1, const ColPartition& merge2,
00562 int ok_box_overlap, bool debug);
00563
00564
00565
00566 BLOBNBOX* OverlapSplitBlob(const TBOX& box);
00567
00568
00569
00570
00571
00572 ColPartition* SplitAtBlob(BLOBNBOX* split_blob);
00573
00574
00575
00576 ColPartition* SplitAt(int split_x);
00577
00578
00579 void ComputeLimits();
00580
00581
00582 int CountOverlappingBoxes(const TBOX& box);
00583
00584
00585
00586 void SetPartitionType(int resolution, ColPartitionSet* columns);
00587
00588
00589
00590
00591
00592 PolyBlockType PartitionType(ColumnSpanningType flow) const;
00593
00594
00595
00596 void ColumnRange(int resolution, ColPartitionSet* columns,
00597 int* first_col, int* last_col);
00598
00599
00600 void SetColumnGoodness(WidthCallback* cb);
00601
00602
00603
00604
00605
00606
00607
00608 bool MarkAsLeaderIfMonospaced();
00609
00610
00611
00612
00613 void SetRegionAndFlowTypesFromProjectionValue(int value);
00614
00615
00616
00617 void SetBlobTypes();
00618
00619
00620
00621 bool HasGoodBaseline();
00622
00623
00624
00625 void AddToWorkingSet(const ICOORD& bleft, const ICOORD& tright,
00626 int resolution, ColPartition_LIST* used_parts,
00627 WorkingPartSet_LIST* working_set);
00628
00629
00630
00631
00632
00633
00634
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
00642
00643 static TO_BLOCK* MakeBlock(const ICOORD& bleft, const ICOORD& tright,
00644 ColPartition_LIST* block_parts,
00645 ColPartition_LIST* used_parts);
00646
00647
00648
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
00656
00657 ColPartition* ShallowCopy() const;
00658
00659
00660
00661 ColPartition* CopyButDontOwnBlobs();
00662
00663
00664 ScrollView::Color BoxColor() const;
00665
00666
00667 void Print() const;
00668
00669 void PrintColors();
00670
00671
00672 void SmoothPartnerRun(int working_set_count);
00673
00674
00675
00676
00677
00678 void RefinePartners(PolyBlockType type, bool get_desparate,
00679 ColPartitionGrid* grid);
00680
00681
00682
00683
00684
00685 bool IsInSameColumnAs(const ColPartition& part) const;
00686
00687
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
00697
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
00709
00710
00711 void RefinePartnersInternal(bool upper, bool get_desperate,
00712 ColPartitionGrid* grid);
00713
00714
00715 void RefinePartnersByType(bool upper, ColPartition_CLIST* partners);
00716
00717
00718
00719
00720 void RefinePartnerShortcuts(bool upper, ColPartition_CLIST* partners);
00721
00722
00723
00724
00725
00726
00727 void RefineTextPartnersByMerge(bool upper, bool desperate,
00728 ColPartition_CLIST* partners,
00729 ColPartitionGrid* grid);
00730
00731 void RefinePartnersByOverlap(bool upper, ColPartition_CLIST* partners);
00732
00733
00734 bool ThisPartitionBetter(BLOBNBOX* bbox, const ColPartition& other);
00735
00736
00737
00738
00739 static void SmoothSpacings(int resolution, int page_height,
00740 ColPartition_LIST* parts);
00741
00742
00743
00744
00745 static bool OKSpacingBlip(int resolution, int median_spacing,
00746 ColPartition** parts);
00747
00748
00749
00750 bool SpacingEqual(int spacing, int resolution) const;
00751
00752
00753
00754 bool SpacingsEqual(const ColPartition& other, int resolution) const;
00755
00756
00757
00758
00759 bool SummedSpacingOK(const ColPartition& other,
00760 int spacing, int resolution) const;
00761
00762
00763
00764 int BottomSpacingMargin(int resolution) const;
00765
00766
00767
00768 int TopSpacingMargin(int resolution) const;
00769
00770
00771
00772 bool SizesSimilar(const ColPartition& other) const;
00773
00774
00775
00776
00777
00778
00779
00780 static void LeftEdgeRun(ColPartition_IT* part_it,
00781 ICOORD* start, ICOORD* end);
00782
00783
00784
00785
00786
00787
00788 static void RightEdgeRun(ColPartition_IT* part_it,
00789 ICOORD* start, ICOORD* end);
00790
00791
00792
00793
00794
00795 int left_margin_;
00796
00797 int right_margin_;
00798
00799 TBOX bounding_box_;
00800
00801 int median_bottom_;
00802 int median_top_;
00803
00804
00805 int median_size_;
00806
00807 int median_left_;
00808 int median_right_;
00809
00810 int median_width_;
00811
00812 BlobRegionType blob_type_;
00813 BlobTextFlowType flow_;
00814
00815 int good_blob_score_;
00816
00817 bool good_width_;
00818
00819 bool good_column_;
00820
00821 bool left_key_tab_;
00822
00823 bool right_key_tab_;
00824
00825
00826
00827
00828
00829
00830 int left_key_;
00831 int right_key_;
00832
00833 PolyBlockType type_;
00834
00835 BLOBNBOX_CLIST boxes_;
00836
00837 ICOORD vertical_;
00838
00839 ColPartition_CLIST upper_partners_;
00840
00841 ColPartition_CLIST lower_partners_;
00842
00843 WorkingPartSet* working_set_;
00844
00845 bool last_add_was_vertical_;
00846
00847
00848 bool block_owned_;
00849
00850
00851 bool desperately_merged_;
00852
00853
00854
00855
00856
00857
00858
00859 int first_column_;
00860 int last_column_;
00861
00862 ColPartitionSet* column_set_;
00863
00864 int side_step_;
00865 int top_spacing_;
00866 int bottom_spacing_;
00867
00868
00869
00870
00871 PolyBlockType type_before_table_;
00872 bool inside_table_column_;
00873
00874
00875 ColPartition* nearest_neighbor_above_;
00876
00877 ColPartition* nearest_neighbor_below_;
00878 int space_above_;
00879 int space_below_;
00880 int space_to_left_;
00881 int space_to_right_;
00882
00883 uinT8 color1_[kRGBRMSColors];
00884 uinT8 color2_[kRGBRMSColors];
00885 bool owns_blobs_;
00886
00887 float special_blobs_densities_[BSTT_COUNT];
00888 };
00889
00890
00891 typedef GridSearch<ColPartition,
00892 ColPartition_CLIST,
00893 ColPartition_C_IT> ColPartitionGridSearch;
00894
00895 }
00896
00897 #endif // TESSERACT_TEXTORD_COLPARTITION_H__