Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/tesseract/src/ccstruct/coutln.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 |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 /********************************************************************** | |
| 2 * File: coutln.h | |
| 3 * Description: Code for the C_OUTLINE class. | |
| 4 * Author: Ray Smith | |
| 5 * | |
| 6 * (C) Copyright 1991, Hewlett-Packard Ltd. | |
| 7 ** Licensed under the Apache License, Version 2.0 (the "License"); | |
| 8 ** you may not use this file except in compliance with the License. | |
| 9 ** You may obtain a copy of the License at | |
| 10 ** http://www.apache.org/licenses/LICENSE-2.0 | |
| 11 ** Unless required by applicable law or agreed to in writing, software | |
| 12 ** distributed under the License is distributed on an "AS IS" BASIS, | |
| 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 14 ** See the License for the specific language governing permissions and | |
| 15 ** limitations under the License. | |
| 16 * | |
| 17 **********************************************************************/ | |
| 18 | |
| 19 #ifndef COUTLN_H | |
| 20 #define COUTLN_H | |
| 21 | |
| 22 #include "elst.h" // for ELIST_ITERATOR, ELISTIZEH, ELIST_LINK | |
| 23 #include "mod128.h" // for DIR128, DIRBITS | |
| 24 #include "points.h" // for ICOORD, FCOORD | |
| 25 #include "rect.h" // for TBOX | |
| 26 #include "scrollview.h" // for ScrollView, ScrollView::Color | |
| 27 | |
| 28 #include <tesseract/export.h> // for DLLSYM | |
| 29 | |
| 30 #include <cstdint> // for int16_t, int32_t | |
| 31 #include <bitset> // for std::bitset<16> | |
| 32 | |
| 33 struct Pix; | |
| 34 | |
| 35 namespace tesseract { | |
| 36 | |
| 37 class CRACKEDGE; | |
| 38 class DENORM; | |
| 39 | |
| 40 #define INTERSECTING INT16_MAX // no winding number | |
| 41 | |
| 42 // mask to get step | |
| 43 #define STEP_MASK 3 | |
| 44 | |
| 45 enum C_OUTLINE_FLAGS { | |
| 46 COUT_INVERSE // White on black blob | |
| 47 }; | |
| 48 | |
| 49 // Simple struct to hold the 3 values needed to compute a more precise edge | |
| 50 // position and direction. The offset_numerator is the difference between the | |
| 51 // grey threshold and the mean pixel value. pixel_diff is the difference between | |
| 52 // the pixels in the edge. Consider the following row of pixels: p1 p2 p3 p4 p5 | |
| 53 // Say the image was thresholded at threshold t, making p1, p2, p3 black | |
| 54 // and p4, p5 white (p1, p2, p3 < t, and p4, p5 >= t), but suppose that | |
| 55 // max(p[i+1] - p[i]) is p3 - p2. Then the extrapolated position of the edge, | |
| 56 // based on the maximum gradient, is at the crack between p2 and p3 plus the | |
| 57 // offset (t - (p2+p3)/2)/(p3 - p2). We store the pixel difference p3-p2 | |
| 58 // denominator in pixel_diff and the offset numerator, relative to the original | |
| 59 // binary edge (t - (p2+p3)/2) - (p3 -p2) in offset_numerator. | |
| 60 // The sign of offset_numerator and pixel_diff are manipulated to ensure | |
| 61 // that the pixel_diff, which will be used as a weight, is always positive. | |
| 62 // The direction stores the quantized feature direction for the given step | |
| 63 // computed from the edge gradient. (Using binary_angle_plus_pi.) | |
| 64 // If the pixel_diff is zero, it means that the direction of the gradient | |
| 65 // is in conflict with the step direction, so this step is to be ignored. | |
| 66 struct EdgeOffset { | |
| 67 int8_t offset_numerator; | |
| 68 uint8_t pixel_diff; | |
| 69 uint8_t direction; | |
| 70 }; | |
| 71 | |
| 72 class C_OUTLINE; // forward declaration | |
| 73 | |
| 74 ELISTIZEH(C_OUTLINE) | |
| 75 class C_OUTLINE : public ELIST_LINK { | |
| 76 public: | |
| 77 C_OUTLINE() { | |
| 78 stepcount = 0; | |
| 79 offsets = nullptr; | |
| 80 } | |
| 81 C_OUTLINE( // constructor | |
| 82 CRACKEDGE *startpt, // from edge detector | |
| 83 ICOORD bot_left, // bounding box //length of loop | |
| 84 ICOORD top_right, int16_t length); | |
| 85 C_OUTLINE(ICOORD startpt, // start of loop | |
| 86 DIR128 *new_steps, // steps in loop | |
| 87 int16_t length); // length of loop | |
| 88 // outline to copy | |
| 89 C_OUTLINE(C_OUTLINE *srcline, FCOORD rotation); // and rotate | |
| 90 | |
| 91 // Build a fake outline, given just a bounding box and append to the list. | |
| 92 static void FakeOutline(const TBOX &box, C_OUTLINE_LIST *outlines); | |
| 93 | |
| 94 ~C_OUTLINE() { // destructor | |
| 95 delete[] offsets; | |
| 96 } | |
| 97 | |
| 98 bool flag( // test flag | |
| 99 C_OUTLINE_FLAGS mask) const { // flag to test | |
| 100 return flags[mask]; | |
| 101 } | |
| 102 void set_flag( // set flag value | |
| 103 C_OUTLINE_FLAGS mask, // flag to test | |
| 104 bool value) { // value to set | |
| 105 flags.set(mask, value); | |
| 106 } | |
| 107 | |
| 108 C_OUTLINE_LIST *child() { // get child list | |
| 109 return &children; | |
| 110 } | |
| 111 | |
| 112 // access function | |
| 113 const TBOX &bounding_box() const { | |
| 114 return box; | |
| 115 } | |
| 116 void set_step( // set a step | |
| 117 int16_t stepindex, // index of step | |
| 118 int8_t stepdir) { // chain code | |
| 119 int shift = stepindex % 4 * 2; | |
| 120 uint8_t mask = 3 << shift; | |
| 121 steps[stepindex / 4] = ((stepdir << shift) & mask) | (steps[stepindex / 4] & ~mask); | |
| 122 // squeeze 4 into byte | |
| 123 } | |
| 124 void set_step( // set a step | |
| 125 int16_t stepindex, // index of step | |
| 126 DIR128 stepdir) { // direction | |
| 127 // clean it | |
| 128 int8_t chaindir = stepdir.get_dir() >> (DIRBITS - 2); | |
| 129 // difference | |
| 130 set_step(stepindex, chaindir); | |
| 131 // squeeze 4 into byte | |
| 132 } | |
| 133 | |
| 134 int32_t pathlength() const { // get path length | |
| 135 return stepcount; | |
| 136 } | |
| 137 // Return step at a given index as a DIR128. | |
| 138 DIR128 step_dir(int index) const { | |
| 139 return DIR128( | |
| 140 static_cast<int16_t>(((steps[index / 4] >> (index % 4 * 2)) & STEP_MASK) << (DIRBITS - 2))); | |
| 141 } | |
| 142 // Return the step vector for the given outline position. | |
| 143 ICOORD step(int index) const { // index of step | |
| 144 return step_coords[chain_code(index)]; | |
| 145 } | |
| 146 // get start position | |
| 147 const ICOORD &start_pos() const { | |
| 148 return start; | |
| 149 } | |
| 150 // Returns the position at the given index on the outline. | |
| 151 // NOT to be used lightly, as it has to iterate the outline to find out. | |
| 152 ICOORD position_at_index(int index) const { | |
| 153 ICOORD pos = start; | |
| 154 for (int i = 0; i < index; ++i) { | |
| 155 pos += step(i); | |
| 156 } | |
| 157 return pos; | |
| 158 } | |
| 159 // Returns the sub-pixel accurate position given the integer position pos | |
| 160 // at the given index on the outline. pos may be a return value of | |
| 161 // position_at_index, or computed by repeatedly adding step to the | |
| 162 // start_pos() in the usual way. | |
| 163 FCOORD sub_pixel_pos_at_index(const ICOORD &pos, int index) const { | |
| 164 const ICOORD &step_to_next(step(index)); | |
| 165 FCOORD f_pos(pos.x() + step_to_next.x() / 2.0f, pos.y() + step_to_next.y() / 2.0f); | |
| 166 if (offsets != nullptr && offsets[index].pixel_diff > 0) { | |
| 167 float offset = offsets[index].offset_numerator; | |
| 168 offset /= offsets[index].pixel_diff; | |
| 169 if (step_to_next.x() != 0) { | |
| 170 f_pos.set_y(f_pos.y() + offset); | |
| 171 } else { | |
| 172 f_pos.set_x(f_pos.x() + offset); | |
| 173 } | |
| 174 } | |
| 175 return f_pos; | |
| 176 } | |
| 177 // Returns the step direction for the given index or -1 if there is none. | |
| 178 int direction_at_index(int index) const { | |
| 179 if (offsets != nullptr && offsets[index].pixel_diff > 0) { | |
| 180 return offsets[index].direction; | |
| 181 } | |
| 182 return -1; | |
| 183 } | |
| 184 // Returns the edge strength for the given index. | |
| 185 // If there are no recorded edge strengths, returns 1 (assuming the image | |
| 186 // is binary). Returns 0 if the gradient direction conflicts with the | |
| 187 // step direction, indicating that this position could be skipped. | |
| 188 int edge_strength_at_index(int index) const { | |
| 189 if (offsets != nullptr) { | |
| 190 return offsets[index].pixel_diff; | |
| 191 } | |
| 192 return 1; | |
| 193 } | |
| 194 // Return the step as a chain code (0-3) related to the standard feature | |
| 195 // direction of binary_angle_plus_pi by: | |
| 196 // chain_code * 64 = feature direction. | |
| 197 int chain_code(int index) const { // index of step | |
| 198 return (steps[index / 4] >> (index % 4 * 2)) & STEP_MASK; | |
| 199 } | |
| 200 | |
| 201 int32_t area() const; // Returns area of self and 1st level children. | |
| 202 int32_t perimeter() const; // Total perimeter of self and 1st level children. | |
| 203 int32_t outer_area() const; // Returns area of self only. | |
| 204 int32_t count_transitions( // count maxima | |
| 205 int32_t threshold); // size threshold | |
| 206 | |
| 207 bool operator<( // containment test | |
| 208 const C_OUTLINE &other) const; | |
| 209 bool operator>( // containment test | |
| 210 C_OUTLINE &other) const { | |
| 211 return other < *this; // use the < to do it | |
| 212 } | |
| 213 int16_t winding_number( // get winding number | |
| 214 ICOORD testpt) const; // around this point | |
| 215 // get direction | |
| 216 int16_t turn_direction() const; | |
| 217 void reverse(); // reverse direction | |
| 218 | |
| 219 void move( // reposition outline | |
| 220 const ICOORD vec); // by vector | |
| 221 | |
| 222 // Returns true if *this and its children are legally nested. | |
| 223 // The outer area of a child should have the opposite sign to the | |
| 224 // parent. If not, it means we have discarded an outline in between | |
| 225 // (probably due to excessive length). | |
| 226 bool IsLegallyNested() const; | |
| 227 | |
| 228 // If this outline is smaller than the given min_size, delete this and | |
| 229 // remove from its list, via *it, after checking that *it points to this. | |
| 230 // Otherwise, if any children of this are too small, delete them. | |
| 231 // On entry, *it must be an iterator pointing to this. If this gets deleted | |
| 232 // then this is extracted from *it, so an iteration can continue. | |
| 233 void RemoveSmallRecursive(int min_size, C_OUTLINE_IT *it); | |
| 234 | |
| 235 // Adds sub-pixel resolution EdgeOffsets for the outline if the supplied | |
| 236 // pix is 8-bit. Does nothing otherwise. | |
| 237 void ComputeEdgeOffsets(int threshold, Image pix); | |
| 238 // Adds sub-pixel resolution EdgeOffsets for the outline using only | |
| 239 // a binary image source. | |
| 240 void ComputeBinaryOffsets(); | |
| 241 | |
| 242 // Renders the outline to the given pix, with left and top being | |
| 243 // the coords of the upper-left corner of the pix. | |
| 244 void render(int left, int top, Image pix) const; | |
| 245 | |
| 246 // Renders just the outline to the given pix (no fill), with left and top | |
| 247 // being the coords of the upper-left corner of the pix. | |
| 248 void render_outline(int left, int top, Image pix) const; | |
| 249 | |
| 250 #ifndef GRAPHICS_DISABLED | |
| 251 void plot( // draw one | |
| 252 ScrollView *window, // window to draw in | |
| 253 ScrollView::Color colour) const; // colour to draw it | |
| 254 // Draws the outline in the given colour, normalized using the given denorm, | |
| 255 // making use of sub-pixel accurate information if available. | |
| 256 void plot_normed(const DENORM &denorm, ScrollView::Color colour, ScrollView *window) const; | |
| 257 #endif // !GRAPHICS_DISABLED | |
| 258 | |
| 259 C_OUTLINE &operator=(const C_OUTLINE &source); | |
| 260 | |
| 261 static C_OUTLINE *deep_copy(const C_OUTLINE *src) { | |
| 262 auto *outline = new C_OUTLINE; | |
| 263 *outline = *src; | |
| 264 return outline; | |
| 265 } | |
| 266 | |
| 267 static ICOORD chain_step(int chaindir); | |
| 268 | |
| 269 // The maximum length of any outline. The stepcount is stored as 16 bits, | |
| 270 // but it is probably not a good idea to increase this constant by much | |
| 271 // and switch to 32 bits, as it plays an important role in keeping huge | |
| 272 // outlines invisible, which prevents bad speed behavior. | |
| 273 static const int kMaxOutlineLength = 16000; | |
| 274 | |
| 275 private: | |
| 276 // Helper for ComputeBinaryOffsets. Increments pos, dir_counts, pos_totals | |
| 277 // by the step, increment, and vertical step ? x : y position * increment | |
| 278 // at step s Mod stepcount respectively. Used to add or subtract the | |
| 279 // direction and position to/from accumulators of a small neighbourhood. | |
| 280 void increment_step(int s, int increment, ICOORD *pos, int *dir_counts, int *pos_totals) const; | |
| 281 int step_mem() const { | |
| 282 return (stepcount + 3) / 4; | |
| 283 } | |
| 284 | |
| 285 TBOX box; // bounding box | |
| 286 ICOORD start; // start coord | |
| 287 int16_t stepcount; // no of steps | |
| 288 std::bitset<16> flags; // flags about outline | |
| 289 std::vector<uint8_t> steps; // step array | |
| 290 EdgeOffset *offsets; // Higher precision edge. | |
| 291 C_OUTLINE_LIST children; // child elements | |
| 292 static ICOORD step_coords[4]; | |
| 293 }; | |
| 294 | |
| 295 } // namespace tesseract | |
| 296 | |
| 297 #endif |
