|
tesseract 3.04.01
|
00001 /* -*-C-*- 00002 ******************************************************************************** 00003 * 00004 * File: blobs.h (Formerly blobs.h) 00005 * Description: Blob definition 00006 * Author: Mark Seaman, OCR Technology 00007 * Created: Fri Oct 27 15:39:52 1989 00008 * Modified: Thu Mar 28 15:33:38 1991 (Mark Seaman) marks@hpgrlt 00009 * Language: C 00010 * Package: N/A 00011 * Status: Experimental (Do Not Distribute) 00012 * 00013 * (c) Copyright 1989, Hewlett-Packard Company. 00014 ** Licensed under the Apache License, Version 2.0 (the "License"); 00015 ** you may not use this file except in compliance with the License. 00016 ** You may obtain a copy of the License at 00017 ** http://www.apache.org/licenses/LICENSE-2.0 00018 ** Unless required by applicable law or agreed to in writing, software 00019 ** distributed under the License is distributed on an "AS IS" BASIS, 00020 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00021 ** See the License for the specific language governing permissions and 00022 ** limitations under the License. 00023 * 00024 *********************************************************************************/ 00025 00026 #ifndef BLOBS_H 00027 #define BLOBS_H 00028 00029 /*---------------------------------------------------------------------- 00030 I n c l u d e s 00031 ----------------------------------------------------------------------*/ 00032 #include "clst.h" 00033 #include "normalis.h" 00034 #include "publictypes.h" 00035 #include "rect.h" 00036 #include "vecfuncs.h" 00037 00038 class BLOCK; 00039 class C_BLOB; 00040 class C_OUTLINE; 00041 class LLSQ; 00042 class ROW; 00043 class WERD; 00044 00045 /*---------------------------------------------------------------------- 00046 T y p e s 00047 ----------------------------------------------------------------------*/ 00048 #define EDGEPTFLAGS 4 /*concavity,length etc. */ 00049 00050 struct TPOINT { 00051 TPOINT(): x(0), y(0) {} 00052 TPOINT(inT16 vx, inT16 vy) : x(vx), y(vy) {} 00053 TPOINT(const ICOORD &ic) : x(ic.x()), y(ic.y()) {} 00054 00055 void operator+=(const TPOINT& other) { 00056 x += other.x; 00057 y += other.y; 00058 } 00059 void operator/=(int divisor) { 00060 x /= divisor; 00061 y /= divisor; 00062 } 00063 bool operator==(const TPOINT& other) const { 00064 return x == other.x && y == other.y; 00065 } 00066 // Returns true when the two line segments cross each other. 00067 // (Moved from outlines.cpp). 00068 static bool IsCrossed(const TPOINT& a0, const TPOINT& a1, const TPOINT& b0, 00069 const TPOINT& b1); 00070 00071 inT16 x; // absolute x coord. 00072 inT16 y; // absolute y coord. 00073 }; 00074 typedef TPOINT VECTOR; // structure for coordinates. 00075 00076 struct EDGEPT { 00077 EDGEPT() 00078 : next(NULL), prev(NULL), src_outline(NULL), start_step(0), step_count(0) { 00079 memset(flags, 0, EDGEPTFLAGS * sizeof(flags[0])); 00080 } 00081 EDGEPT(const EDGEPT& src) : next(NULL), prev(NULL) { 00082 CopyFrom(src); 00083 } 00084 EDGEPT& operator=(const EDGEPT& src) { 00085 CopyFrom(src); 00086 return *this; 00087 } 00088 // Copies the data elements, but leaves the pointers untouched. 00089 void CopyFrom(const EDGEPT& src) { 00090 pos = src.pos; 00091 vec = src.vec; 00092 memcpy(flags, src.flags, EDGEPTFLAGS * sizeof(flags[0])); 00093 src_outline = src.src_outline; 00094 start_step = src.start_step; 00095 step_count = src.step_count; 00096 } 00097 // Returns the squared distance between the points, with the x-component 00098 // weighted by x_factor. 00099 int WeightedDistance(const EDGEPT& other, int x_factor) const { 00100 int x_dist = pos.x - other.pos.x; 00101 int y_dist = pos.y - other.pos.y; 00102 return x_dist * x_dist * x_factor + y_dist * y_dist; 00103 } 00104 // Returns true if the positions are equal. 00105 bool EqualPos(const EDGEPT& other) const { return pos == other.pos; } 00106 // Returns the bounding box of the outline segment from *this to *end. 00107 // Ignores hidden edge flags. 00108 TBOX SegmentBox(const EDGEPT* end) const { 00109 TBOX box(pos.x, pos.y, pos.x, pos.y); 00110 const EDGEPT* pt = this; 00111 do { 00112 pt = pt->next; 00113 if (pt->pos.x < box.left()) box.set_left(pt->pos.x); 00114 if (pt->pos.x > box.right()) box.set_right(pt->pos.x); 00115 if (pt->pos.y < box.bottom()) box.set_bottom(pt->pos.y); 00116 if (pt->pos.y > box.top()) box.set_top(pt->pos.y); 00117 } while (pt != end && pt != this); 00118 return box; 00119 } 00120 // Returns the area of the outline segment from *this to *end. 00121 // Ignores hidden edge flags. 00122 int SegmentArea(const EDGEPT* end) const { 00123 int area = 0; 00124 const EDGEPT* pt = this->next; 00125 do { 00126 TPOINT origin_vec(pt->pos.x - pos.x, pt->pos.y - pos.y); 00127 area += CROSS(origin_vec, pt->vec); 00128 pt = pt->next; 00129 } while (pt != end && pt != this); 00130 return area; 00131 } 00132 // Returns true if the number of points in the outline segment from *this to 00133 // *end is less that min_points and false if we get back to *this first. 00134 // Ignores hidden edge flags. 00135 bool ShortNonCircularSegment(int min_points, const EDGEPT* end) const { 00136 int count = 0; 00137 const EDGEPT* pt = this; 00138 do { 00139 if (pt == end) return true; 00140 pt = pt->next; 00141 ++count; 00142 } while (pt != this && count <= min_points); 00143 return false; 00144 } 00145 00146 // Accessors to hide or reveal a cut edge from feature extractors. 00147 void Hide() { 00148 flags[0] = true; 00149 } 00150 void Reveal() { 00151 flags[0] = false; 00152 } 00153 bool IsHidden() const { 00154 return flags[0] != 0; 00155 } 00156 void MarkChop() { 00157 flags[2] = true; 00158 } 00159 bool IsChopPt() const { 00160 return flags[2] != 0; 00161 } 00162 00163 TPOINT pos; // position 00164 VECTOR vec; // vector to next point 00165 // TODO(rays) Remove flags and replace with 00166 // is_hidden, runlength, dir, and fixed. The only use 00167 // of the flags other than is_hidden is in polyaprx.cpp. 00168 char flags[EDGEPTFLAGS]; // concavity, length etc 00169 EDGEPT* next; // anticlockwise element 00170 EDGEPT* prev; // clockwise element 00171 C_OUTLINE* src_outline; // Outline it came from. 00172 // The following fields are not used if src_outline is NULL. 00173 int start_step; // Location of pos in src_outline. 00174 int step_count; // Number of steps used (may wrap around). 00175 }; 00176 00177 // For use in chop and findseam to keep a list of which EDGEPTs were inserted. 00178 CLISTIZEH(EDGEPT); 00179 00180 struct TESSLINE { 00181 TESSLINE() : is_hole(false), loop(NULL), next(NULL) {} 00182 TESSLINE(const TESSLINE& src) : loop(NULL), next(NULL) { 00183 CopyFrom(src); 00184 } 00185 ~TESSLINE() { 00186 Clear(); 00187 } 00188 TESSLINE& operator=(const TESSLINE& src) { 00189 CopyFrom(src); 00190 return *this; 00191 } 00192 // Consume the circular list of EDGEPTs to make a TESSLINE. 00193 static TESSLINE* BuildFromOutlineList(EDGEPT* outline); 00194 // Copies the data and the outline, but leaves next untouched. 00195 void CopyFrom(const TESSLINE& src); 00196 // Deletes owned data. 00197 void Clear(); 00198 // Normalize in-place using the DENORM. 00199 void Normalize(const DENORM& denorm); 00200 // Rotates by the given rotation in place. 00201 void Rotate(const FCOORD rotation); 00202 // Moves by the given vec in place. 00203 void Move(const ICOORD vec); 00204 // Scales by the given factor in place. 00205 void Scale(float factor); 00206 // Sets up the start and vec members of the loop from the pos members. 00207 void SetupFromPos(); 00208 // Recomputes the bounding box from the points in the loop. 00209 void ComputeBoundingBox(); 00210 // Computes the min and max cross product of the outline points with the 00211 // given vec and returns the results in min_xp and max_xp. Geometrically 00212 // this is the left and right edge of the outline perpendicular to the 00213 // given direction, but to get the distance units correct, you would 00214 // have to divide by the modulus of vec. 00215 void MinMaxCrossProduct(const TPOINT vec, int* min_xp, int* max_xp) const; 00216 00217 TBOX bounding_box() const; 00218 // Returns true if *this and other have equal bounding boxes. 00219 bool SameBox(const TESSLINE& other) const { 00220 return topleft == other.topleft && botright == other.botright; 00221 } 00222 // Returns true if the given line segment crosses any outline of this blob. 00223 bool SegmentCrosses(const TPOINT& pt1, const TPOINT& pt2) const { 00224 if (Contains(pt1) && Contains(pt2)) { 00225 EDGEPT* pt = loop; 00226 do { 00227 if (TPOINT::IsCrossed(pt1, pt2, pt->pos, pt->next->pos)) return true; 00228 pt = pt->next; 00229 } while (pt != loop); 00230 } 00231 return false; 00232 } 00233 // Returns true if the point is contained within the outline box. 00234 bool Contains(const TPOINT& pt) const { 00235 return topleft.x <= pt.x && pt.x <= botright.x && 00236 botright.y <= pt.y && pt.y <= topleft.y; 00237 } 00238 00239 #ifndef GRAPHICS_DISABLED 00240 void plot(ScrollView* window, ScrollView::Color color, 00241 ScrollView::Color child_color); 00242 #endif // GRAPHICS_DISABLED 00243 00244 // Returns the first outline point that has a different src_outline to its 00245 // predecessor, or, if all the same, the lowest indexed point. 00246 EDGEPT* FindBestStartPt() const; 00247 00248 00249 int BBArea() const { 00250 return (botright.x - topleft.x) * (topleft.y - botright.y); 00251 } 00252 00253 TPOINT topleft; // Top left of loop. 00254 TPOINT botright; // Bottom right of loop. 00255 TPOINT start; // Start of loop. 00256 bool is_hole; // True if this is a hole/child outline. 00257 EDGEPT *loop; // Edgeloop. 00258 TESSLINE *next; // Next outline in blob. 00259 }; // Outline structure. 00260 00261 struct TBLOB { 00262 TBLOB() : outlines(NULL) {} 00263 TBLOB(const TBLOB& src) : outlines(NULL) { 00264 CopyFrom(src); 00265 } 00266 ~TBLOB() { 00267 Clear(); 00268 } 00269 TBLOB& operator=(const TBLOB& src) { 00270 CopyFrom(src); 00271 return *this; 00272 } 00273 // Factory to build a TBLOB from a C_BLOB with polygonal approximation along 00274 // the way. If allow_detailed_fx is true, the EDGEPTs in the returned TBLOB 00275 // contain pointers to the input C_OUTLINEs that enable higher-resolution 00276 // feature extraction that does not use the polygonal approximation. 00277 static TBLOB* PolygonalCopy(bool allow_detailed_fx, C_BLOB* src); 00278 // Factory builds a blob with no outlines, but copies the other member data. 00279 static TBLOB* ShallowCopy(const TBLOB& src); 00280 // Normalizes the blob for classification only if needed. 00281 // (Normally this means a non-zero classify rotation.) 00282 // If no Normalization is needed, then NULL is returned, and the input blob 00283 // can be used directly. Otherwise a new TBLOB is returned which must be 00284 // deleted after use. 00285 TBLOB* ClassifyNormalizeIfNeeded() const; 00286 00287 // Copies the data and the outlines, but leaves next untouched. 00288 void CopyFrom(const TBLOB& src); 00289 // Deletes owned data. 00290 void Clear(); 00291 // Sets up the built-in DENORM and normalizes the blob in-place. 00292 // For parameters see DENORM::SetupNormalization, plus the inverse flag for 00293 // this blob and the Pix for the full image. 00294 void Normalize(const BLOCK* block, 00295 const FCOORD* rotation, 00296 const DENORM* predecessor, 00297 float x_origin, float y_origin, 00298 float x_scale, float y_scale, 00299 float final_xshift, float final_yshift, 00300 bool inverse, Pix* pix); 00301 // Rotates by the given rotation in place. 00302 void Rotate(const FCOORD rotation); 00303 // Moves by the given vec in place. 00304 void Move(const ICOORD vec); 00305 // Scales by the given factor in place. 00306 void Scale(float factor); 00307 // Recomputes the bounding boxes of the outlines. 00308 void ComputeBoundingBoxes(); 00309 00310 // Returns the number of outlines. 00311 int NumOutlines() const; 00312 00313 TBOX bounding_box() const; 00314 00315 // Returns true if the given line segment crosses any outline of this blob. 00316 bool SegmentCrossesOutline(const TPOINT& pt1, const TPOINT& pt2) const { 00317 for (const TESSLINE* outline = outlines; outline != NULL; 00318 outline = outline->next) { 00319 if (outline->SegmentCrosses(pt1, pt2)) return true; 00320 } 00321 return false; 00322 } 00323 // Returns true if the point is contained within any of the outline boxes. 00324 bool Contains(const TPOINT& pt) const { 00325 for (const TESSLINE* outline = outlines; outline != NULL; 00326 outline = outline->next) { 00327 if (outline->Contains(pt)) return true; 00328 } 00329 return false; 00330 } 00331 00332 // Finds and deletes any duplicate outlines in this blob, without deleting 00333 // their EDGEPTs. 00334 void EliminateDuplicateOutlines(); 00335 00336 // Swaps the outlines of *this and next if needed to keep the centers in 00337 // increasing x. 00338 void CorrectBlobOrder(TBLOB* next); 00339 00340 const DENORM& denorm() const { 00341 return denorm_; 00342 } 00343 00344 #ifndef GRAPHICS_DISABLED 00345 void plot(ScrollView* window, ScrollView::Color color, 00346 ScrollView::Color child_color); 00347 #endif // GRAPHICS_DISABLED 00348 00349 int BBArea() const { 00350 int total_area = 0; 00351 for (TESSLINE* outline = outlines; outline != NULL; outline = outline->next) 00352 total_area += outline->BBArea(); 00353 return total_area; 00354 } 00355 00356 // Computes the center of mass and second moments for the old baseline and 00357 // 2nd moment normalizations. Returns the outline length. 00358 // The input denorm should be the normalizations that have been applied from 00359 // the image to the current state of this TBLOB. 00360 int ComputeMoments(FCOORD* center, FCOORD* second_moments) const; 00361 // Computes the precise bounding box of the coords that are generated by 00362 // GetEdgeCoords. This may be different from the bounding box of the polygon. 00363 void GetPreciseBoundingBox(TBOX* precise_box) const; 00364 // Adds edges to the given vectors. 00365 // For all the edge steps in all the outlines, or polygonal approximation 00366 // where there are no edge steps, collects the steps into x_coords/y_coords. 00367 // x_coords is a collection of the x-coords of vertical edges for each 00368 // y-coord starting at box.bottom(). 00369 // y_coords is a collection of the y-coords of horizontal edges for each 00370 // x-coord starting at box.left(). 00371 // Eg x_coords[0] is a collection of the x-coords of edges at y=bottom. 00372 // Eg x_coords[1] is a collection of the x-coords of edges at y=bottom + 1. 00373 void GetEdgeCoords(const TBOX& box, 00374 GenericVector<GenericVector<int> >* x_coords, 00375 GenericVector<GenericVector<int> >* y_coords) const; 00376 00377 TESSLINE *outlines; // List of outlines in blob. 00378 00379 private: // TODO(rays) Someday the data members will be private too. 00380 // For all the edge steps in all the outlines, or polygonal approximation 00381 // where there are no edge steps, collects the steps into the bounding_box, 00382 // llsq and/or the x_coords/y_coords. Both are used in different kinds of 00383 // normalization. 00384 // For a description of x_coords, y_coords, see GetEdgeCoords above. 00385 void CollectEdges(const TBOX& box, 00386 TBOX* bounding_box, LLSQ* llsq, 00387 GenericVector<GenericVector<int> >* x_coords, 00388 GenericVector<GenericVector<int> >* y_coords) const; 00389 00390 private: 00391 // DENORM indicating the transformations that this blob has undergone so far. 00392 DENORM denorm_; 00393 }; // Blob structure. 00394 00395 struct TWERD { 00396 TWERD() : latin_script(false) {} 00397 TWERD(const TWERD& src) { 00398 CopyFrom(src); 00399 } 00400 ~TWERD() { 00401 Clear(); 00402 } 00403 TWERD& operator=(const TWERD& src) { 00404 CopyFrom(src); 00405 return *this; 00406 } 00407 // Factory to build a TWERD from a (C_BLOB) WERD, with polygonal 00408 // approximation along the way. 00409 static TWERD* PolygonalCopy(bool allow_detailed_fx, WERD* src); 00410 // Baseline normalizes the blobs in-place, recording the normalization in the 00411 // DENORMs in the blobs. 00412 void BLNormalize(const BLOCK* block, const ROW* row, Pix* pix, bool inverse, 00413 float x_height, float baseline_shift, bool numeric_mode, 00414 tesseract::OcrEngineMode hint, 00415 const TBOX* norm_box, 00416 DENORM* word_denorm); 00417 // Copies the data and the blobs, but leaves next untouched. 00418 void CopyFrom(const TWERD& src); 00419 // Deletes owned data. 00420 void Clear(); 00421 // Recomputes the bounding boxes of the blobs. 00422 void ComputeBoundingBoxes(); 00423 00424 // Returns the number of blobs in the word. 00425 int NumBlobs() const { 00426 return blobs.size(); 00427 } 00428 TBOX bounding_box() const; 00429 00430 // Merges the blobs from start to end, not including end, and deletes 00431 // the blobs between start and end. 00432 void MergeBlobs(int start, int end); 00433 00434 void plot(ScrollView* window); 00435 00436 GenericVector<TBLOB*> blobs; // Blobs in word. 00437 bool latin_script; // This word is in a latin-based script. 00438 }; 00439 00440 /*---------------------------------------------------------------------- 00441 M a c r o s 00442 ----------------------------------------------------------------------*/ 00443 /********************************************************************** 00444 * free_widths 00445 * 00446 * Free the memory taken up by a width array. 00447 **********************************************************************/ 00448 #define free_widths(w) \ 00449 if (w) memfree (w) 00450 00451 /*---------------------------------------------------------------------- 00452 F u n c t i o n s 00453 ----------------------------------------------------------------------*/ 00454 // TODO(rays) Make divisible_blob and divide_blobs members of TBLOB. 00455 bool divisible_blob(TBLOB *blob, bool italic_blob, TPOINT* location); 00456 00457 void divide_blobs(TBLOB *blob, TBLOB *other_blob, bool italic_blob, 00458 const TPOINT& location); 00459 00460 #endif