forked from arthenica/tesseract
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathedgloop.cpp
157 lines (140 loc) · 5.22 KB
/
edgloop.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/**********************************************************************
* File: edgloop.cpp (Formerly edgeloop.c)
* Description: Functions to clean up an outline before approximation.
* Author: Ray Smith
*
* (C) Copyright 1991, Hewlett-Packard Ltd.
** 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.
*
**********************************************************************/
// Include automatically generated configuration file if running autoconf.
#ifdef HAVE_CONFIG_H
# include "config_auto.h"
#endif
#include "scanedg.h"
#include "edgloop.h"
namespace tesseract {
#define MINEDGELENGTH 8 // min decent length
/**********************************************************************
* complete_edge
*
* Complete the edge by cleaning it up.
**********************************************************************/
void complete_edge(CRACKEDGE *start, // start of loop
C_OUTLINE_IT *outline_it) {
ScrollView::Color colour; // colour to draw in
int16_t looplength; // steps in loop
ICOORD botleft; // bounding box
ICOORD topright;
C_OUTLINE *outline; // new outline
// check length etc.
colour = check_path_legal(start);
if (colour == ScrollView::RED || colour == ScrollView::BLUE) {
looplength = loop_bounding_box(start, botleft, topright);
outline = new C_OUTLINE(start, botleft, topright, looplength);
// add to list
outline_it->add_after_then_move(outline);
}
}
/**********************************************************************
* check_path_legal
*
* Check that the outline is legal for length and for chaincode sum.
* The return value is RED for a normal black-inside outline,
* BLUE for a white-inside outline, MAGENTA if it is too short,
* YELLOW if it is too long, and GREEN if it is illegal.
* These colours are used to draw the raw outline.
**********************************************************************/
ScrollView::Color check_path_legal( // certify outline
CRACKEDGE *start // start of loop
) {
int lastchain; // last chain code
int chaindiff; // chain code diff
int32_t length; // length of loop
int32_t chainsum; // sum of chain diffs
CRACKEDGE *edgept; // current point
constexpr ERRCODE ED_ILLEGAL_SUM("Illegal sum of chain codes");
length = 0;
chainsum = 0; // sum of chain codes
edgept = start;
lastchain = edgept->prev->stepdir; // previous chain code
do {
length++;
if (edgept->stepdir != lastchain) {
// chain code difference
chaindiff = edgept->stepdir - lastchain;
if (chaindiff > 2) {
chaindiff -= 4;
} else if (chaindiff < -2) {
chaindiff += 4;
}
chainsum += chaindiff; // sum differences
lastchain = edgept->stepdir;
}
edgept = edgept->next;
} while (edgept != start && length < C_OUTLINE::kMaxOutlineLength);
if ((chainsum != 4 && chainsum != -4) || edgept != start || length < MINEDGELENGTH) {
if (edgept != start) {
return ScrollView::YELLOW;
} else if (length < MINEDGELENGTH) {
return ScrollView::MAGENTA;
} else {
ED_ILLEGAL_SUM.error("check_path_legal", TESSLOG, "chainsum=%d", chainsum);
return ScrollView::GREEN;
}
}
// colour on inside
return chainsum < 0 ? ScrollView::BLUE : ScrollView::RED;
}
/**********************************************************************
* loop_bounding_box
*
* Find the bounding box of the edge loop.
**********************************************************************/
int16_t loop_bounding_box( // get bounding box
CRACKEDGE *&start, // edge loop
ICOORD &botleft, // bounding box
ICOORD &topright) {
int16_t length; // length of loop
int16_t leftmost; // on top row
CRACKEDGE *edgept; // current point
CRACKEDGE *realstart; // topleft start
edgept = start;
realstart = start;
botleft = topright = ICOORD(edgept->pos.x(), edgept->pos.y());
leftmost = edgept->pos.x();
length = 0; // coutn length
do {
edgept = edgept->next;
if (edgept->pos.x() < botleft.x()) {
// get bounding box
botleft.set_x(edgept->pos.x());
} else if (edgept->pos.x() > topright.x()) {
topright.set_x(edgept->pos.x());
}
if (edgept->pos.y() < botleft.y()) {
// get bounding box
botleft.set_y(edgept->pos.y());
} else if (edgept->pos.y() > topright.y()) {
realstart = edgept;
leftmost = edgept->pos.x();
topright.set_y(edgept->pos.y());
} else if (edgept->pos.y() == topright.y() && edgept->pos.x() < leftmost) {
// leftmost on line
leftmost = edgept->pos.x();
realstart = edgept;
}
length++; // count elements
} while (edgept != start);
start = realstart; // shift it to topleft
return length;
}
} // namespace tesseract