Tesseract
3.02
|
00001 /********************************************************************** 00002 * File: blobbox.h (Formerly blobnbox.h) 00003 * Description: Code for the textord blob class. 00004 * Author: Ray Smith 00005 * Created: Thu Jul 30 09:08:51 BST 1992 00006 * 00007 * (C) Copyright 1992, Hewlett-Packard Ltd. 00008 ** Licensed under the Apache License, Version 2.0 (the "License"); 00009 ** you may not use this file except in compliance with the License. 00010 ** You may obtain a copy of the License at 00011 ** http://www.apache.org/licenses/LICENSE-2.0 00012 ** Unless required by applicable law or agreed to in writing, software 00013 ** distributed under the License is distributed on an "AS IS" BASIS, 00014 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00015 ** See the License for the specific language governing permissions and 00016 ** limitations under the License. 00017 * 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, // insufficient data 00032 PITCH_DEF_FIXED, // definitely fixed 00033 PITCH_MAYBE_FIXED, // could be 00034 PITCH_DEF_PROP, 00035 PITCH_MAYBE_PROP, 00036 PITCH_CORR_FIXED, 00037 PITCH_CORR_PROP 00038 }; 00039 00040 // The possible tab-stop types of each side of a BLOBNBOX. 00041 // The ordering is important, as it is used for deleting dead-ends in the 00042 // search. ALIGNED, CONFIRMED and VLINE should remain greater than the 00043 // non-aligned, unset, or deleted members. 00044 enum TabType { 00045 TT_NONE, // Not a tab. 00046 TT_DELETED, // Not a tab after detailed analysis. 00047 TT_MAYBE_RAGGED, // Initial designation of a tab-stop candidate. 00048 TT_MAYBE_ALIGNED, // Initial designation of a tab-stop candidate. 00049 TT_CONFIRMED, // Aligned with neighbours. 00050 TT_VLINE // Detected as a vertical line. 00051 }; 00052 00053 // The possible region types of a BLOBNBOX. 00054 // Note: keep all the text types > BRT_UNKNOWN and all the image types less. 00055 // Keep in sync with kBlobTypes in colpartition.cpp and BoxColor, and the 00056 // *Type static functions below. 00057 enum BlobRegionType { 00058 BRT_NOISE, // Neither text nor image. 00059 BRT_HLINE, // Horizontal separator line. 00060 BRT_VLINE, // Vertical separator line. 00061 BRT_RECTIMAGE, // Rectangular image. 00062 BRT_POLYIMAGE, // Non-rectangular image. 00063 BRT_UNKNOWN, // Not determined yet. 00064 BRT_VERT_TEXT, // Vertical alignment, not necessarily vertically oriented. 00065 BRT_TEXT, // Convincing text. 00066 00067 BRT_COUNT // Number of possibilities. 00068 }; 00069 00070 // enum for elements of arrays that refer to neighbours. 00071 // NOTE: keep in this order, so ^2 can be used to flip direction. 00072 enum BlobNeighbourDir { 00073 BND_LEFT, 00074 BND_BELOW, 00075 BND_RIGHT, 00076 BND_ABOVE, 00077 BND_COUNT 00078 }; 00079 00080 // enum for special type of text characters, such as math symbol or italic. 00081 enum BlobSpecialTextType { 00082 BSTT_NONE, // No special. 00083 BSTT_ITALIC, // Italic style. 00084 BSTT_DIGIT, // Digit symbols. 00085 BSTT_MATH, // Mathmatical symobls (not including digit). 00086 BSTT_UNCLEAR, // Characters with low recognition rate. 00087 BSTT_SKIP, // Characters that we skip labeling (usually too small). 00088 BSTT_COUNT 00089 }; 00090 00091 inline BlobNeighbourDir DirOtherWay(BlobNeighbourDir dir) { 00092 return static_cast<BlobNeighbourDir>(dir ^ 2); 00093 } 00094 00095 // BlobTextFlowType indicates the quality of neighbouring information 00096 // related to a chain of connected components, either horizontally or 00097 // vertically. Also used by ColPartition for the collection of blobs 00098 // within, which should all have the same value in most cases. 00099 enum BlobTextFlowType { 00100 BTFT_NONE, // No text flow set yet. 00101 BTFT_NONTEXT, // Flow too poor to be likely text. 00102 BTFT_NEIGHBOURS, // Neighbours support flow in this direction. 00103 BTFT_CHAIN, // There is a weak chain of text in this direction. 00104 BTFT_STRONG_CHAIN, // There is a strong chain of text in this direction. 00105 BTFT_TEXT_ON_IMAGE, // There is a strong chain of text on an image. 00106 BTFT_LEADER, // Leader dots/dashes etc. 00107 BTFT_COUNT 00108 }; 00109 00110 // Returns true if type1 dominates type2 in a merge. Mostly determined by the 00111 // ordering of the enum, LEADER is weak and dominates nothing. 00112 // The function is anti-symmetric (t1 > t2) === !(t2 > t1), except that 00113 // this cannot be true if t1 == t2, so the result is undefined. 00114 inline bool DominatesInMerge(BlobTextFlowType type1, BlobTextFlowType type2) { 00115 // LEADER always loses. 00116 if (type1 == BTFT_LEADER) return false; 00117 if (type2 == BTFT_LEADER) return true; 00118 // With those out of the way, the ordering of the enum determines the result. 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 // Rotates the box and the underlying blob. 00146 void rotate(FCOORD rotation); 00147 00148 // Methods that act on the box without touching the underlying blob. 00149 // Reflect the box in the y-axis, leaving the underlying blob untouched. 00150 void reflect_box_in_y_axis(); 00151 // Rotates the box by the angle given by rotation. 00152 // If the blob is a diacritic, then only small rotations for skew 00153 // correction can be applied. 00154 void rotate_box(FCOORD rotation); 00155 // Moves just the box by the given vector. 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( // fake chop blob 00169 BLOBNBOX_IT *start_it, // location of this 00170 BLOBNBOX_IT *blob_it, // iterator 00171 FCOORD rotation, // for landscape 00172 float xheight); // line height 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 // Returns positive if there is at least one side neighbour that has a 00179 // similar stroke width and is not on the other side of a rule line. 00180 int GoodTextBlob() const; 00181 // Returns the number of side neighbours that are of type BRT_NOISE. 00182 int NoisyNeighbours() const; 00183 00184 // Returns true if the blob is noise and has no owner. 00185 bool DeletableNoise() const { 00186 return owner() == NULL && region_type() == BRT_NOISE; 00187 } 00188 00189 // Returns true, and sets vert_possible/horz_possible if the blob has some 00190 // feature that makes it individually appear to flow one way. 00191 // eg if it has a high aspect ratio, yet has a complex shape, such as a 00192 // joined word in Latin, Arabic, or Hindi, rather than being a -, I, l, 1. 00193 bool DefiniteIndividualFlow(); 00194 00195 // Returns true if there is no tabstop violation in merging this and other. 00196 bool ConfirmNoTabViolation(const BLOBNBOX& other) const; 00197 00198 // Returns true if other has a similar stroke width to this. 00199 bool MatchingStrokeWidth(const BLOBNBOX& other, 00200 double fractional_tolerance, 00201 double constant_tolerance) const; 00202 00203 // Returns a bounding box of the outline contained within the 00204 // given horizontal range. 00205 TBOX BoundsWithinLimits(int left, int right); 00206 00207 // Simple accessors. 00208 const TBOX& bounding_box() const { 00209 return box; 00210 } 00211 // Set the bounding box. Use with caution. 00212 // Normally use compute_bounding_box instead. 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 // Returns true if the region type is text. 00391 static bool IsTextType(BlobRegionType type) { 00392 return type == BRT_TEXT || type == BRT_VERT_TEXT; 00393 } 00394 // Returns true if the region type is image. 00395 static bool IsImageType(BlobRegionType type) { 00396 return type == BRT_RECTIMAGE || type == BRT_POLYIMAGE; 00397 } 00398 // Returns true if the region type is line. 00399 static bool IsLineType(BlobRegionType type) { 00400 return type == BRT_HLINE || type == BRT_VLINE; 00401 } 00402 // Returns true if the region type cannot be merged. 00403 static bool UnMergeableType(BlobRegionType type) { 00404 return IsLineType(type) || IsImageType(type); 00405 } 00406 // Helper to call CleanNeighbours on all blobs on the list. 00407 static void CleanNeighbours(BLOBNBOX_LIST* blobs); 00408 // Helper to delete all the deletable blobs on the list. 00409 static void DeleteNoiseBlobs(BLOBNBOX_LIST* blobs); 00410 00411 #ifndef GRAPHICS_DISABLED 00412 // Helper to draw all the blobs on the list in the given body_colour, 00413 // with child outlines in the child_colour. 00414 static void PlotBlobs(BLOBNBOX_LIST* list, 00415 ScrollView::Color body_colour, 00416 ScrollView::Color child_colour, 00417 ScrollView* win); 00418 // Helper to draw only DeletableNoise blobs (unowned, BRT_NOISE) on the 00419 // given list in the given body_colour, with child outlines in the 00420 // child_colour. 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 // Keep in sync with BlobRegionType. 00430 ScrollView::Color BoxColor() const; 00431 00432 void plot(ScrollView* window, // window to draw in 00433 ScrollView::Color blob_colour, // for outer bits 00434 ScrollView::Color child_colour) { // for holes 00435 if (cblob_ptr != NULL) 00436 cblob_ptr->plot(window, blob_colour, child_colour); 00437 } 00438 #endif 00439 00440 // Initializes the bulk of the members to default values for use at 00441 // construction time. 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 // Initializes members set by StrokeWidth and beyond, without discarding 00451 // stored area and strokewidth values, which are expensive to calculate. 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; // edgestep blob 00488 TBOX box; // bounding box 00489 TBOX red_box; // bounding box 00490 int area:30; // enclosed area 00491 int joined:1; // joined to prev 00492 int reduced:1; // reduced box set 00493 int repeated_set_; // id of the set of repeated blobs 00494 TabType left_tab_type_; // Indicates tab-stop assessment 00495 TabType right_tab_type_; // Indicates tab-stop assessment 00496 BlobRegionType region_type_; // Type of region this blob belongs to 00497 BlobTextFlowType flow_; // Quality of text flow. 00498 inT16 left_rule_; // x-coord of nearest but not crossing rule line 00499 inT16 right_rule_; // x-coord of nearest but not crossing rule line 00500 inT16 left_crossing_rule_; // x-coord of nearest or crossing rule line 00501 inT16 right_crossing_rule_; // x-coord of nearest or crossing rule line 00502 inT16 base_char_top_; // y-coord of top/bottom of diacritic base, 00503 inT16 base_char_bottom_; // if it exists else top/bottom of this blob. 00504 int line_crossings_; // Number of line intersections touched. 00505 BLOBNBOX* base_char_blob_; // The blob that was the base char. 00506 float horz_stroke_width_; // Median horizontal stroke width 00507 float vert_stroke_width_; // Median vertical stroke width 00508 float area_stroke_width_; // Stroke width from area/perimeter ratio. 00509 tesseract::ColPartition* owner_; // Who will delete me when I am not needed 00510 BlobSpecialTextType spt_type_; // Special text type. 00511 BLOBNBOX* neighbours_[BND_COUNT]; 00512 bool good_stroke_neighbours_[BND_COUNT]; 00513 bool horz_possible_; // Could be part of horizontal flow. 00514 bool vert_possible_; // Could be part of vertical flow. 00515 bool leader_on_left_; // There is a leader to the left. 00516 bool leader_on_right_; // There is a leader to the 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 } //empty 00527 TO_ROW( //constructor 00528 BLOBNBOX *blob, //from first blob 00529 float top, //of row //target height 00530 float bottom, 00531 float row_size); 00532 00533 float max_y() const { //access function 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 { //access to line fit 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 { //baseline goodness 00561 return credibility; 00562 } 00563 float intercept() const { //real parallel_c 00564 return y_origin; 00565 } 00566 void add_blob( //put in row 00567 BLOBNBOX *blob, //blob to add 00568 float top, //of row //target height 00569 float bottom, 00570 float row_size); 00571 void insert_blob( //put in row in order 00572 BLOBNBOX *blob); 00573 00574 BLOBNBOX_LIST *blob_list() { //get list 00575 return &blobs; 00576 } 00577 00578 void set_line( //set line spec 00579 float new_m, //line to set 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( //set fixed gradient line 00587 float gradient, //page 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 //real intercept 00596 } 00597 void set_limits( //set min,max 00598 float new_min, //bottom and 00599 float new_max) { //top of row 00600 y_min = new_min; 00601 y_max = new_max; 00602 } 00603 void compute_vertical_projection(); 00604 //get projection 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 // true when dead 00620 BOOL8 merged; 00621 BOOL8 all_caps; // had no ascenders 00622 BOOL8 used_dm_model; // in guessing pitch 00623 inT16 projection_left; // start of projection 00624 inT16 projection_right; // start of projection 00625 PITCH_TYPE pitch_decision; // how strong is decision 00626 float fixed_pitch; // pitch or 0 00627 float fp_space; // sp if fixed pitch 00628 float fp_nonsp; // nonsp if fixed pitch 00629 float pr_space; // sp if prop 00630 float pr_nonsp; // non sp if prop 00631 float spacing; // to "next" row 00632 float xheight; // of line 00633 int xheight_evidence; // number of blobs of height xheight 00634 float ascrise; // ascenders 00635 float descdrop; // descenders 00636 float body_size; // of CJK characters. Assumed to be 00637 // xheight+ascrise for non-CJK text. 00638 inT32 min_space; // min size for real space 00639 inT32 max_nonspace; // max size of non-space 00640 inT32 space_threshold; // space vs nonspace 00641 float kern_size; // average non-space 00642 float space_size; // average space 00643 WERD_LIST rep_words; // repeated chars 00644 ICOORDELT_LIST char_cells; // fixed pitch cells 00645 QSPLINE baseline; // curved baseline 00646 STATS projection; // vertical projection 00647 00648 private: 00649 void clear(); // clear all values to reasonable defaults 00650 00651 BLOBNBOX_LIST blobs; //blobs in row 00652 float y_min; //coords 00653 float y_max; 00654 float initial_y_min; 00655 float m, c; //line spec 00656 float error; //line error 00657 float para_c; //constrained fit 00658 float para_error; 00659 float y_origin; //rotated para_c; 00660 float credibility; //baseline believability 00661 int num_repeated_sets_; // number of sets of repeated blobs 00662 // set to -1 if we have not searched 00663 // for repeated blobs in this row yet 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 } //empty 00673 TO_BLOCK( //constructor 00674 BLOCK *src_block); //real block 00675 ~TO_BLOCK(); 00676 00677 void clear(); // clear all scalar members. 00678 00679 TO_ROW_LIST *get_rows() { //access function 00680 return &row_list; 00681 } 00682 00683 // Rotate all the blobnbox lists and the underlying block. Then update the 00684 // median size statistic from the blobs list. 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 // Rotate the block 00695 ASSERT_HOST(block->poly_block() != NULL); 00696 block->rotate(rotation); 00697 // Update the median size statistic from the blobs list. 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() { //debug info 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 // Reorganizes the blob lists with a different definition of small, medium 00723 // and large, compared to the original definition. 00724 // Height is still the primary filter key, but medium width blobs of small 00725 // height become medium, and very wide blobs of small height stay small. 00726 void ReSetAndReFilterBlobs(); 00727 00728 // Deletes noise blobs from all lists where not owned by a ColPartition. 00729 void DeleteUnownedNoise(); 00730 00731 #ifndef GRAPHICS_DISABLED 00732 // Draw the noise blobs from all lists in red. 00733 void plot_noise_blobs(ScrollView* to_win); 00734 // Draw the blobs on on the various lists in the block in different colors. 00735 void plot_graded_blobs(ScrollView* to_win); 00736 #endif 00737 00738 BLOBNBOX_LIST blobs; //medium size 00739 BLOBNBOX_LIST underlines; //underline blobs 00740 BLOBNBOX_LIST noise_blobs; //very small 00741 BLOBNBOX_LIST small_blobs; //fairly small 00742 BLOBNBOX_LIST large_blobs; //big blobs 00743 BLOCK *block; //real block 00744 PITCH_TYPE pitch_decision; //how strong is decision 00745 float line_spacing; //estimate 00746 // line_size is a lower-bound estimate of the font size in pixels of 00747 // the text in the block (with ascenders and descenders), being a small 00748 // (1.25) multiple of the median height of filtered blobs. 00749 // In most cases the font size will be bigger, but it will be closer 00750 // if the text is allcaps, or in a no-x-height script. 00751 float line_size; //estimate 00752 float max_blob_size; //line assignment limit 00753 float baseline_offset; //phase shift 00754 float xheight; //median blob size 00755 float fixed_pitch; //pitch or 0 00756 float kern_size; //average non-space 00757 float space_size; //average space 00758 inT32 min_space; //min definite space 00759 inT32 max_nonspace; //max definite 00760 float fp_space; //sp if fixed pitch 00761 float fp_nonsp; //nonsp if fixed pitch 00762 float pr_space; //sp if prop 00763 float pr_nonsp; //non sp if prop 00764 TO_ROW *key_row; //starting row 00765 00766 private: 00767 TO_ROW_LIST row_list; //temporary rows 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( //get y limits 00774 C_BLOB *blob, //blob to search 00775 float leftx, //x limits 00776 float rightx, 00777 FCOORD rotation, //for landscape 00778 float &ymin, //output y limits 00779 float &ymax); 00780 void find_cblob_vlimits( //get y limits 00781 C_BLOB *blob, //blob to search 00782 float leftx, //x limits 00783 float rightx, 00784 float &ymin, //output y limits 00785 float &ymax); 00786 void find_cblob_hlimits( //get x limits 00787 C_BLOB *blob, //blob to search 00788 float bottomy, //y limits 00789 float topy, 00790 float &xmin, //output x limits 00791 float &xymax); 00792 C_BLOB *crotate_cblob( //rotate it 00793 C_BLOB *blob, //blob to search 00794 FCOORD rotation //for landscape 00795 ); 00796 TBOX box_next( //get bounding box 00797 BLOBNBOX_IT *it //iterator to blobds 00798 ); 00799 TBOX box_next_pre_chopped( //get bounding box 00800 BLOBNBOX_IT *it //iterator to blobds 00801 ); 00802 void vertical_cblob_projection( //project outlines 00803 C_BLOB *blob, //blob to project 00804 STATS *stats //output 00805 ); 00806 void vertical_coutline_projection( //project outlines 00807 C_OUTLINE *outline, //outline to project 00808 STATS *stats //output 00809 ); 00810 #ifndef GRAPHICS_DISABLED 00811 void plot_blob_list(ScrollView* win, // window to draw in 00812 BLOBNBOX_LIST *list, // blob list 00813 ScrollView::Color body_colour, // colour to draw 00814 ScrollView::Color child_colour); // colour of child 00815 #endif // GRAPHICS_DISABLED 00816 #endif