tesseract v5.3.3.20231005
mfoutline.cpp
Go to the documentation of this file.
1/******************************************************************************
2 ** Filename: mfoutline.c
3 ** Purpose: Interface to outline struct used for extracting features
4 ** Author: Dan Johnson
5 **
6 ** (c) Copyright Hewlett-Packard Company, 1988.
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#include "mfoutline.h"
19
20#include "blobs.h"
21#include "classify.h"
22#include "clusttool.h" //If remove you get caught in a loop somewhere
23#include "mfx.h"
24#include "params.h"
25
26#include <cmath>
27#include <cstdio>
28
29namespace tesseract {
30
31/*---------------------------------------------------------------------------*/
35 LIST outlines = NIL_LIST;
36 return (blob == nullptr) ? NIL_LIST : ConvertOutlines(blob->outlines, outlines, outer);
37}
38
39/*---------------------------------------------------------------------------*/
42 auto MFOutline = NIL_LIST;
43
44 if (outline == nullptr || outline->loop == nullptr) {
45 return MFOutline;
46 }
47
48 auto StartPoint = outline->loop;
49 auto EdgePoint = StartPoint;
50 do {
51 auto NextPoint = EdgePoint->next;
52
53 /* filter out duplicate points */
54 if (EdgePoint->pos.x != NextPoint->pos.x || EdgePoint->pos.y != NextPoint->pos.y) {
55 auto NewPoint = new MFEDGEPT;
56 NewPoint->ClearMark();
57 NewPoint->Hidden = EdgePoint->IsHidden();
58 NewPoint->Point.x = EdgePoint->pos.x;
59 NewPoint->Point.y = EdgePoint->pos.y;
60 MFOutline = push(MFOutline, NewPoint);
61 }
62 EdgePoint = NextPoint;
63 } while (EdgePoint != StartPoint);
64
65 if (MFOutline != nullptr) {
66 MakeOutlineCircular(MFOutline);
67 }
68 return MFOutline;
69}
70
71/*---------------------------------------------------------------------------*/
79LIST ConvertOutlines(TESSLINE *outline, LIST mf_outlines, OUTLINETYPE outline_type) {
80 MFOUTLINE mf_outline;
81
82 while (outline != nullptr) {
83 mf_outline = ConvertOutline(outline);
84 if (mf_outline != nullptr) {
85 mf_outlines = push(mf_outlines, mf_outline);
86 }
87 outline = outline->next;
88 }
89 return mf_outlines;
90}
91
92/*---------------------------------------------------------------------------*/
104void FindDirectionChanges(MFOUTLINE Outline, float MinSlope, float MaxSlope) {
105 MFEDGEPT *Current;
106 MFEDGEPT *Last;
107 MFOUTLINE EdgePoint;
108
109 if (DegenerateOutline(Outline)) {
110 return;
111 }
112
113 Last = PointAt(Outline);
114 Outline = NextPointAfter(Outline);
115 EdgePoint = Outline;
116 do {
117 Current = PointAt(EdgePoint);
118 ComputeDirection(Last, Current, MinSlope, MaxSlope);
119
120 Last = Current;
121 EdgePoint = NextPointAfter(EdgePoint);
122 } while (EdgePoint != Outline);
123
124} /* FindDirectionChanges */
125
126/*---------------------------------------------------------------------------*/
132void FreeMFOutline(void *arg) { // MFOUTLINE Outline)
133 auto Outline = static_cast<MFOUTLINE>(arg);
134
135 /* break the circular outline so we can use std. techniques to deallocate */
136 MFOUTLINE Start = Outline->list_rest();
137 set_rest(Outline, NIL_LIST);
138 while (Start != nullptr) {
139 delete reinterpret_cast<MFEDGEPT *>(Start->first_node());
140 Start = pop(Start);
141 }
142
143} /* FreeMFOutline */
144
145/*---------------------------------------------------------------------------*/
151void FreeOutlines(LIST Outlines) {
152 destroy_nodes(Outlines, FreeMFOutline);
153} /* FreeOutlines */
154
155/*---------------------------------------------------------------------------*/
167 MFOUTLINE Current;
168 MFOUTLINE Last;
169 MFOUTLINE First;
170
171 if (DegenerateOutline(Outline)) {
172 return;
173 }
174
175 First = NextDirectionChange(Outline);
176 Last = First;
177 do {
178 Current = NextDirectionChange(Last);
179 PointAt(Current)->MarkPoint();
180 Last = Current;
181 } while (Last != First);
182
183} /* MarkDirectionChanges */
184
185/*---------------------------------------------------------------------------*/
197 EdgePoint = NextPointAfter(EdgePoint);
198 while (!PointAt(EdgePoint)->ExtremityMark) {
199 EdgePoint = NextPointAfter(EdgePoint);
200 }
201
202 return (EdgePoint);
203
204} /* NextExtremity */
205
206/*---------------------------------------------------------------------------*/
218void NormalizeOutline(MFOUTLINE Outline, float XOrigin) {
219 if (Outline == NIL_LIST) {
220 return;
221 }
222
223 MFOUTLINE EdgePoint = Outline;
224 do {
225 MFEDGEPT *Current = PointAt(EdgePoint);
226 Current->Point.y = MF_SCALE_FACTOR * (Current->Point.y - kBlnBaselineOffset);
227 Current->Point.x = MF_SCALE_FACTOR * (Current->Point.x - XOrigin);
228 EdgePoint = NextPointAfter(EdgePoint);
229 } while (EdgePoint != Outline);
230} /* NormalizeOutline */
231
232/*---------------------------------------------------------------------------*/
249void Classify::NormalizeOutlines(LIST Outlines, float *XScale, float *YScale) {
250 MFOUTLINE Outline;
251
252 switch (classify_norm_method) {
253 case character:
254 ASSERT_HOST(!"How did NormalizeOutlines get called in character mode?");
255 break;
256
257 case baseline:
258 iterate(Outlines) {
259 Outline = static_cast<MFOUTLINE>(Outlines->first_node());
260 NormalizeOutline(Outline, 0.0);
261 }
262 *XScale = *YScale = MF_SCALE_FACTOR;
263 break;
264 }
265} /* NormalizeOutlines */
266
267/*----------------------------------------------------------------------------
268 Private Code
269----------------------------------------------------------------------------*/
280void ChangeDirection(MFOUTLINE Start, MFOUTLINE End, DIRECTION Direction) {
281 MFOUTLINE Current;
282
283 for (Current = Start; Current != End; Current = NextPointAfter(Current)) {
284 PointAt(Current)->Direction = Direction;
285 }
286
287 PointAt(End)->PreviousDirection = Direction;
288
289} /* ChangeDirection */
290
298void CharNormalizeOutline(MFOUTLINE Outline, const DENORM &cn_denorm) {
299 MFOUTLINE First, Current;
300 MFEDGEPT *CurrentPoint;
301
302 if (Outline == NIL_LIST) {
303 return;
304 }
305
306 First = Outline;
307 Current = First;
308 do {
309 CurrentPoint = PointAt(Current);
310 FCOORD pos(CurrentPoint->Point.x, CurrentPoint->Point.y);
311 cn_denorm.LocalNormTransform(pos, &pos);
312 CurrentPoint->Point.x = (pos.x() - UINT8_MAX / 2) * MF_SCALE_FACTOR;
313 CurrentPoint->Point.y = (pos.y() - UINT8_MAX / 2) * MF_SCALE_FACTOR;
314
315 Current = NextPointAfter(Current);
316 } while (Current != First);
317
318} /* CharNormalizeOutline */
319
335void ComputeDirection(MFEDGEPT *Start, MFEDGEPT *Finish, float MinSlope, float MaxSlope) {
336 FVECTOR Delta;
337
338 Delta.x = Finish->Point.x - Start->Point.x;
339 Delta.y = Finish->Point.y - Start->Point.y;
340 if (Delta.x == 0) {
341 if (Delta.y < 0) {
342 Start->Slope = -FLT_MAX;
343 Start->Direction = south;
344 } else {
345 Start->Slope = FLT_MAX;
346 Start->Direction = north;
347 }
348 } else {
349 Start->Slope = Delta.y / Delta.x;
350 if (Delta.x > 0) {
351 if (Delta.y > 0) {
352 if (Start->Slope > MinSlope) {
353 if (Start->Slope < MaxSlope) {
354 Start->Direction = northeast;
355 } else {
356 Start->Direction = north;
357 }
358 } else {
359 Start->Direction = east;
360 }
361 } else if (Start->Slope < -MinSlope) {
362 if (Start->Slope > -MaxSlope) {
363 Start->Direction = southeast;
364 } else {
365 Start->Direction = south;
366 }
367 } else {
368 Start->Direction = east;
369 }
370 } else if (Delta.y > 0) {
371 if (Start->Slope < -MinSlope) {
372 if (Start->Slope > -MaxSlope) {
373 Start->Direction = northwest;
374 } else {
375 Start->Direction = north;
376 }
377 } else {
378 Start->Direction = west;
379 }
380 } else if (Start->Slope > MinSlope) {
381 if (Start->Slope < MaxSlope) {
382 Start->Direction = southwest;
383 } else {
384 Start->Direction = south;
385 }
386 } else {
387 Start->Direction = west;
388 }
389 }
390 Finish->PreviousDirection = Start->Direction;
391}
392
403 DIRECTION InitialDirection;
404
405 InitialDirection = PointAt(EdgePoint)->Direction;
406
407 MFOUTLINE next_pt = nullptr;
408 do {
409 EdgePoint = NextPointAfter(EdgePoint);
410 next_pt = NextPointAfter(EdgePoint);
411 } while (PointAt(EdgePoint)->Direction == InitialDirection && !PointAt(EdgePoint)->Hidden &&
412 next_pt != nullptr && !PointAt(next_pt)->Hidden);
413
414 return (EdgePoint);
415}
416
417} // namespace tesseract
#define ASSERT_HOST(x)
Definition: errcode.h:54
#define iterate(l)
Definition: oldlist.h:91
#define set_rest(l, cell)
Definition: oldlist.h:101
#define NIL_LIST
Definition: oldlist.h:75
void FreeOutlines(LIST Outlines)
Definition: mfoutline.cpp:151
void MarkDirectionChanges(MFOUTLINE Outline)
Definition: mfoutline.cpp:166
@ northeast
Definition: mfoutline.h:30
@ southeast
Definition: mfoutline.h:30
@ northwest
Definition: mfoutline.h:30
@ southwest
Definition: mfoutline.h:30
@ character
Definition: mfoutline.h:53
@ baseline
Definition: mfoutline.h:53
LIST ConvertBlob(TBLOB *blob)
Definition: mfoutline.cpp:34
void CharNormalizeOutline(MFOUTLINE Outline, const DENORM &cn_denorm)
Definition: mfoutline.cpp:298
const float MF_SCALE_FACTOR
Definition: mfoutline.h:61
MFOUTLINE ConvertOutline(TESSLINE *outline)
Definition: mfoutline.cpp:41
void ChangeDirection(MFOUTLINE Start, MFOUTLINE End, DIRECTION Direction)
Definition: mfoutline.cpp:280
void FreeMFOutline(void *arg)
Definition: mfoutline.cpp:132
LIST ConvertOutlines(TESSLINE *outline, LIST mf_outlines, OUTLINETYPE outline_type)
Definition: mfoutline.cpp:79
LIST pop(LIST list)
Definition: oldlist.cpp:166
MFOUTLINE NextExtremity(MFOUTLINE EdgePoint)
Definition: mfoutline.cpp:196
void ComputeDirection(MFEDGEPT *Start, MFEDGEPT *Finish, float MinSlope, float MaxSlope)
Definition: mfoutline.cpp:335
LIST push(LIST list, void *element)
Definition: oldlist.cpp:178
void destroy_nodes(LIST list, void_dest destructor)
Definition: oldlist.cpp:137
void FindDirectionChanges(MFOUTLINE Outline, float MinSlope, float MaxSlope)
Definition: mfoutline.cpp:104
void NormalizeOutline(MFOUTLINE Outline, float XOrigin)
Definition: mfoutline.cpp:218
const int kBlnBaselineOffset
Definition: normalis.h:34
MFOUTLINE NextDirectionChange(MFOUTLINE EdgePoint)
Definition: mfoutline.cpp:402
EDGEPT * next
Definition: blobs.h:200
EDGEPT * loop
Definition: blobs.h:287
TESSLINE * next
Definition: blobs.h:288
TESSLINE * outlines
Definition: blobs.h:404
void LocalNormTransform(const TPOINT &pt, TPOINT *transformed) const
Definition: normalis.cpp:310
float y() const
Definition: points.h:209
float x() const
Definition: points.h:206
void NormalizeOutlines(LIST Outlines, float *XScale, float *YScale)
Definition: mfoutline.cpp:249
Definition: fpoint.h:29
float y
Definition: fpoint.h:30
float x
Definition: fpoint.h:30
DIRECTION Direction
Definition: mfoutline.h:47
DIRECTION PreviousDirection
Definition: mfoutline.h:48
list_rec * list_rest()
Definition: oldlist.h:111
list_rec * first_node()
Definition: oldlist.h:107