Mercurial > hgrepos > Python2 > PyMuPDF
diff mupdf-source/thirdparty/tesseract/src/ccstruct/blobs.h @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mupdf-source/thirdparty/tesseract/src/ccstruct/blobs.h Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,476 @@ +/****************************************************************************** + * + * File: blobs.h + * Description: Blob definition + * Author: Mark Seaman, OCR Technology + * + * (c) Copyright 1989, Hewlett-Packard Company. + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** http://www.apache.org/licenses/LICENSE-2.0 + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + * + *****************************************************************************/ + +#ifndef BLOBS_H +#define BLOBS_H + +#include "clst.h" // for CLIST_ITERATOR, CLISTIZEH +#include "normalis.h" // for DENORM +#include "points.h" // for FCOORD, ICOORD +#include "rect.h" // for TBOX +#include "scrollview.h" // for ScrollView, ScrollView::Color + +#include <tesseract/publictypes.h> // for OcrEngineMode + +#include "tesstypes.h" // for TDimension + +struct Pix; + +namespace tesseract { + +class BLOCK; +class C_BLOB; +class C_OUTLINE; +class LLSQ; +class ROW; +class WERD; + +/*---------------------------------------------------------------------- + T y p e s +----------------------------------------------------------------------*/ + +struct TPOINT { + TPOINT() = default; + TPOINT(TDimension vx, TDimension vy) : x(vx), y(vy) {} + TPOINT(const ICOORD &ic) : x(ic.x()), y(ic.y()) {} + + void operator+=(const TPOINT &other) { + x += other.x; + y += other.y; + } + void operator/=(int divisor) { + x /= divisor; + y /= divisor; + } + bool operator==(const TPOINT &other) const { + return x == other.x && y == other.y; + } + // Returns true when the two line segments cross each other. + // (Moved from outlines.cpp). + static bool IsCrossed(const TPOINT &a0, const TPOINT &a1, const TPOINT &b0, const TPOINT &b1); + + // Assign the difference from point p1 to point p2. + void diff(const TPOINT &p1, const TPOINT &p2) { + x = p1.x - p2.x; + y = p1.y - p2.y; + } + + // Return cross product. + int cross(const TPOINT &other) const { + return x * other.y - y * other.x; + } + + // Return scalar or dot product. + int dot(const TPOINT &other) const { + return x * other.x + y * other.y; + } + + // Calculate square of vector length. + int length2() const { + return x * x + y * y; + } + + TDimension x = 0; // absolute x coord. + TDimension y = 0; // absolute y coord. +}; + +using VECTOR = TPOINT; // structure for coordinates. + +struct EDGEPT { + EDGEPT() = default; + EDGEPT(const EDGEPT &src) : next(nullptr), prev(nullptr) { + CopyFrom(src); + } + EDGEPT &operator=(const EDGEPT &src) { + CopyFrom(src); + return *this; + } + // Copies the data elements, but leaves the pointers untouched. + void CopyFrom(const EDGEPT &src) { + pos = src.pos; + vec = src.vec; + is_hidden = src.is_hidden; + runlength = src.runlength; + dir = src.dir; + fixed = src.fixed; + src_outline = src.src_outline; + start_step = src.start_step; + step_count = src.step_count; + } + // Returns the squared distance between the points, with the x-component + // weighted by x_factor. + int WeightedDistance(const EDGEPT &other, int x_factor) const { + int x_dist = pos.x - other.pos.x; + int y_dist = pos.y - other.pos.y; + return x_dist * x_dist * x_factor + y_dist * y_dist; + } + // Returns true if the positions are equal. + bool EqualPos(const EDGEPT &other) const { + return pos == other.pos; + } + // Returns the bounding box of the outline segment from *this to *end. + // Ignores hidden edge flags. + TBOX SegmentBox(const EDGEPT *end) const { + TBOX box(pos.x, pos.y, pos.x, pos.y); + const EDGEPT *pt = this; + do { + pt = pt->next; + if (pt->pos.x < box.left()) { + box.set_left(pt->pos.x); + } + if (pt->pos.x > box.right()) { + box.set_right(pt->pos.x); + } + if (pt->pos.y < box.bottom()) { + box.set_bottom(pt->pos.y); + } + if (pt->pos.y > box.top()) { + box.set_top(pt->pos.y); + } + } while (pt != end && pt != this); + return box; + } + // Returns the area of the outline segment from *this to *end. + // Ignores hidden edge flags. + int SegmentArea(const EDGEPT *end) const { + int area = 0; + const EDGEPT *pt = this->next; + do { + TPOINT origin_vec(pt->pos.x - pos.x, pt->pos.y - pos.y); + area += origin_vec.cross(pt->vec); + pt = pt->next; + } while (pt != end && pt != this); + return area; + } + // Returns true if the number of points in the outline segment from *this to + // *end is less that min_points and false if we get back to *this first. + // Ignores hidden edge flags. + bool ShortNonCircularSegment(int min_points, const EDGEPT *end) const { + int count = 0; + const EDGEPT *pt = this; + do { + if (pt == end) { + return true; + } + pt = pt->next; + ++count; + } while (pt != this && count <= min_points); + return false; + } + + // Accessors to hide or reveal a cut edge from feature extractors. + void Hide() { + is_hidden = true; + } + void Reveal() { + is_hidden = false; + } + bool IsHidden() const { + return is_hidden; + } + void MarkChop() { + dir = 1; + } + bool IsChopPt() const { + return dir != 0; + } + + TPOINT pos; // position + VECTOR vec; // vector to next point + bool is_hidden = false; + uint8_t runlength = 0; + int8_t dir = 0; + bool fixed = false; + EDGEPT *next = nullptr; // anticlockwise element + EDGEPT *prev = nullptr; // clockwise element + C_OUTLINE *src_outline = nullptr; // Outline it came from. + // The following fields are not used if src_outline is nullptr. + int start_step = 0; // Location of pos in src_outline. + int step_count = 0; // Number of steps used (may wrap around). +}; + +// For use in chop and findseam to keep a list of which EDGEPTs were inserted. +CLISTIZEH(EDGEPT) + +struct TESSLINE { + TESSLINE() : is_hole(false), loop(nullptr), next(nullptr) {} + TESSLINE(const TESSLINE &src) : loop(nullptr), next(nullptr) { + CopyFrom(src); + } + ~TESSLINE() { + Clear(); + } + TESSLINE &operator=(const TESSLINE &src) { + CopyFrom(src); + return *this; + } + // Consume the circular list of EDGEPTs to make a TESSLINE. + static TESSLINE *BuildFromOutlineList(EDGEPT *outline); + // Copies the data and the outline, but leaves next untouched. + void CopyFrom(const TESSLINE &src); + // Deletes owned data. + void Clear(); + // Normalize in-place using the DENORM. + void Normalize(const DENORM &denorm); + // Rotates by the given rotation in place. + void Rotate(const FCOORD rotation); + // Moves by the given vec in place. + void Move(const ICOORD vec); + // Scales by the given factor in place. + void Scale(float factor); + // Sets up the start and vec members of the loop from the pos members. + void SetupFromPos(); + // Recomputes the bounding box from the points in the loop. + void ComputeBoundingBox(); + // Computes the min and max cross product of the outline points with the + // given vec and returns the results in min_xp and max_xp. Geometrically + // this is the left and right edge of the outline perpendicular to the + // given direction, but to get the distance units correct, you would + // have to divide by the modulus of vec. + void MinMaxCrossProduct(const TPOINT vec, int *min_xp, int *max_xp) const; + + TBOX bounding_box() const; + // Returns true if *this and other have equal bounding boxes. + bool SameBox(const TESSLINE &other) const { + return topleft == other.topleft && botright == other.botright; + } + // Returns true if the given line segment crosses any outline of this blob. + bool SegmentCrosses(const TPOINT &pt1, const TPOINT &pt2) const { + if (Contains(pt1) && Contains(pt2)) { + EDGEPT *pt = loop; + do { + if (TPOINT::IsCrossed(pt1, pt2, pt->pos, pt->next->pos)) { + return true; + } + pt = pt->next; + } while (pt != loop); + } + return false; + } + // Returns true if the point is contained within the outline box. + bool Contains(const TPOINT &pt) const { + return topleft.x <= pt.x && pt.x <= botright.x && botright.y <= pt.y && pt.y <= topleft.y; + } + +#ifndef GRAPHICS_DISABLED + void plot(ScrollView *window, ScrollView::Color color, ScrollView::Color child_color); +#endif // !GRAPHICS_DISABLED + + // Returns the first outline point that has a different src_outline to its + // predecessor, or, if all the same, the lowest indexed point. + EDGEPT *FindBestStartPt() const; + + int BBArea() const { + return (botright.x - topleft.x) * (topleft.y - botright.y); + } + + TPOINT topleft; // Top left of loop. + TPOINT botright; // Bottom right of loop. + TPOINT start; // Start of loop. + bool is_hole; // True if this is a hole/child outline. + EDGEPT *loop; // Edgeloop. + TESSLINE *next; // Next outline in blob. +}; // Outline structure. + +struct TBLOB { + TBLOB() : outlines(nullptr) {} + TBLOB(const TBLOB &src) : outlines(nullptr) { + CopyFrom(src); + } + ~TBLOB() { + Clear(); + } + TBLOB &operator=(const TBLOB &src) { + CopyFrom(src); + return *this; + } + // Factory to build a TBLOB from a C_BLOB with polygonal approximation along + // the way. If allow_detailed_fx is true, the EDGEPTs in the returned TBLOB + // contain pointers to the input C_OUTLINEs that enable higher-resolution + // feature extraction that does not use the polygonal approximation. + static TBLOB *PolygonalCopy(bool allow_detailed_fx, C_BLOB *src); + // Factory builds a blob with no outlines, but copies the other member data. + static TBLOB *ShallowCopy(const TBLOB &src); + // Normalizes the blob for classification only if needed. + // (Normally this means a non-zero classify rotation.) + // If no Normalization is needed, then nullptr is returned, and the input blob + // can be used directly. Otherwise a new TBLOB is returned which must be + // deleted after use. + TBLOB *ClassifyNormalizeIfNeeded() const; + + // Copies the data and the outlines, but leaves next untouched. + void CopyFrom(const TBLOB &src); + // Deletes owned data. + void Clear(); + // Sets up the built-in DENORM and normalizes the blob in-place. + // For parameters see DENORM::SetupNormalization, plus the inverse flag for + // this blob and the Pix for the full image. + void Normalize(const BLOCK *block, const FCOORD *rotation, const DENORM *predecessor, + float x_origin, float y_origin, float x_scale, float y_scale, float final_xshift, + float final_yshift, bool inverse, Image pix); + // Rotates by the given rotation in place. + void Rotate(const FCOORD rotation); + // Moves by the given vec in place. + void Move(const ICOORD vec); + // Scales by the given factor in place. + void Scale(float factor); + // Recomputes the bounding boxes of the outlines. + void ComputeBoundingBoxes(); + + // Returns the number of outlines. + int NumOutlines() const; + + TBOX bounding_box() const; + + // Returns true if the given line segment crosses any outline of this blob. + bool SegmentCrossesOutline(const TPOINT &pt1, const TPOINT &pt2) const { + for (const TESSLINE *outline = outlines; outline != nullptr; outline = outline->next) { + if (outline->SegmentCrosses(pt1, pt2)) { + return true; + } + } + return false; + } + // Returns true if the point is contained within any of the outline boxes. + bool Contains(const TPOINT &pt) const { + for (const TESSLINE *outline = outlines; outline != nullptr; outline = outline->next) { + if (outline->Contains(pt)) { + return true; + } + } + return false; + } + + // Finds and deletes any duplicate outlines in this blob, without deleting + // their EDGEPTs. + void EliminateDuplicateOutlines(); + + // Swaps the outlines of *this and next if needed to keep the centers in + // increasing x. + void CorrectBlobOrder(TBLOB *next); + + const DENORM &denorm() const { + return denorm_; + } + +#ifndef GRAPHICS_DISABLED + void plot(ScrollView *window, ScrollView::Color color, ScrollView::Color child_color); +#endif // !GRAPHICS_DISABLED + + int BBArea() const { + int total_area = 0; + for (TESSLINE *outline = outlines; outline != nullptr; outline = outline->next) { + total_area += outline->BBArea(); + } + return total_area; + } + + // Computes the center of mass and second moments for the old baseline and + // 2nd moment normalizations. Returns the outline length. + // The input denorm should be the normalizations that have been applied from + // the image to the current state of this TBLOB. + int ComputeMoments(FCOORD *center, FCOORD *second_moments) const; + // Computes the precise bounding box of the coords that are generated by + // GetEdgeCoords. This may be different from the bounding box of the polygon. + void GetPreciseBoundingBox(TBOX *precise_box) const; + // Adds edges to the given vectors. + // For all the edge steps in all the outlines, or polygonal approximation + // where there are no edge steps, collects the steps into x_coords/y_coords. + // x_coords is a collection of the x-coords of vertical edges for each + // y-coord starting at box.bottom(). + // y_coords is a collection of the y-coords of horizontal edges for each + // x-coord starting at box.left(). + // Eg x_coords[0] is a collection of the x-coords of edges at y=bottom. + // Eg x_coords[1] is a collection of the x-coords of edges at y=bottom + 1. + void GetEdgeCoords(const TBOX &box, std::vector<std::vector<int>> &x_coords, + std::vector<std::vector<int>> &y_coords) const; + + TESSLINE *outlines; // List of outlines in blob. + +private: // TODO(rays) Someday the data members will be private too. + // For all the edge steps in all the outlines, or polygonal approximation + // where there are no edge steps, collects the steps into the bounding_box, + // llsq and/or the x_coords/y_coords. Both are used in different kinds of + // normalization. + // For a description of x_coords, y_coords, see GetEdgeCoords above. + void CollectEdges(const TBOX &box, TBOX *bounding_box, LLSQ *llsq, + std::vector<std::vector<int>> *x_coords, + std::vector<std::vector<int>> *y_coords) const; + +private: + // DENORM indicating the transformations that this blob has undergone so far. + DENORM denorm_; +}; // Blob structure. + +struct TWERD { + TWERD() : latin_script(false) {} + TWERD(const TWERD &src) { + CopyFrom(src); + } + ~TWERD() { + Clear(); + } + TWERD &operator=(const TWERD &src) { + CopyFrom(src); + return *this; + } + // Factory to build a TWERD from a (C_BLOB) WERD, with polygonal + // approximation along the way. + static TWERD *PolygonalCopy(bool allow_detailed_fx, WERD *src); + // Baseline normalizes the blobs in-place, recording the normalization in the + // DENORMs in the blobs. + void BLNormalize(const BLOCK *block, const ROW *row, Image pix, bool inverse, float x_height, + float baseline_shift, bool numeric_mode, tesseract::OcrEngineMode hint, + const TBOX *norm_box, DENORM *word_denorm); + // Copies the data and the blobs, but leaves next untouched. + void CopyFrom(const TWERD &src); + // Deletes owned data. + void Clear(); + // Recomputes the bounding boxes of the blobs. + void ComputeBoundingBoxes(); + + // Returns the number of blobs in the word. + unsigned NumBlobs() const { + return blobs.size(); + } + TBOX bounding_box() const; + + // Merges the blobs from start to end, not including end, and deletes + // the blobs between start and end. + void MergeBlobs(unsigned start, unsigned end); + +#ifndef GRAPHICS_DISABLED + void plot(ScrollView *window); +#endif // !GRAPHICS_DISABLED + + std::vector<TBLOB *> blobs; // Blobs in word. + bool latin_script; // This word is in a latin-based script. +}; + +/*---------------------------------------------------------------------- + F u n c t i o n s +----------------------------------------------------------------------*/ +// TODO(rays) Make divisible_blob and divide_blobs members of TBLOB. +bool divisible_blob(TBLOB *blob, bool italic_blob, TPOINT *location); + +void divide_blobs(TBLOB *blob, TBLOB *other_blob, bool italic_blob, const TPOINT &location); + +} // namespace tesseract + +#endif
