/src/tesseract/src/ccstruct/polyaprx.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /********************************************************************** |
2 | | * File: polyaprx.cpp |
3 | | * Description: Code for polygonal approximation from old edgeprog. |
4 | | * Author: Ray Smith |
5 | | * |
6 | | * (C) Copyright 1993, 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 | | #include "polyaprx.h" |
20 | | |
21 | | #include "blobs.h" // for EDGEPT, TPOINT, VECTOR, TESSLINE |
22 | | #include "coutln.h" // for C_OUTLINE |
23 | | #include "errcode.h" // for ASSERT_HOST |
24 | | #include "mod128.h" // for DIR128 |
25 | | #include "params.h" // for BoolParam, BOOL_VAR |
26 | | #include "points.h" // for ICOORD |
27 | | #include "rect.h" // for TBOX |
28 | | #include "tprintf.h" // for tprintf |
29 | | |
30 | | #include <cstdint> // for INT16_MAX, int8_t |
31 | | |
32 | | namespace tesseract { |
33 | | |
34 | 1.93M | #define FASTEDGELENGTH 256 |
35 | | |
36 | | static BOOL_VAR(poly_debug, false, "Debug old poly"); |
37 | | static BOOL_VAR(poly_wide_objects_better, true, |
38 | | "More accurate approx on wide things"); |
39 | | |
40 | 3.87M | #define fixed_dist 20 // really an int_variable |
41 | | #define approx_dist 15 // really an int_variable |
42 | | |
43 | | const int par1 = 4500 / (approx_dist * approx_dist); |
44 | | const int par2 = 6750 / (approx_dist * approx_dist); |
45 | | |
46 | | /********************************************************************** |
47 | | *cutline(first,last,area) straightens out a line by partitioning |
48 | | *and joining the ends by a straight line* |
49 | | **********************************************************************/ |
50 | | |
51 | | static void cutline( // recursive refine |
52 | | EDGEPT *first, // ends of line |
53 | | EDGEPT *last, int area // area of object |
54 | 8.91M | ) { |
55 | 8.91M | EDGEPT *edge; // current edge |
56 | 8.91M | TPOINT vecsum; // vector sum |
57 | 8.91M | int vlen; // approx length of vecsum |
58 | 8.91M | TPOINT vec; // accumulated vector |
59 | 8.91M | EDGEPT *maxpoint; // worst point |
60 | 8.91M | int maxperp; // max deviation |
61 | 8.91M | int perp; // perp distance |
62 | 8.91M | int ptcount; // no of points |
63 | 8.91M | int squaresum; // sum of perps |
64 | | |
65 | 8.91M | edge = first; // start of line |
66 | 8.91M | if (edge->next == last) { |
67 | 972k | return; // simple line |
68 | 972k | } |
69 | | |
70 | | // vector sum |
71 | 7.94M | vecsum.x = last->pos.x - edge->pos.x; |
72 | 7.94M | vecsum.y = last->pos.y - edge->pos.y; |
73 | 7.94M | if (vecsum.x == 0 && vecsum.y == 0) { |
74 | | // special case |
75 | 81 | vecsum.x = -edge->prev->vec.x; |
76 | 81 | vecsum.y = -edge->prev->vec.y; |
77 | 81 | } |
78 | | // absolute value |
79 | 7.94M | vlen = vecsum.x > 0 ? vecsum.x : -vecsum.x; |
80 | 7.94M | if (vecsum.y > vlen) { |
81 | 1.95M | vlen = vecsum.y; // maximum |
82 | 5.98M | } else if (-vecsum.y > vlen) { |
83 | 2.56M | vlen = -vecsum.y; // absolute value |
84 | 2.56M | } |
85 | | |
86 | 7.94M | vec.x = edge->vec.x; // accumulated vector |
87 | 7.94M | vec.y = edge->vec.y; |
88 | 7.94M | maxperp = 0; // none yet |
89 | 7.94M | squaresum = ptcount = 0; |
90 | 7.94M | edge = edge->next; // move to actual point |
91 | 7.94M | maxpoint = edge; // in case there isn't one |
92 | 15.5M | do { |
93 | 15.5M | perp = vec.cross(vecsum); // get perp distance |
94 | 15.5M | if (perp != 0) { |
95 | 14.0M | perp *= perp; // squared deviation |
96 | 14.0M | } |
97 | 15.5M | squaresum += perp; // sum squares |
98 | 15.5M | ptcount++; // count points |
99 | 15.5M | if (poly_debug) { |
100 | 0 | tprintf("Cutline:Final perp=%d\n", perp); |
101 | 0 | } |
102 | 15.5M | if (perp > maxperp) { |
103 | 9.61M | maxperp = perp; |
104 | 9.61M | maxpoint = edge; // find greatest deviation |
105 | 9.61M | } |
106 | 15.5M | vec.x += edge->vec.x; // accumulate vectors |
107 | 15.5M | vec.y += edge->vec.y; |
108 | 15.5M | edge = edge->next; |
109 | 15.5M | } while (edge != last); // test all line |
110 | | |
111 | 7.94M | perp = vecsum.length2(); |
112 | 7.94M | ASSERT_HOST(perp != 0); |
113 | | |
114 | 7.94M | if (maxperp < 256 * INT16_MAX) { |
115 | 7.94M | maxperp <<= 8; |
116 | 7.94M | maxperp /= perp; // true max perp |
117 | 7.94M | } else { |
118 | 68 | maxperp /= perp; |
119 | 68 | maxperp <<= 8; // avoid overflow |
120 | 68 | } |
121 | 7.94M | if (squaresum < 256 * INT16_MAX) { |
122 | | // mean squared perp |
123 | 7.94M | perp = (squaresum << 8) / (perp * ptcount); |
124 | 7.94M | } else { |
125 | | // avoid overflow |
126 | 284 | perp = (squaresum / perp << 8) / ptcount; |
127 | 284 | } |
128 | | |
129 | 7.94M | if (poly_debug) { |
130 | 0 | tprintf("Cutline:A=%d, max=%.2f(%.2f%%), msd=%.2f(%.2f%%)\n", area, |
131 | 0 | maxperp / 256.0, maxperp * 200.0 / area, perp / 256.0, |
132 | 0 | perp * 300.0 / area); |
133 | 0 | } |
134 | 7.94M | if (maxperp * par1 >= 10 * area || perp * par2 >= 10 * area || vlen >= 126) { |
135 | 818k | maxpoint->fixed = true; |
136 | | // partitions |
137 | 818k | cutline(first, maxpoint, area); |
138 | 818k | cutline(maxpoint, last, area); |
139 | 818k | } |
140 | 7.94M | } |
141 | | |
142 | | /********************************************************************** |
143 | | * edgesteps_to_edgepts |
144 | | * |
145 | | * Convert a C_OUTLINE to EDGEPTs. |
146 | | **********************************************************************/ |
147 | | |
148 | | static EDGEPT *edgesteps_to_edgepts( // convert outline |
149 | | C_OUTLINE *c_outline, // input |
150 | | EDGEPT edgepts[] // output is array |
151 | 1.93M | ) { |
152 | 1.93M | int32_t length; // steps in path |
153 | 1.93M | ICOORD pos; // current coords |
154 | 1.93M | int32_t stepindex; // current step |
155 | 1.93M | int32_t stepinc; // increment |
156 | 1.93M | int32_t epindex; // current EDGEPT |
157 | 1.93M | ICOORD vec; // for this 8 step |
158 | 1.93M | ICOORD prev_vec; |
159 | 1.93M | int8_t epdir; // of this step |
160 | 1.93M | DIR128 prevdir; // previous dir |
161 | 1.93M | DIR128 dir; // of this step |
162 | | |
163 | 1.93M | pos = c_outline->start_pos(); // start of loop |
164 | 1.93M | length = c_outline->pathlength(); |
165 | 1.93M | stepindex = 0; |
166 | 1.93M | epindex = 0; |
167 | 1.93M | prevdir = -1; |
168 | | // repeated steps |
169 | 1.93M | uint32_t count = 0; |
170 | 1.93M | int prev_stepindex = 0; |
171 | 55.5M | do { |
172 | 55.5M | dir = c_outline->step_dir(stepindex); |
173 | 55.5M | vec = c_outline->step(stepindex); |
174 | 55.5M | if (stepindex < length - 1 && |
175 | 55.5M | c_outline->step_dir(stepindex + 1) - dir == -32) { |
176 | 7.94M | dir += 128 - 16; |
177 | 7.94M | vec += c_outline->step(stepindex + 1); |
178 | 7.94M | stepinc = 2; |
179 | 47.6M | } else { |
180 | 47.6M | stepinc = 1; |
181 | 47.6M | } |
182 | 55.5M | if (count == 0) { |
183 | 1.93M | prevdir = dir; |
184 | 1.93M | prev_vec = vec; |
185 | 1.93M | } |
186 | 55.5M | if (prevdir.get_dir() != dir.get_dir()) { |
187 | 22.1M | edgepts[epindex].pos.x = pos.x(); |
188 | 22.1M | edgepts[epindex].pos.y = pos.y(); |
189 | 22.1M | prev_vec *= count; |
190 | 22.1M | edgepts[epindex].vec.x = prev_vec.x(); |
191 | 22.1M | edgepts[epindex].vec.y = prev_vec.y(); |
192 | 22.1M | pos += prev_vec; |
193 | 22.1M | edgepts[epindex].runlength = count; |
194 | 22.1M | edgepts[epindex].prev = &edgepts[epindex - 1]; |
195 | | // TODO: reset is_hidden, too? |
196 | 22.1M | edgepts[epindex].fixed = false; |
197 | 22.1M | edgepts[epindex].next = &edgepts[epindex + 1]; |
198 | 22.1M | prevdir += 64; |
199 | 22.1M | epdir = DIR128(0) - prevdir; |
200 | 22.1M | epdir >>= 4; |
201 | 22.1M | epdir &= 7; |
202 | 22.1M | edgepts[epindex].dir = epdir; |
203 | 22.1M | edgepts[epindex].src_outline = c_outline; |
204 | 22.1M | edgepts[epindex].start_step = prev_stepindex; |
205 | 22.1M | edgepts[epindex].step_count = stepindex - prev_stepindex; |
206 | 22.1M | epindex++; |
207 | 22.1M | prevdir = dir; |
208 | 22.1M | prev_vec = vec; |
209 | 22.1M | count = 1; |
210 | 22.1M | prev_stepindex = stepindex; |
211 | 33.4M | } else { |
212 | 33.4M | count++; |
213 | 33.4M | } |
214 | 55.5M | stepindex += stepinc; |
215 | 55.5M | } while (stepindex < length); |
216 | 1.93M | edgepts[epindex].pos.x = pos.x(); |
217 | 1.93M | edgepts[epindex].pos.y = pos.y(); |
218 | 1.93M | prev_vec *= count; |
219 | 1.93M | edgepts[epindex].vec.x = prev_vec.x(); |
220 | 1.93M | edgepts[epindex].vec.y = prev_vec.y(); |
221 | 1.93M | pos += prev_vec; |
222 | 1.93M | edgepts[epindex].runlength = count; |
223 | | // TODO: reset is_hidden, too? |
224 | 1.93M | edgepts[epindex].fixed = false; |
225 | 1.93M | edgepts[epindex].src_outline = c_outline; |
226 | 1.93M | edgepts[epindex].start_step = prev_stepindex; |
227 | 1.93M | edgepts[epindex].step_count = stepindex - prev_stepindex; |
228 | 1.93M | edgepts[epindex].prev = &edgepts[epindex - 1]; |
229 | 1.93M | edgepts[epindex].next = &edgepts[0]; |
230 | 1.93M | prevdir += 64; |
231 | 1.93M | epdir = DIR128(0) - prevdir; |
232 | 1.93M | epdir >>= 4; |
233 | 1.93M | epdir &= 7; |
234 | 1.93M | edgepts[epindex].dir = epdir; |
235 | 1.93M | edgepts[0].prev = &edgepts[epindex]; |
236 | 1.93M | ASSERT_HOST(pos.x() == c_outline->start_pos().x() && |
237 | 1.93M | pos.y() == c_outline->start_pos().y()); |
238 | 1.93M | return &edgepts[0]; |
239 | 1.93M | } |
240 | | |
241 | | /********************************************************************** |
242 | | *fix2(start,area) fixes points on the outline according to a trial method* |
243 | | **********************************************************************/ |
244 | | |
245 | | static void fix2( // polygonal approx |
246 | | EDGEPT *start, // loop to approximate |
247 | 1.93M | int area) { |
248 | 1.93M | EDGEPT *edgept; // current point |
249 | 1.93M | EDGEPT *edgept1; |
250 | 1.93M | EDGEPT *loopstart; // modified start of loop |
251 | 1.93M | EDGEPT *linestart; // start of line segment |
252 | 1.93M | int fixed_count; // no of fixed points |
253 | 1.93M | int8_t dir; |
254 | 1.93M | int d01, d12, d23, gapmin; |
255 | 1.93M | TPOINT d01vec, d12vec, d23vec; |
256 | 1.93M | EDGEPT *edgefix, *startfix; |
257 | 1.93M | EDGEPT *edgefix0, *edgefix1, *edgefix2, *edgefix3; |
258 | | |
259 | 1.93M | edgept = start; // start of loop |
260 | 2.03M | while (((edgept->dir - edgept->prev->dir + 1) & 7) < 3 && |
261 | 2.03M | (dir = (edgept->prev->dir - edgept->next->dir) & 7) != 2 && dir != 6) { |
262 | 102k | edgept = edgept->next; // find suitable start |
263 | 102k | } |
264 | 1.93M | loopstart = edgept; // remember start |
265 | | |
266 | | // completed flag |
267 | 1.93M | bool stopped = false; |
268 | 1.93M | edgept->fixed = true; // fix it |
269 | 16.4M | do { |
270 | 16.4M | linestart = edgept; // possible start of line |
271 | 16.4M | auto dir1 = edgept->dir; // first direction |
272 | | // length of dir1 |
273 | 16.4M | auto sum1 = edgept->runlength; |
274 | 16.4M | edgept = edgept->next; |
275 | 16.4M | auto dir2 = edgept->dir; // 2nd direction |
276 | | // length in dir2 |
277 | 16.4M | auto sum2 = edgept->runlength; |
278 | 16.4M | if (((dir1 - dir2 + 1) & 7) < 3) { |
279 | 9.78M | while (edgept->prev->dir == edgept->next->dir) { |
280 | 1.85M | edgept = edgept->next; // look at next |
281 | 1.85M | if (edgept->dir == dir1) { |
282 | | // sum lengths |
283 | 1.62M | sum1 += edgept->runlength; |
284 | 1.62M | } else { |
285 | 230k | sum2 += edgept->runlength; |
286 | 230k | } |
287 | 1.85M | } |
288 | | |
289 | 7.92M | if (edgept == loopstart) { |
290 | | // finished |
291 | 185k | stopped = true; |
292 | 185k | } |
293 | 7.92M | if (sum2 + sum1 > 2 && linestart->prev->dir == dir2 && |
294 | 7.92M | (linestart->prev->runlength > linestart->runlength || sum2 > sum1)) { |
295 | | // start is back one |
296 | 166k | linestart = linestart->prev; |
297 | 166k | linestart->fixed = true; |
298 | 166k | } |
299 | | |
300 | 7.92M | if (((edgept->next->dir - edgept->dir + 1) & 7) >= 3 || |
301 | 7.92M | (edgept->dir == dir1 && sum1 >= sum2) || |
302 | 7.92M | ((edgept->prev->runlength < edgept->runlength || |
303 | 2.28M | (edgept->dir == dir2 && sum2 >= sum1)) && |
304 | 5.71M | linestart->next != edgept)) { |
305 | 5.71M | edgept = edgept->next; |
306 | 5.71M | } |
307 | 7.92M | } |
308 | | // sharp bend |
309 | 16.4M | edgept->fixed = true; |
310 | 16.4M | } |
311 | | // do whole loop |
312 | 16.4M | while (edgept != loopstart && !stopped); |
313 | | |
314 | 1.93M | edgept = start; |
315 | 24.0M | do { |
316 | 24.0M | if (((edgept->runlength >= 8) && (edgept->dir != 2) && |
317 | 24.0M | (edgept->dir != 6)) || |
318 | 24.0M | ((edgept->runlength >= 8) && |
319 | 23.8M | ((edgept->dir == 2) || (edgept->dir == 6)))) { |
320 | 1.10M | edgept->fixed = true; |
321 | 1.10M | edgept1 = edgept->next; |
322 | 1.10M | edgept1->fixed = true; |
323 | 1.10M | } |
324 | 24.0M | edgept = edgept->next; |
325 | 24.0M | } while (edgept != start); |
326 | | |
327 | 1.93M | edgept = start; |
328 | 24.0M | do { |
329 | | // single fixed step |
330 | 24.0M | if (edgept->fixed && |
331 | 24.0M | edgept->runlength == 1 |
332 | | // and neighbours free |
333 | 24.0M | && edgept->next->fixed && |
334 | 24.0M | !edgept->prev->fixed |
335 | | // same pair of dirs |
336 | 24.0M | && !edgept->next->next->fixed && |
337 | 24.0M | edgept->prev->dir == edgept->next->dir && |
338 | 24.0M | edgept->prev->prev->dir == edgept->next->next->dir && |
339 | 24.0M | ((edgept->prev->dir - edgept->dir + 1) & 7) < 3) { |
340 | | // unfix it |
341 | 60.6k | edgept->fixed = false; |
342 | 60.6k | edgept->next->fixed = false; |
343 | 60.6k | } |
344 | 24.0M | edgept = edgept->next; // do all points |
345 | 24.0M | } while (edgept != start); // until finished |
346 | | |
347 | 1.93M | stopped = false; |
348 | 1.93M | if (area < 450) { |
349 | 1.90M | area = 450; |
350 | 1.90M | } |
351 | | |
352 | 1.93M | gapmin = area * fixed_dist * fixed_dist / 44000; |
353 | | |
354 | 1.93M | edgept = start; |
355 | 1.93M | fixed_count = 0; |
356 | 24.0M | do { |
357 | 24.0M | if (edgept->fixed) { |
358 | 16.7M | fixed_count++; |
359 | 16.7M | } |
360 | 24.0M | edgept = edgept->next; |
361 | 24.0M | } while (edgept != start); |
362 | 2.02M | while (!edgept->fixed) { |
363 | 88.8k | edgept = edgept->next; |
364 | 88.8k | } |
365 | 1.93M | edgefix0 = edgept; |
366 | | |
367 | 1.93M | edgept = edgept->next; |
368 | 2.80M | while (!edgept->fixed) { |
369 | 870k | edgept = edgept->next; |
370 | 870k | } |
371 | 1.93M | edgefix1 = edgept; |
372 | | |
373 | 1.93M | edgept = edgept->next; |
374 | 2.48M | while (!edgept->fixed) { |
375 | 550k | edgept = edgept->next; |
376 | 550k | } |
377 | 1.93M | edgefix2 = edgept; |
378 | | |
379 | 1.93M | edgept = edgept->next; |
380 | 2.57M | while (!edgept->fixed) { |
381 | 642k | edgept = edgept->next; |
382 | 642k | } |
383 | 1.93M | edgefix3 = edgept; |
384 | | |
385 | 1.93M | startfix = edgefix2; |
386 | | |
387 | 14.1M | do { |
388 | 14.1M | if (fixed_count <= 3) { |
389 | 1.09M | break; // already too few |
390 | 1.09M | } |
391 | 13.0M | d12vec.diff(edgefix1->pos, edgefix2->pos); |
392 | 13.0M | d12 = d12vec.length2(); |
393 | | // TODO(rays) investigate this change: |
394 | | // Only unfix a point if it is part of a low-curvature section |
395 | | // of outline and the total angle change of the outlines is |
396 | | // less than 90 degrees, ie the scalar product is positive. |
397 | | // if (d12 <= gapmin && edgefix0->vec.dot(edgefix2->vec) > 0) { |
398 | 13.0M | if (d12 <= gapmin) { |
399 | 6.77M | d01vec.diff(edgefix0->pos, edgefix1->pos); |
400 | 6.77M | d01 = d01vec.length2(); |
401 | 6.77M | d23vec.diff(edgefix2->pos, edgefix3->pos); |
402 | 6.77M | d23 = d23vec.length2(); |
403 | 6.77M | if (d01 > d23) { |
404 | 4.02M | edgefix2->fixed = false; |
405 | 4.02M | fixed_count--; |
406 | 4.02M | } else { |
407 | 2.75M | edgefix1->fixed = false; |
408 | 2.75M | fixed_count--; |
409 | 2.75M | edgefix1 = edgefix2; |
410 | 2.75M | } |
411 | 6.77M | } else { |
412 | 6.30M | edgefix0 = edgefix1; |
413 | 6.30M | edgefix1 = edgefix2; |
414 | 6.30M | } |
415 | 13.0M | edgefix2 = edgefix3; |
416 | 13.0M | edgept = edgept->next; |
417 | 21.0M | while (!edgept->fixed) { |
418 | 7.99M | if (edgept == startfix) { |
419 | 439k | stopped = true; |
420 | 439k | } |
421 | 7.99M | edgept = edgept->next; |
422 | 7.99M | } |
423 | 13.0M | edgefix3 = edgept; |
424 | 13.0M | edgefix = edgefix2; |
425 | 13.0M | } while ((edgefix != startfix) && (!stopped)); |
426 | 1.93M | } |
427 | | |
428 | | /********************************************************************** |
429 | | *poly2(startpt,area,path) applies a second approximation to the outline |
430 | | *using the points which have been fixed by the first approximation* |
431 | | **********************************************************************/ |
432 | | |
433 | | static EDGEPT *poly2( // second poly |
434 | | EDGEPT *startpt, // start of loop |
435 | | int area // area of blob box |
436 | 1.93M | ) { |
437 | 1.93M | EDGEPT *edgept; // current outline point |
438 | 1.93M | EDGEPT *loopstart; // starting point |
439 | 1.93M | EDGEPT *linestart; // start of line |
440 | 1.93M | int edgesum; // correction count |
441 | | |
442 | 1.93M | if (area < 1200) { |
443 | 1.92M | area = 1200; // minimum value |
444 | 1.92M | } |
445 | | |
446 | 1.93M | loopstart = nullptr; // not found it yet |
447 | 1.93M | edgept = startpt; // start of loop |
448 | | |
449 | 3.01M | do { |
450 | | // current point fixed and next not |
451 | 3.01M | if (edgept->fixed && !edgept->next->fixed) { |
452 | 1.91M | loopstart = edgept; // start of repoly |
453 | 1.91M | break; |
454 | 1.91M | } |
455 | 1.09M | edgept = edgept->next; // next point |
456 | 1.09M | } while (edgept != startpt); // until found or finished |
457 | | |
458 | 1.93M | if (loopstart == nullptr && !startpt->fixed) { |
459 | | // fixed start of loop |
460 | 0 | startpt->fixed = true; |
461 | 0 | loopstart = startpt; // or start of loop |
462 | 0 | } |
463 | 1.93M | if (loopstart) { |
464 | 1.95M | do { |
465 | 1.95M | edgept = loopstart; // first to do |
466 | 7.27M | do { |
467 | 7.27M | linestart = edgept; |
468 | 7.27M | edgesum = 0; // sum of lengths |
469 | 21.4M | do { |
470 | | // sum lengths |
471 | 21.4M | edgesum += edgept->runlength; |
472 | 21.4M | edgept = edgept->next; // move on |
473 | 21.4M | } while (!edgept->fixed && edgept != loopstart && edgesum < 126); |
474 | 7.27M | if (poly_debug) { |
475 | 0 | tprintf("Poly2:starting at (%d,%d)+%d=(%d,%d),%d to (%d,%d)\n", |
476 | 0 | linestart->pos.x, linestart->pos.y, linestart->dir, |
477 | 0 | linestart->vec.x, linestart->vec.y, edgesum, edgept->pos.x, |
478 | 0 | edgept->pos.y); |
479 | 0 | } |
480 | | // reapproximate |
481 | 7.27M | cutline(linestart, edgept, area); |
482 | | |
483 | 9.98M | while (edgept->next->fixed && edgept != loopstart) { |
484 | 2.71M | edgept = edgept->next; // look for next non-fixed |
485 | 2.71M | } |
486 | 7.27M | } |
487 | | // do all the loop |
488 | 7.27M | while (edgept != loopstart); |
489 | 1.95M | edgesum = 0; |
490 | 24.1M | do { |
491 | 24.1M | if (edgept->fixed) { |
492 | 10.8M | edgesum++; |
493 | 10.8M | } |
494 | 24.1M | edgept = edgept->next; |
495 | 24.1M | } |
496 | | // count fixed pts |
497 | 24.1M | while (edgept != loopstart); |
498 | 1.95M | if (edgesum < 3) { |
499 | 41.7k | area /= 2; // must have 3 pts |
500 | 41.7k | } |
501 | 1.95M | } while (edgesum < 3); |
502 | 10.7M | do { |
503 | 10.7M | linestart = edgept; |
504 | 23.9M | do { |
505 | 23.9M | edgept = edgept->next; |
506 | 23.9M | } while (!edgept->fixed); |
507 | 10.7M | linestart->next = edgept; |
508 | 10.7M | edgept->prev = linestart; |
509 | 10.7M | linestart->vec.x = edgept->pos.x - linestart->pos.x; |
510 | 10.7M | linestart->vec.y = edgept->pos.y - linestart->pos.y; |
511 | 10.7M | } while (edgept != loopstart); |
512 | 1.91M | } else { |
513 | 20.4k | edgept = startpt; // start of loop |
514 | 20.4k | } |
515 | | |
516 | 1.93M | loopstart = edgept; // new start |
517 | 1.93M | return loopstart; // correct exit |
518 | 1.93M | } |
519 | | |
520 | | /********************************************************************** |
521 | | * tesspoly_outline |
522 | | * |
523 | | * Approximate an outline from chain codes form using the old tess algorithm. |
524 | | * If allow_detailed_fx is true, the EDGEPTs in the returned TBLOB |
525 | | * contain pointers to the input C_OUTLINEs that enable higher-resolution |
526 | | * feature extraction that does not use the polygonal approximation. |
527 | | **********************************************************************/ |
528 | | |
529 | 1.93M | TESSLINE *ApproximateOutline(bool allow_detailed_fx, C_OUTLINE *c_outline) { |
530 | 1.93M | EDGEPT stack_edgepts[FASTEDGELENGTH]; // converted path |
531 | 1.93M | EDGEPT *edgepts = stack_edgepts; |
532 | | |
533 | | // Use heap memory if the stack buffer is not big enough. |
534 | 1.93M | if (c_outline->pathlength() > FASTEDGELENGTH) { |
535 | 17.0k | edgepts = new EDGEPT[c_outline->pathlength()]; |
536 | 17.0k | } |
537 | | |
538 | | // bounding box |
539 | 1.93M | const auto &loop_box = c_outline->bounding_box(); |
540 | 1.93M | int32_t area = loop_box.height(); |
541 | 1.93M | if (!poly_wide_objects_better && loop_box.width() > area) { |
542 | 0 | area = loop_box.width(); |
543 | 0 | } |
544 | 1.93M | area *= area; |
545 | 1.93M | edgesteps_to_edgepts(c_outline, edgepts); |
546 | 1.93M | fix2(edgepts, area); |
547 | 1.93M | EDGEPT *edgept = poly2(edgepts, area); // 2nd approximation. |
548 | 1.93M | EDGEPT *startpt = edgept; |
549 | 1.93M | EDGEPT *result = nullptr; |
550 | 1.93M | EDGEPT *prev_result = nullptr; |
551 | 10.7M | do { |
552 | 10.7M | auto *new_pt = new EDGEPT; |
553 | 10.7M | new_pt->pos = edgept->pos; |
554 | 10.7M | new_pt->prev = prev_result; |
555 | 10.7M | if (prev_result == nullptr) { |
556 | 1.93M | result = new_pt; |
557 | 8.86M | } else { |
558 | 8.86M | prev_result->next = new_pt; |
559 | 8.86M | new_pt->prev = prev_result; |
560 | 8.86M | } |
561 | 10.7M | if (allow_detailed_fx) { |
562 | 0 | new_pt->src_outline = edgept->src_outline; |
563 | 0 | new_pt->start_step = edgept->start_step; |
564 | 0 | new_pt->step_count = edgept->step_count; |
565 | 0 | } |
566 | 10.7M | prev_result = new_pt; |
567 | 10.7M | edgept = edgept->next; |
568 | 10.7M | } while (edgept != startpt); |
569 | 1.93M | prev_result->next = result; |
570 | 1.93M | result->prev = prev_result; |
571 | 1.93M | if (edgepts != stack_edgepts) { |
572 | 17.0k | delete[] edgepts; |
573 | 17.0k | } |
574 | 1.93M | return TESSLINE::BuildFromOutlineList(result); |
575 | 1.93M | } |
576 | | |
577 | | } // namespace tesseract |