00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef BLOBBOX_H
00021 #define BLOBBOX_H
00022
00023 #include "clst.h"
00024 #include "elst2.h"
00025 #include "werd.h"
00026 #include "ocrblock.h"
00027 #include "statistc.h"
00028
00029 enum PITCH_TYPE
00030 {
00031 PITCH_DUNNO,
00032 PITCH_DEF_FIXED,
00033 PITCH_MAYBE_FIXED,
00034 PITCH_DEF_PROP,
00035 PITCH_MAYBE_PROP,
00036 PITCH_CORR_FIXED,
00037 PITCH_CORR_PROP
00038 };
00039
00040
00041
00042
00043
00044 enum TabType {
00045 TT_NONE,
00046 TT_DELETED,
00047 TT_MAYBE_RAGGED,
00048 TT_MAYBE_ALIGNED,
00049 TT_CONFIRMED,
00050 TT_VLINE
00051 };
00052
00053
00054
00055
00056
00057 enum BlobRegionType {
00058 BRT_NOISE,
00059 BRT_HLINE,
00060 BRT_VLINE,
00061 BRT_RECTIMAGE,
00062 BRT_POLYIMAGE,
00063 BRT_UNKNOWN,
00064 BRT_VERT_TEXT,
00065 BRT_TEXT,
00066
00067 BRT_COUNT
00068 };
00069
00070
00071
00072 enum BlobNeighbourDir {
00073 BND_LEFT,
00074 BND_BELOW,
00075 BND_RIGHT,
00076 BND_ABOVE,
00077 BND_COUNT
00078 };
00079
00080
00081 enum BlobSpecialTextType {
00082 BSTT_NONE,
00083 BSTT_ITALIC,
00084 BSTT_DIGIT,
00085 BSTT_MATH,
00086 BSTT_UNCLEAR,
00087 BSTT_SKIP,
00088 BSTT_COUNT
00089 };
00090
00091 inline BlobNeighbourDir DirOtherWay(BlobNeighbourDir dir) {
00092 return static_cast<BlobNeighbourDir>(dir ^ 2);
00093 }
00094
00095
00096
00097
00098
00099 enum BlobTextFlowType {
00100 BTFT_NONE,
00101 BTFT_NONTEXT,
00102 BTFT_NEIGHBOURS,
00103 BTFT_CHAIN,
00104 BTFT_STRONG_CHAIN,
00105 BTFT_TEXT_ON_IMAGE,
00106 BTFT_LEADER,
00107 BTFT_COUNT
00108 };
00109
00110
00111
00112
00113
00114 inline bool DominatesInMerge(BlobTextFlowType type1, BlobTextFlowType type2) {
00115
00116 if (type1 == BTFT_LEADER) return false;
00117 if (type2 == BTFT_LEADER) return true;
00118
00119 return type1 >= type2;
00120 }
00121
00122 namespace tesseract {
00123 class ColPartition;
00124 }
00125
00126 class BLOBNBOX;
00127 ELISTIZEH (BLOBNBOX)
00128 class BLOBNBOX:public ELIST_LINK
00129 {
00130 public:
00131 BLOBNBOX() {
00132 ConstructionInit();
00133 }
00134 explicit BLOBNBOX(C_BLOB *srcblob) {
00135 box = srcblob->bounding_box();
00136 ConstructionInit();
00137 cblob_ptr = srcblob;
00138 area = static_cast<int>(srcblob->area());
00139 }
00140 static BLOBNBOX* RealBlob(C_OUTLINE* outline) {
00141 C_BLOB* blob = new C_BLOB(outline);
00142 return new BLOBNBOX(blob);
00143 }
00144
00145
00146 void rotate(FCOORD rotation);
00147
00148
00149
00150 void reflect_box_in_y_axis();
00151
00152
00153
00154 void rotate_box(FCOORD rotation);
00155
00156 void translate_box(ICOORD v) {
00157 if (IsDiacritic()) {
00158 box.move(v);
00159 base_char_top_ += v.y();
00160 base_char_bottom_ += v.y();
00161 } else {
00162 box.move(v);
00163 set_diacritic_box(box);
00164 }
00165 }
00166 void merge(BLOBNBOX *nextblob);
00167 void really_merge(BLOBNBOX* other);
00168 void chop(
00169 BLOBNBOX_IT *start_it,
00170 BLOBNBOX_IT *blob_it,
00171 FCOORD rotation,
00172 float xheight);
00173
00174 void NeighbourGaps(int gaps[BND_COUNT]) const;
00175 void MinMaxGapsClipped(int* h_min, int* h_max,
00176 int* v_min, int* v_max) const;
00177 void CleanNeighbours();
00178
00179
00180 int GoodTextBlob() const;
00181
00182 int NoisyNeighbours() const;
00183
00184
00185 bool DeletableNoise() const {
00186 return owner() == NULL && region_type() == BRT_NOISE;
00187 }
00188
00189
00190
00191
00192
00193 bool DefiniteIndividualFlow();
00194
00195
00196 bool ConfirmNoTabViolation(const BLOBNBOX& other) const;
00197
00198
00199 bool MatchingStrokeWidth(const BLOBNBOX& other,
00200 double fractional_tolerance,
00201 double constant_tolerance) const;
00202
00203
00204
00205 TBOX BoundsWithinLimits(int left, int right);
00206
00207
00208 const TBOX& bounding_box() const {
00209 return box;
00210 }
00211
00212
00213 void set_bounding_box(const TBOX& new_box) {
00214 box = new_box;
00215 base_char_top_ = box.top();
00216 base_char_bottom_ = box.bottom();
00217 }
00218 void compute_bounding_box() {
00219 box = cblob_ptr->bounding_box();
00220 base_char_top_ = box.top();
00221 base_char_bottom_ = box.bottom();
00222 }
00223 const TBOX& reduced_box() const {
00224 return red_box;
00225 }
00226 void set_reduced_box(TBOX new_box) {
00227 red_box = new_box;
00228 reduced = TRUE;
00229 }
00230 inT32 enclosed_area() const {
00231 return area;
00232 }
00233 bool joined_to_prev() const {
00234 return joined != 0;
00235 }
00236 bool red_box_set() const {
00237 return reduced != 0;
00238 }
00239 int repeated_set() const {
00240 return repeated_set_;
00241 }
00242 void set_repeated_set(int set_id) {
00243 repeated_set_ = set_id;
00244 }
00245 C_BLOB *cblob() const {
00246 return cblob_ptr;
00247 }
00248 TabType left_tab_type() const {
00249 return left_tab_type_;
00250 }
00251 void set_left_tab_type(TabType new_type) {
00252 left_tab_type_ = new_type;
00253 }
00254 TabType right_tab_type() const {
00255 return right_tab_type_;
00256 }
00257 void set_right_tab_type(TabType new_type) {
00258 right_tab_type_ = new_type;
00259 }
00260 BlobRegionType region_type() const {
00261 return region_type_;
00262 }
00263 void set_region_type(BlobRegionType new_type) {
00264 region_type_ = new_type;
00265 }
00266 BlobSpecialTextType special_text_type() const {
00267 return spt_type_;
00268 }
00269 void set_special_text_type(BlobSpecialTextType new_type) {
00270 spt_type_ = new_type;
00271 }
00272 BlobTextFlowType flow() const {
00273 return flow_;
00274 }
00275 void set_flow(BlobTextFlowType value) {
00276 flow_ = value;
00277 }
00278 bool vert_possible() const {
00279 return vert_possible_;
00280 }
00281 void set_vert_possible(bool value) {
00282 vert_possible_ = value;
00283 }
00284 bool horz_possible() const {
00285 return horz_possible_;
00286 }
00287 void set_horz_possible(bool value) {
00288 horz_possible_ = value;
00289 }
00290 int left_rule() const {
00291 return left_rule_;
00292 }
00293 void set_left_rule(int new_left) {
00294 left_rule_ = new_left;
00295 }
00296 int right_rule() const {
00297 return right_rule_;
00298 }
00299 void set_right_rule(int new_right) {
00300 right_rule_ = new_right;
00301 }
00302 int left_crossing_rule() const {
00303 return left_crossing_rule_;
00304 }
00305 void set_left_crossing_rule(int new_left) {
00306 left_crossing_rule_ = new_left;
00307 }
00308 int right_crossing_rule() const {
00309 return right_crossing_rule_;
00310 }
00311 void set_right_crossing_rule(int new_right) {
00312 right_crossing_rule_ = new_right;
00313 }
00314 float horz_stroke_width() const {
00315 return horz_stroke_width_;
00316 }
00317 void set_horz_stroke_width(float width) {
00318 horz_stroke_width_ = width;
00319 }
00320 float vert_stroke_width() const {
00321 return vert_stroke_width_;
00322 }
00323 void set_vert_stroke_width(float width) {
00324 vert_stroke_width_ = width;
00325 }
00326 float area_stroke_width() const {
00327 return area_stroke_width_;
00328 }
00329 tesseract::ColPartition* owner() const {
00330 return owner_;
00331 }
00332 void set_owner(tesseract::ColPartition* new_owner) {
00333 owner_ = new_owner;
00334 }
00335 bool leader_on_left() const {
00336 return leader_on_left_;
00337 }
00338 void set_leader_on_left(bool flag) {
00339 leader_on_left_ = flag;
00340 }
00341 bool leader_on_right() const {
00342 return leader_on_right_;
00343 }
00344 void set_leader_on_right(bool flag) {
00345 leader_on_right_ = flag;
00346 }
00347 BLOBNBOX* neighbour(BlobNeighbourDir n) const {
00348 return neighbours_[n];
00349 }
00350 bool good_stroke_neighbour(BlobNeighbourDir n) const {
00351 return good_stroke_neighbours_[n];
00352 }
00353 void set_neighbour(BlobNeighbourDir n, BLOBNBOX* neighbour, bool good) {
00354 neighbours_[n] = neighbour;
00355 good_stroke_neighbours_[n] = good;
00356 }
00357 bool IsDiacritic() const {
00358 return base_char_top_ != box.top() || base_char_bottom_ != box.bottom();
00359 }
00360 int base_char_top() const {
00361 return base_char_top_;
00362 }
00363 int base_char_bottom() const {
00364 return base_char_bottom_;
00365 }
00366 int line_crossings() const {
00367 return line_crossings_;
00368 }
00369 void set_line_crossings(int value) {
00370 line_crossings_ = value;
00371 }
00372 void set_diacritic_box(const TBOX& diacritic_box) {
00373 base_char_top_ = diacritic_box.top();
00374 base_char_bottom_ = diacritic_box.bottom();
00375 }
00376 BLOBNBOX* base_char_blob() const {
00377 return base_char_blob_;
00378 }
00379 void set_base_char_blob(BLOBNBOX* blob) {
00380 base_char_blob_ = blob;
00381 }
00382
00383 bool UniquelyVertical() const {
00384 return vert_possible_ && !horz_possible_;
00385 }
00386 bool UniquelyHorizontal() const {
00387 return horz_possible_ && !vert_possible_;
00388 }
00389
00390
00391 static bool IsTextType(BlobRegionType type) {
00392 return type == BRT_TEXT || type == BRT_VERT_TEXT;
00393 }
00394
00395 static bool IsImageType(BlobRegionType type) {
00396 return type == BRT_RECTIMAGE || type == BRT_POLYIMAGE;
00397 }
00398
00399 static bool IsLineType(BlobRegionType type) {
00400 return type == BRT_HLINE || type == BRT_VLINE;
00401 }
00402
00403 static bool UnMergeableType(BlobRegionType type) {
00404 return IsLineType(type) || IsImageType(type);
00405 }
00406
00407 static void CleanNeighbours(BLOBNBOX_LIST* blobs);
00408
00409 static void DeleteNoiseBlobs(BLOBNBOX_LIST* blobs);
00410
00411 #ifndef GRAPHICS_DISABLED
00412
00413
00414 static void PlotBlobs(BLOBNBOX_LIST* list,
00415 ScrollView::Color body_colour,
00416 ScrollView::Color child_colour,
00417 ScrollView* win);
00418
00419
00420
00421 static void PlotNoiseBlobs(BLOBNBOX_LIST* list,
00422 ScrollView::Color body_colour,
00423 ScrollView::Color child_colour,
00424 ScrollView* win);
00425
00426 static ScrollView::Color TextlineColor(BlobRegionType region_type,
00427 BlobTextFlowType flow_type);
00428
00429
00430 ScrollView::Color BoxColor() const;
00431
00432 void plot(ScrollView* window,
00433 ScrollView::Color blob_colour,
00434 ScrollView::Color child_colour) {
00435 if (cblob_ptr != NULL)
00436 cblob_ptr->plot(window, blob_colour, child_colour);
00437 }
00438 #endif
00439
00440
00441
00442 void ConstructionInit() {
00443 cblob_ptr = NULL;
00444 area = 0;
00445 area_stroke_width_ = 0.0f;
00446 horz_stroke_width_ = 0.0f;
00447 vert_stroke_width_ = 0.0f;
00448 ReInit();
00449 }
00450
00451
00452 void ReInit() {
00453 joined = false;
00454 reduced = false;
00455 repeated_set_ = 0;
00456 left_tab_type_ = TT_NONE;
00457 right_tab_type_ = TT_NONE;
00458 region_type_ = BRT_UNKNOWN;
00459 flow_ = BTFT_NONE;
00460 spt_type_ = BSTT_SKIP;
00461 left_rule_ = 0;
00462 right_rule_ = 0;
00463 left_crossing_rule_ = 0;
00464 right_crossing_rule_ = 0;
00465 if (area_stroke_width_ == 0.0f && area > 0 && cblob() != NULL)
00466 area_stroke_width_ = 2.0f * area / cblob()->perimeter();
00467 owner_ = NULL;
00468 base_char_top_ = box.top();
00469 base_char_bottom_ = box.bottom();
00470 line_crossings_ = 0;
00471 base_char_blob_ = NULL;
00472 horz_possible_ = false;
00473 vert_possible_ = false;
00474 leader_on_left_ = false;
00475 leader_on_right_ = false;
00476 ClearNeighbours();
00477 }
00478
00479 void ClearNeighbours() {
00480 for (int n = 0; n < BND_COUNT; ++n) {
00481 neighbours_[n] = NULL;
00482 good_stroke_neighbours_[n] = false;
00483 }
00484 }
00485
00486 private:
00487 C_BLOB *cblob_ptr;
00488 TBOX box;
00489 TBOX red_box;
00490 int area:30;
00491 int joined:1;
00492 int reduced:1;
00493 int repeated_set_;
00494 TabType left_tab_type_;
00495 TabType right_tab_type_;
00496 BlobRegionType region_type_;
00497 BlobTextFlowType flow_;
00498 inT16 left_rule_;
00499 inT16 right_rule_;
00500 inT16 left_crossing_rule_;
00501 inT16 right_crossing_rule_;
00502 inT16 base_char_top_;
00503 inT16 base_char_bottom_;
00504 int line_crossings_;
00505 BLOBNBOX* base_char_blob_;
00506 float horz_stroke_width_;
00507 float vert_stroke_width_;
00508 float area_stroke_width_;
00509 tesseract::ColPartition* owner_;
00510 BlobSpecialTextType spt_type_;
00511 BLOBNBOX* neighbours_[BND_COUNT];
00512 bool good_stroke_neighbours_[BND_COUNT];
00513 bool horz_possible_;
00514 bool vert_possible_;
00515 bool leader_on_left_;
00516 bool leader_on_right_;
00517 };
00518
00519 class TO_ROW: public ELIST2_LINK
00520 {
00521 public:
00522 static const int kErrorWeight = 3;
00523
00524 TO_ROW() {
00525 clear();
00526 }
00527 TO_ROW(
00528 BLOBNBOX *blob,
00529 float top,
00530 float bottom,
00531 float row_size);
00532
00533 float max_y() const {
00534 return y_max;
00535 }
00536 float min_y() const {
00537 return y_min;
00538 }
00539 float mean_y() const {
00540 return (y_min + y_max) / 2.0f;
00541 }
00542 float initial_min_y() const {
00543 return initial_y_min;
00544 }
00545 float line_m() const {
00546 return m;
00547 }
00548 float line_c() const {
00549 return c;
00550 }
00551 float line_error() const {
00552 return error;
00553 }
00554 float parallel_c() const {
00555 return para_c;
00556 }
00557 float parallel_error() const {
00558 return para_error;
00559 }
00560 float believability() const {
00561 return credibility;
00562 }
00563 float intercept() const {
00564 return y_origin;
00565 }
00566 void add_blob(
00567 BLOBNBOX *blob,
00568 float top,
00569 float bottom,
00570 float row_size);
00571 void insert_blob(
00572 BLOBNBOX *blob);
00573
00574 BLOBNBOX_LIST *blob_list() {
00575 return &blobs;
00576 }
00577
00578 void set_line(
00579 float new_m,
00580 float new_c,
00581 float new_error) {
00582 m = new_m;
00583 c = new_c;
00584 error = new_error;
00585 }
00586 void set_parallel_line(
00587 float gradient,
00588 float new_c,
00589 float new_error) {
00590 para_c = new_c;
00591 para_error = new_error;
00592 credibility =
00593 (float) (blobs.length () - kErrorWeight * new_error);
00594 y_origin = (float) (new_c / sqrt (1 + gradient * gradient));
00595
00596 }
00597 void set_limits(
00598 float new_min,
00599 float new_max) {
00600 y_min = new_min;
00601 y_max = new_max;
00602 }
00603 void compute_vertical_projection();
00604
00605
00606 bool rep_chars_marked() const {
00607 return num_repeated_sets_ != -1;
00608 }
00609 void clear_rep_chars_marked() {
00610 num_repeated_sets_ = -1;
00611 }
00612 int num_repeated_sets() const {
00613 return num_repeated_sets_;
00614 }
00615 void set_num_repeated_sets(int num_sets) {
00616 num_repeated_sets_ = num_sets;
00617 }
00618
00619
00620 BOOL8 merged;
00621 BOOL8 all_caps;
00622 BOOL8 used_dm_model;
00623 inT16 projection_left;
00624 inT16 projection_right;
00625 PITCH_TYPE pitch_decision;
00626 float fixed_pitch;
00627 float fp_space;
00628 float fp_nonsp;
00629 float pr_space;
00630 float pr_nonsp;
00631 float spacing;
00632 float xheight;
00633 int xheight_evidence;
00634 float ascrise;
00635 float descdrop;
00636 float body_size;
00637
00638 inT32 min_space;
00639 inT32 max_nonspace;
00640 inT32 space_threshold;
00641 float kern_size;
00642 float space_size;
00643 WERD_LIST rep_words;
00644 ICOORDELT_LIST char_cells;
00645 QSPLINE baseline;
00646 STATS projection;
00647
00648 private:
00649 void clear();
00650
00651 BLOBNBOX_LIST blobs;
00652 float y_min;
00653 float y_max;
00654 float initial_y_min;
00655 float m, c;
00656 float error;
00657 float para_c;
00658 float para_error;
00659 float y_origin;
00660 float credibility;
00661 int num_repeated_sets_;
00662
00663
00664 };
00665
00666 ELIST2IZEH (TO_ROW)
00667 class TO_BLOCK:public ELIST_LINK
00668 {
00669 public:
00670 TO_BLOCK() : pitch_decision(PITCH_DUNNO) {
00671 clear();
00672 }
00673 TO_BLOCK(
00674 BLOCK *src_block);
00675 ~TO_BLOCK();
00676
00677 void clear();
00678
00679 TO_ROW_LIST *get_rows() {
00680 return &row_list;
00681 }
00682
00683
00684
00685 void rotate(const FCOORD& rotation) {
00686 BLOBNBOX_LIST* blobnbox_list[] = {&blobs, &underlines, &noise_blobs,
00687 &small_blobs, &large_blobs, NULL};
00688 for (BLOBNBOX_LIST** list = blobnbox_list; *list != NULL; ++list) {
00689 BLOBNBOX_IT it(*list);
00690 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
00691 it.data()->rotate(rotation);
00692 }
00693 }
00694
00695 ASSERT_HOST(block->poly_block() != NULL);
00696 block->rotate(rotation);
00697
00698 STATS widths(0, block->bounding_box().width());
00699 STATS heights(0, block->bounding_box().height());
00700 BLOBNBOX_IT blob_it(&blobs);
00701 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
00702 widths.add(blob_it.data()->bounding_box().width(), 1);
00703 heights.add(blob_it.data()->bounding_box().height(), 1);
00704 }
00705 block->set_median_size(static_cast<int>(widths.median() + 0.5),
00706 static_cast<int>(heights.median() + 0.5));
00707 }
00708
00709 void print_rows() {
00710 TO_ROW_IT row_it = &row_list;
00711 TO_ROW *row;
00712
00713 for (row_it.mark_cycle_pt (); !row_it.cycled_list ();
00714 row_it.forward ()) {
00715 row = row_it.data ();
00716 printf ("Row range (%g,%g), para_c=%g, blobcount=" INT32FORMAT
00717 "\n", row->min_y (), row->max_y (), row->parallel_c (),
00718 row->blob_list ()->length ());
00719 }
00720 }
00721
00722
00723
00724
00725
00726 void ReSetAndReFilterBlobs();
00727
00728
00729 void DeleteUnownedNoise();
00730
00731 #ifndef GRAPHICS_DISABLED
00732
00733 void plot_noise_blobs(ScrollView* to_win);
00734
00735 void plot_graded_blobs(ScrollView* to_win);
00736 #endif
00737
00738 BLOBNBOX_LIST blobs;
00739 BLOBNBOX_LIST underlines;
00740 BLOBNBOX_LIST noise_blobs;
00741 BLOBNBOX_LIST small_blobs;
00742 BLOBNBOX_LIST large_blobs;
00743 BLOCK *block;
00744 PITCH_TYPE pitch_decision;
00745 float line_spacing;
00746
00747
00748
00749
00750
00751 float line_size;
00752 float max_blob_size;
00753 float baseline_offset;
00754 float xheight;
00755 float fixed_pitch;
00756 float kern_size;
00757 float space_size;
00758 inT32 min_space;
00759 inT32 max_nonspace;
00760 float fp_space;
00761 float fp_nonsp;
00762 float pr_space;
00763 float pr_nonsp;
00764 TO_ROW *key_row;
00765
00766 private:
00767 TO_ROW_LIST row_list;
00768 };
00769
00770 ELISTIZEH (TO_BLOCK)
00771 extern double_VAR_H (textord_error_weight, 3,
00772 "Weighting for error in believability");
00773 void find_cblob_limits(
00774 C_BLOB *blob,
00775 float leftx,
00776 float rightx,
00777 FCOORD rotation,
00778 float &ymin,
00779 float &ymax);
00780 void find_cblob_vlimits(
00781 C_BLOB *blob,
00782 float leftx,
00783 float rightx,
00784 float &ymin,
00785 float &ymax);
00786 void find_cblob_hlimits(
00787 C_BLOB *blob,
00788 float bottomy,
00789 float topy,
00790 float &xmin,
00791 float &xymax);
00792 C_BLOB *crotate_cblob(
00793 C_BLOB *blob,
00794 FCOORD rotation
00795 );
00796 TBOX box_next(
00797 BLOBNBOX_IT *it
00798 );
00799 TBOX box_next_pre_chopped(
00800 BLOBNBOX_IT *it
00801 );
00802 void vertical_cblob_projection(
00803 C_BLOB *blob,
00804 STATS *stats
00805 );
00806 void vertical_coutline_projection(
00807 C_OUTLINE *outline,
00808 STATS *stats
00809 );
00810 #ifndef GRAPHICS_DISABLED
00811 void plot_blob_list(ScrollView* win,
00812 BLOBNBOX_LIST *list,
00813 ScrollView::Color body_colour,
00814 ScrollView::Color child_colour);
00815 #endif // GRAPHICS_DISABLED
00816 #endif