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