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