tesseract
3.03
|
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 // Estimates and stores the baseline position based on the shape of the 00208 // outline. 00209 void EstimateBaselinePosition(); 00210 00211 // Simple accessors. 00212 const TBOX& bounding_box() const { 00213 return box; 00214 } 00215 // Set the bounding box. Use with caution. 00216 // Normally use compute_bounding_box instead. 00217 void set_bounding_box(const TBOX& new_box) { 00218 box = new_box; 00219 base_char_top_ = box.top(); 00220 base_char_bottom_ = box.bottom(); 00221 } 00222 void compute_bounding_box() { 00223 box = cblob_ptr->bounding_box(); 00224 base_char_top_ = box.top(); 00225 base_char_bottom_ = box.bottom(); 00226 baseline_y_ = box.bottom(); 00227 } 00228 const TBOX& reduced_box() const { 00229 return red_box; 00230 } 00231 void set_reduced_box(TBOX new_box) { 00232 red_box = new_box; 00233 reduced = TRUE; 00234 } 00235 inT32 enclosed_area() const { 00236 return area; 00237 } 00238 bool joined_to_prev() const { 00239 return joined != 0; 00240 } 00241 bool red_box_set() const { 00242 return reduced != 0; 00243 } 00244 int repeated_set() const { 00245 return repeated_set_; 00246 } 00247 void set_repeated_set(int set_id) { 00248 repeated_set_ = set_id; 00249 } 00250 C_BLOB *cblob() const { 00251 return cblob_ptr; 00252 } 00253 TabType left_tab_type() const { 00254 return left_tab_type_; 00255 } 00256 void set_left_tab_type(TabType new_type) { 00257 left_tab_type_ = new_type; 00258 } 00259 TabType right_tab_type() const { 00260 return right_tab_type_; 00261 } 00262 void set_right_tab_type(TabType new_type) { 00263 right_tab_type_ = new_type; 00264 } 00265 BlobRegionType region_type() const { 00266 return region_type_; 00267 } 00268 void set_region_type(BlobRegionType new_type) { 00269 region_type_ = new_type; 00270 } 00271 BlobSpecialTextType special_text_type() const { 00272 return spt_type_; 00273 } 00274 void set_special_text_type(BlobSpecialTextType new_type) { 00275 spt_type_ = new_type; 00276 } 00277 BlobTextFlowType flow() const { 00278 return flow_; 00279 } 00280 void set_flow(BlobTextFlowType value) { 00281 flow_ = value; 00282 } 00283 bool vert_possible() const { 00284 return vert_possible_; 00285 } 00286 void set_vert_possible(bool value) { 00287 vert_possible_ = value; 00288 } 00289 bool horz_possible() const { 00290 return horz_possible_; 00291 } 00292 void set_horz_possible(bool value) { 00293 horz_possible_ = value; 00294 } 00295 int left_rule() const { 00296 return left_rule_; 00297 } 00298 void set_left_rule(int new_left) { 00299 left_rule_ = new_left; 00300 } 00301 int right_rule() const { 00302 return right_rule_; 00303 } 00304 void set_right_rule(int new_right) { 00305 right_rule_ = new_right; 00306 } 00307 int left_crossing_rule() const { 00308 return left_crossing_rule_; 00309 } 00310 void set_left_crossing_rule(int new_left) { 00311 left_crossing_rule_ = new_left; 00312 } 00313 int right_crossing_rule() const { 00314 return right_crossing_rule_; 00315 } 00316 void set_right_crossing_rule(int new_right) { 00317 right_crossing_rule_ = new_right; 00318 } 00319 float horz_stroke_width() const { 00320 return horz_stroke_width_; 00321 } 00322 void set_horz_stroke_width(float width) { 00323 horz_stroke_width_ = width; 00324 } 00325 float vert_stroke_width() const { 00326 return vert_stroke_width_; 00327 } 00328 void set_vert_stroke_width(float width) { 00329 vert_stroke_width_ = width; 00330 } 00331 float area_stroke_width() const { 00332 return area_stroke_width_; 00333 } 00334 tesseract::ColPartition* owner() const { 00335 return owner_; 00336 } 00337 void set_owner(tesseract::ColPartition* new_owner) { 00338 owner_ = new_owner; 00339 } 00340 bool leader_on_left() const { 00341 return leader_on_left_; 00342 } 00343 void set_leader_on_left(bool flag) { 00344 leader_on_left_ = flag; 00345 } 00346 bool leader_on_right() const { 00347 return leader_on_right_; 00348 } 00349 void set_leader_on_right(bool flag) { 00350 leader_on_right_ = flag; 00351 } 00352 BLOBNBOX* neighbour(BlobNeighbourDir n) const { 00353 return neighbours_[n]; 00354 } 00355 bool good_stroke_neighbour(BlobNeighbourDir n) const { 00356 return good_stroke_neighbours_[n]; 00357 } 00358 void set_neighbour(BlobNeighbourDir n, BLOBNBOX* neighbour, bool good) { 00359 neighbours_[n] = neighbour; 00360 good_stroke_neighbours_[n] = good; 00361 } 00362 bool IsDiacritic() const { 00363 return base_char_top_ != box.top() || base_char_bottom_ != box.bottom(); 00364 } 00365 int base_char_top() const { 00366 return base_char_top_; 00367 } 00368 int base_char_bottom() const { 00369 return base_char_bottom_; 00370 } 00371 int baseline_position() const { 00372 return baseline_y_; 00373 } 00374 int line_crossings() const { 00375 return line_crossings_; 00376 } 00377 void set_line_crossings(int value) { 00378 line_crossings_ = value; 00379 } 00380 void set_diacritic_box(const TBOX& diacritic_box) { 00381 base_char_top_ = diacritic_box.top(); 00382 base_char_bottom_ = diacritic_box.bottom(); 00383 } 00384 BLOBNBOX* base_char_blob() const { 00385 return base_char_blob_; 00386 } 00387 void set_base_char_blob(BLOBNBOX* blob) { 00388 base_char_blob_ = blob; 00389 } 00390 00391 bool UniquelyVertical() const { 00392 return vert_possible_ && !horz_possible_; 00393 } 00394 bool UniquelyHorizontal() const { 00395 return horz_possible_ && !vert_possible_; 00396 } 00397 00398 // Returns true if the region type is text. 00399 static bool IsTextType(BlobRegionType type) { 00400 return type == BRT_TEXT || type == BRT_VERT_TEXT; 00401 } 00402 // Returns true if the region type is image. 00403 static bool IsImageType(BlobRegionType type) { 00404 return type == BRT_RECTIMAGE || type == BRT_POLYIMAGE; 00405 } 00406 // Returns true if the region type is line. 00407 static bool IsLineType(BlobRegionType type) { 00408 return type == BRT_HLINE || type == BRT_VLINE; 00409 } 00410 // Returns true if the region type cannot be merged. 00411 static bool UnMergeableType(BlobRegionType type) { 00412 return IsLineType(type) || IsImageType(type); 00413 } 00414 // Helper to call CleanNeighbours on all blobs on the list. 00415 static void CleanNeighbours(BLOBNBOX_LIST* blobs); 00416 // Helper to delete all the deletable blobs on the list. 00417 static void DeleteNoiseBlobs(BLOBNBOX_LIST* blobs); 00418 // Helper to compute edge offsets for all the blobs on the list. 00419 // See coutln.h for an explanation of edge offsets. 00420 static void ComputeEdgeOffsets(Pix* thresholds, Pix* grey, 00421 BLOBNBOX_LIST* blobs); 00422 00423 #ifndef GRAPHICS_DISABLED 00424 // Helper to draw all the blobs on the list in the given body_colour, 00425 // with child outlines in the child_colour. 00426 static void PlotBlobs(BLOBNBOX_LIST* list, 00427 ScrollView::Color body_colour, 00428 ScrollView::Color child_colour, 00429 ScrollView* win); 00430 // Helper to draw only DeletableNoise blobs (unowned, BRT_NOISE) on the 00431 // given list in the given body_colour, with child outlines in the 00432 // child_colour. 00433 static void PlotNoiseBlobs(BLOBNBOX_LIST* list, 00434 ScrollView::Color body_colour, 00435 ScrollView::Color child_colour, 00436 ScrollView* win); 00437 00438 static ScrollView::Color TextlineColor(BlobRegionType region_type, 00439 BlobTextFlowType flow_type); 00440 00441 // Keep in sync with BlobRegionType. 00442 ScrollView::Color BoxColor() const; 00443 00444 void plot(ScrollView* window, // window to draw in 00445 ScrollView::Color blob_colour, // for outer bits 00446 ScrollView::Color child_colour); // for holes 00447 #endif 00448 00449 // Initializes the bulk of the members to default values for use at 00450 // construction time. 00451 void ConstructionInit() { 00452 cblob_ptr = NULL; 00453 area = 0; 00454 area_stroke_width_ = 0.0f; 00455 horz_stroke_width_ = 0.0f; 00456 vert_stroke_width_ = 0.0f; 00457 ReInit(); 00458 } 00459 // Initializes members set by StrokeWidth and beyond, without discarding 00460 // stored area and strokewidth values, which are expensive to calculate. 00461 void ReInit() { 00462 joined = false; 00463 reduced = false; 00464 repeated_set_ = 0; 00465 left_tab_type_ = TT_NONE; 00466 right_tab_type_ = TT_NONE; 00467 region_type_ = BRT_UNKNOWN; 00468 flow_ = BTFT_NONE; 00469 spt_type_ = BSTT_SKIP; 00470 left_rule_ = 0; 00471 right_rule_ = 0; 00472 left_crossing_rule_ = 0; 00473 right_crossing_rule_ = 0; 00474 if (area_stroke_width_ == 0.0f && area > 0 && cblob() != NULL) 00475 area_stroke_width_ = 2.0f * area / cblob()->perimeter(); 00476 owner_ = NULL; 00477 base_char_top_ = box.top(); 00478 base_char_bottom_ = box.bottom(); 00479 baseline_y_ = box.bottom(); 00480 line_crossings_ = 0; 00481 base_char_blob_ = NULL; 00482 horz_possible_ = false; 00483 vert_possible_ = false; 00484 leader_on_left_ = false; 00485 leader_on_right_ = false; 00486 ClearNeighbours(); 00487 } 00488 00489 void ClearNeighbours() { 00490 for (int n = 0; n < BND_COUNT; ++n) { 00491 neighbours_[n] = NULL; 00492 good_stroke_neighbours_[n] = false; 00493 } 00494 } 00495 00496 private: 00497 C_BLOB *cblob_ptr; // edgestep blob 00498 TBOX box; // bounding box 00499 TBOX red_box; // bounding box 00500 int area:30; // enclosed area 00501 int joined:1; // joined to prev 00502 int reduced:1; // reduced box set 00503 int repeated_set_; // id of the set of repeated blobs 00504 TabType left_tab_type_; // Indicates tab-stop assessment 00505 TabType right_tab_type_; // Indicates tab-stop assessment 00506 BlobRegionType region_type_; // Type of region this blob belongs to 00507 BlobTextFlowType flow_; // Quality of text flow. 00508 inT16 left_rule_; // x-coord of nearest but not crossing rule line 00509 inT16 right_rule_; // x-coord of nearest but not crossing rule line 00510 inT16 left_crossing_rule_; // x-coord of nearest or crossing rule line 00511 inT16 right_crossing_rule_; // x-coord of nearest or crossing rule line 00512 inT16 base_char_top_; // y-coord of top/bottom of diacritic base, 00513 inT16 base_char_bottom_; // if it exists else top/bottom of this blob. 00514 inT16 baseline_y_; // Estimate of baseline position. 00515 int line_crossings_; // Number of line intersections touched. 00516 BLOBNBOX* base_char_blob_; // The blob that was the base char. 00517 float horz_stroke_width_; // Median horizontal stroke width 00518 float vert_stroke_width_; // Median vertical stroke width 00519 float area_stroke_width_; // Stroke width from area/perimeter ratio. 00520 tesseract::ColPartition* owner_; // Who will delete me when I am not needed 00521 BlobSpecialTextType spt_type_; // Special text type. 00522 BLOBNBOX* neighbours_[BND_COUNT]; 00523 bool good_stroke_neighbours_[BND_COUNT]; 00524 bool horz_possible_; // Could be part of horizontal flow. 00525 bool vert_possible_; // Could be part of vertical flow. 00526 bool leader_on_left_; // There is a leader to the left. 00527 bool leader_on_right_; // There is a leader to the right. 00528 }; 00529 00530 class TO_ROW: public ELIST2_LINK 00531 { 00532 public: 00533 static const int kErrorWeight = 3; 00534 00535 TO_ROW() { 00536 clear(); 00537 } //empty 00538 TO_ROW( //constructor 00539 BLOBNBOX *blob, //from first blob 00540 float top, //of row //target height 00541 float bottom, 00542 float row_size); 00543 00544 void print() const; 00545 float max_y() const { //access function 00546 return y_max; 00547 } 00548 float min_y() const { 00549 return y_min; 00550 } 00551 float mean_y() const { 00552 return (y_min + y_max) / 2.0f; 00553 } 00554 float initial_min_y() const { 00555 return initial_y_min; 00556 } 00557 float line_m() const { //access to line fit 00558 return m; 00559 } 00560 float line_c() const { 00561 return c; 00562 } 00563 float line_error() const { 00564 return error; 00565 } 00566 float parallel_c() const { 00567 return para_c; 00568 } 00569 float parallel_error() const { 00570 return para_error; 00571 } 00572 float believability() const { //baseline goodness 00573 return credibility; 00574 } 00575 float intercept() const { //real parallel_c 00576 return y_origin; 00577 } 00578 void add_blob( //put in row 00579 BLOBNBOX *blob, //blob to add 00580 float top, //of row //target height 00581 float bottom, 00582 float row_size); 00583 void insert_blob( //put in row in order 00584 BLOBNBOX *blob); 00585 00586 BLOBNBOX_LIST *blob_list() { //get list 00587 return &blobs; 00588 } 00589 00590 void set_line( //set line spec 00591 float new_m, //line to set 00592 float new_c, 00593 float new_error) { 00594 m = new_m; 00595 c = new_c; 00596 error = new_error; 00597 } 00598 void set_parallel_line( //set fixed gradient line 00599 float gradient, //page gradient 00600 float new_c, 00601 float new_error) { 00602 para_c = new_c; 00603 para_error = new_error; 00604 credibility = 00605 (float) (blobs.length () - kErrorWeight * new_error); 00606 y_origin = (float) (new_c / sqrt (1 + gradient * gradient)); 00607 //real intercept 00608 } 00609 void set_limits( //set min,max 00610 float new_min, //bottom and 00611 float new_max) { //top of row 00612 y_min = new_min; 00613 y_max = new_max; 00614 } 00615 void compute_vertical_projection(); 00616 //get projection 00617 00618 bool rep_chars_marked() const { 00619 return num_repeated_sets_ != -1; 00620 } 00621 void clear_rep_chars_marked() { 00622 num_repeated_sets_ = -1; 00623 } 00624 int num_repeated_sets() const { 00625 return num_repeated_sets_; 00626 } 00627 void set_num_repeated_sets(int num_sets) { 00628 num_repeated_sets_ = num_sets; 00629 } 00630 00631 // true when dead 00632 BOOL8 merged; 00633 BOOL8 all_caps; // had no ascenders 00634 BOOL8 used_dm_model; // in guessing pitch 00635 inT16 projection_left; // start of projection 00636 inT16 projection_right; // start of projection 00637 PITCH_TYPE pitch_decision; // how strong is decision 00638 float fixed_pitch; // pitch or 0 00639 float fp_space; // sp if fixed pitch 00640 float fp_nonsp; // nonsp if fixed pitch 00641 float pr_space; // sp if prop 00642 float pr_nonsp; // non sp if prop 00643 float spacing; // to "next" row 00644 float xheight; // of line 00645 int xheight_evidence; // number of blobs of height xheight 00646 float ascrise; // ascenders 00647 float descdrop; // descenders 00648 float body_size; // of CJK characters. Assumed to be 00649 // xheight+ascrise for non-CJK text. 00650 inT32 min_space; // min size for real space 00651 inT32 max_nonspace; // max size of non-space 00652 inT32 space_threshold; // space vs nonspace 00653 float kern_size; // average non-space 00654 float space_size; // average space 00655 WERD_LIST rep_words; // repeated chars 00656 ICOORDELT_LIST char_cells; // fixed pitch cells 00657 QSPLINE baseline; // curved baseline 00658 STATS projection; // vertical projection 00659 00660 private: 00661 void clear(); // clear all values to reasonable defaults 00662 00663 BLOBNBOX_LIST blobs; //blobs in row 00664 float y_min; //coords 00665 float y_max; 00666 float initial_y_min; 00667 float m, c; //line spec 00668 float error; //line error 00669 float para_c; //constrained fit 00670 float para_error; 00671 float y_origin; //rotated para_c; 00672 float credibility; //baseline believability 00673 int num_repeated_sets_; // number of sets of repeated blobs 00674 // set to -1 if we have not searched 00675 // for repeated blobs in this row yet 00676 }; 00677 00678 ELIST2IZEH (TO_ROW) 00679 class TO_BLOCK:public ELIST_LINK 00680 { 00681 public: 00682 TO_BLOCK() : pitch_decision(PITCH_DUNNO) { 00683 clear(); 00684 } //empty 00685 TO_BLOCK( //constructor 00686 BLOCK *src_block); //real block 00687 ~TO_BLOCK(); 00688 00689 void clear(); // clear all scalar members. 00690 00691 TO_ROW_LIST *get_rows() { //access function 00692 return &row_list; 00693 } 00694 00695 // Rotate all the blobnbox lists and the underlying block. Then update the 00696 // median size statistic from the blobs list. 00697 void rotate(const FCOORD& rotation) { 00698 BLOBNBOX_LIST* blobnbox_list[] = {&blobs, &underlines, &noise_blobs, 00699 &small_blobs, &large_blobs, NULL}; 00700 for (BLOBNBOX_LIST** list = blobnbox_list; *list != NULL; ++list) { 00701 BLOBNBOX_IT it(*list); 00702 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) { 00703 it.data()->rotate(rotation); 00704 } 00705 } 00706 // Rotate the block 00707 ASSERT_HOST(block->poly_block() != NULL); 00708 block->rotate(rotation); 00709 // Update the median size statistic from the blobs list. 00710 STATS widths(0, block->bounding_box().width()); 00711 STATS heights(0, block->bounding_box().height()); 00712 BLOBNBOX_IT blob_it(&blobs); 00713 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) { 00714 widths.add(blob_it.data()->bounding_box().width(), 1); 00715 heights.add(blob_it.data()->bounding_box().height(), 1); 00716 } 00717 block->set_median_size(static_cast<int>(widths.median() + 0.5), 00718 static_cast<int>(heights.median() + 0.5)); 00719 } 00720 00721 void print_rows() { //debug info 00722 TO_ROW_IT row_it = &row_list; 00723 TO_ROW *row; 00724 00725 for (row_it.mark_cycle_pt(); !row_it.cycled_list(); 00726 row_it.forward()) { 00727 row = row_it.data(); 00728 tprintf("Row range (%g,%g), para_c=%g, blobcount=" INT32FORMAT 00729 "\n", row->min_y(), row->max_y(), row->parallel_c(), 00730 row->blob_list()->length()); 00731 } 00732 } 00733 00734 // Reorganizes the blob lists with a different definition of small, medium 00735 // and large, compared to the original definition. 00736 // Height is still the primary filter key, but medium width blobs of small 00737 // height become medium, and very wide blobs of small height stay small. 00738 void ReSetAndReFilterBlobs(); 00739 00740 // Deletes noise blobs from all lists where not owned by a ColPartition. 00741 void DeleteUnownedNoise(); 00742 00743 // Computes and stores the edge offsets on each blob for use in feature 00744 // extraction, using greyscale if the supplied grey and thresholds pixes 00745 // are 8-bit or otherwise (if NULL or not 8 bit) the original binary 00746 // edge step outlines. 00747 // Thresholds must either be the same size as grey or an integer down-scale 00748 // of grey. 00749 // See coutln.h for an explanation of edge offsets. 00750 void ComputeEdgeOffsets(Pix* thresholds, Pix* grey); 00751 00752 #ifndef GRAPHICS_DISABLED 00753 // Draw the noise blobs from all lists in red. 00754 void plot_noise_blobs(ScrollView* to_win); 00755 // Draw the blobs on on the various lists in the block in different colors. 00756 void plot_graded_blobs(ScrollView* to_win); 00757 #endif 00758 00759 BLOBNBOX_LIST blobs; //medium size 00760 BLOBNBOX_LIST underlines; //underline blobs 00761 BLOBNBOX_LIST noise_blobs; //very small 00762 BLOBNBOX_LIST small_blobs; //fairly small 00763 BLOBNBOX_LIST large_blobs; //big blobs 00764 BLOCK *block; //real block 00765 PITCH_TYPE pitch_decision; //how strong is decision 00766 float line_spacing; //estimate 00767 // line_size is a lower-bound estimate of the font size in pixels of 00768 // the text in the block (with ascenders and descenders), being a small 00769 // (1.25) multiple of the median height of filtered blobs. 00770 // In most cases the font size will be bigger, but it will be closer 00771 // if the text is allcaps, or in a no-x-height script. 00772 float line_size; //estimate 00773 float max_blob_size; //line assignment limit 00774 float baseline_offset; //phase shift 00775 float xheight; //median blob size 00776 float fixed_pitch; //pitch or 0 00777 float kern_size; //average non-space 00778 float space_size; //average space 00779 inT32 min_space; //min definite space 00780 inT32 max_nonspace; //max definite 00781 float fp_space; //sp if fixed pitch 00782 float fp_nonsp; //nonsp if fixed pitch 00783 float pr_space; //sp if prop 00784 float pr_nonsp; //non sp if prop 00785 TO_ROW *key_row; //starting row 00786 00787 private: 00788 TO_ROW_LIST row_list; //temporary rows 00789 }; 00790 00791 ELISTIZEH (TO_BLOCK) 00792 extern double_VAR_H (textord_error_weight, 3, 00793 "Weighting for error in believability"); 00794 void find_cblob_limits( //get y limits 00795 C_BLOB *blob, //blob to search 00796 float leftx, //x limits 00797 float rightx, 00798 FCOORD rotation, //for landscape 00799 float &ymin, //output y limits 00800 float &ymax); 00801 void find_cblob_vlimits( //get y limits 00802 C_BLOB *blob, //blob to search 00803 float leftx, //x limits 00804 float rightx, 00805 float &ymin, //output y limits 00806 float &ymax); 00807 void find_cblob_hlimits( //get x limits 00808 C_BLOB *blob, //blob to search 00809 float bottomy, //y limits 00810 float topy, 00811 float &xmin, //output x limits 00812 float &xymax); 00813 C_BLOB *crotate_cblob( //rotate it 00814 C_BLOB *blob, //blob to search 00815 FCOORD rotation //for landscape 00816 ); 00817 TBOX box_next( //get bounding box 00818 BLOBNBOX_IT *it //iterator to blobds 00819 ); 00820 TBOX box_next_pre_chopped( //get bounding box 00821 BLOBNBOX_IT *it //iterator to blobds 00822 ); 00823 void vertical_cblob_projection( //project outlines 00824 C_BLOB *blob, //blob to project 00825 STATS *stats //output 00826 ); 00827 void vertical_coutline_projection( //project outlines 00828 C_OUTLINE *outline, //outline to project 00829 STATS *stats //output 00830 ); 00831 #ifndef GRAPHICS_DISABLED 00832 void plot_blob_list(ScrollView* win, // window to draw in 00833 BLOBNBOX_LIST *list, // blob list 00834 ScrollView::Color body_colour, // colour to draw 00835 ScrollView::Color child_colour); // colour of child 00836 #endif // GRAPHICS_DISABLED 00837 #endif