1 /**********************************************************************
2 * File: edgloop.c (Formerly edgeloop.c)
3 * Description: Functions to clean up an outline before approximation.
4 * Author: Ray Smith
5 * Created: Tue Mar 26 16:56:25 GMT 1991
6 *
7 * (C) Copyright 1991, Hewlett-Packard Ltd.
8 ** Licensed under the Apache License, Version 2.0 (the "License");
9 ** you may not use this file except in compliance with the License.
10 ** You may obtain a copy of the License at
11 ** http://www.apache.org/licenses/LICENSE-2.0
12 ** Unless required by applicable law or agreed to in writing, software
13 ** distributed under the License is distributed on an "AS IS" BASIS,
14 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 ** See the License for the specific language governing permissions and
16 ** limitations under the License.
17 *
18 **********************************************************************/
19
20 #include "mfcpch.h"
21 #include "scanedg.h"
22 #include "drawedg.h"
23 #include "edgloop.h"
24
25 #define MINEDGELENGTH 8 //min decent length
26
27 #define EXTERN
28
29 EXTERN double_VAR (edges_threshold_greyfraction, 0.07,
30 "Min edge diff for grad vector");
31 EXTERN BOOL_VAR (edges_show_paths, FALSE, "Draw raw outlines");
32 EXTERN BOOL_VAR (edges_show_needles, FALSE, "Draw edge needles");
33 EXTERN INT_VAR (edges_maxedgelength, 16000, "Max steps in any outline");
34
35 #ifndef GRAPHICS_DISABLED
36 static ScrollView* edge_win; //window
37 #endif
38 static C_OUTLINE_IT *outline_it; //iterator
39 static int short_edges; //no of short ones
40 static int long_edges; //no of long ones
41
42 /**********************************************************************
43 * get_outlines
44 *
45 * Run the edge detector over the block and return a list of outlines.
46 **********************************************************************/
47
get_outlines(ScrollView * window,IMAGE * image,IMAGE * t_image,ICOORD page_tr,PDBLK * block,C_OUTLINE_IT * out_it)48 DLLSYM void get_outlines( //edge detect
49 #ifndef GRAPHICS_DISABLED
50 ScrollView* window, //window for output
51 #endif
52 IMAGE *image, //image to scan
53 IMAGE *t_image, //thresholded image
54 ICOORD page_tr, //corner of page
55 PDBLK *block, //block to scan
56 C_OUTLINE_IT *out_it //output iterator
57 ) {
58 #ifndef GRAPHICS_DISABLED
59 edge_win = window; //set statics
60 #endif
61 outline_it = out_it;
62 block_edges(t_image, block, page_tr);
63 out_it->move_to_first ();
64 #ifndef GRAPHICS_DISABLED
65 if (window != NULL)
66 // overlap_picture_ops(TRUE); //update window
67 ScrollView::Update();
68 #endif
69 }
70
71
72 /**********************************************************************
73 * complete_edge
74 *
75 * Complete the edge by cleaning it up andapproximating it.
76 **********************************************************************/
77
complete_edge(CRACKEDGE * start)78 void complete_edge( //clean and approximate
79 CRACKEDGE *start //start of loop
80 ) {
81 ScrollView::Color colour; //colour to draw in
82 inT16 looplength; //steps in loop
83 ICOORD botleft; //bounding box
84 ICOORD topright;
85 C_OUTLINE *outline; //new outline
86
87 //check length etc.
88 colour = check_path_legal (start);
89 #ifndef GRAPHICS_DISABLED
90 if (edges_show_paths) {
91 //in red
92 draw_raw_edge(edge_win, start, colour);
93 }
94 #endif
95
96 if (colour == ScrollView::RED || colour == ScrollView::BLUE) {
97 looplength = loop_bounding_box (start, botleft, topright);
98 outline = new C_OUTLINE (start, botleft, topright, looplength);
99 //add to list
100 outline_it->add_after_then_move (outline);
101 }
102 }
103
104
105 /**********************************************************************
106 * check_path_legal
107 *
108 * Check that the outline is legal for length and for chaincode sum.
109 * The return value is RED for a normal black-inside outline,
110 * BLUE for a white-inside outline, MAGENTA if it is too short,
111 * YELLOW if it is too long, and GREEN if it is illegal.
112 * These colours are used to draw the raw outline.
113 **********************************************************************/
114
check_path_legal(CRACKEDGE * start)115 ScrollView::Color check_path_legal( //certify outline
116 CRACKEDGE *start //start of loop
117 ) {
118 int lastchain; //last chain code
119 int chaindiff; //chain code diff
120 inT32 length; //length of loop
121 inT32 chainsum; //sum of chain diffs
122 CRACKEDGE *edgept; //current point
123 const ERRCODE ED_ILLEGAL_SUM = "Illegal sum of chain codes";
124
125 length = 0;
126 chainsum = 0; //sum of chain codes
127 edgept = start;
128 lastchain = edgept->prev->stepdir; //previous chain code
129 do {
130 length++;
131 if (edgept->stepdir != lastchain) {
132 //chain code difference
133 chaindiff = edgept->stepdir - lastchain;
134 if (chaindiff > 2)
135 chaindiff -= 4;
136 else if (chaindiff < -2)
137 chaindiff += 4;
138 chainsum += chaindiff; //sum differences
139 lastchain = edgept->stepdir;
140 }
141 edgept = edgept->next;
142 }
143 while (edgept != start && length < edges_maxedgelength);
144
145 if ((chainsum != 4 && chainsum != -4)
146 || edgept != start || length < MINEDGELENGTH) {
147 if (edgept != start) {
148 long_edges++;
149 return ScrollView::YELLOW;
150 }
151 else if (length < MINEDGELENGTH) {
152 short_edges++;
153 return ScrollView::MAGENTA;
154 }
155 else {
156 ED_ILLEGAL_SUM.error ("check_path_legal", TESSLOG, "chainsum=%d",
157 chainsum);
158 return ScrollView::GREEN;
159 }
160 }
161 //colour on inside
162 return chainsum < 0 ? ScrollView::BLUE : ScrollView::RED;
163 }
164
165 /**********************************************************************
166 * loop_bounding_box
167 *
168 * Find the bounding box of the edge loop.
169 **********************************************************************/
170
loop_bounding_box(CRACKEDGE * & start,ICOORD & botleft,ICOORD & topright)171 inT16 loop_bounding_box( //get bounding box
172 CRACKEDGE *&start, //edge loop
173 ICOORD &botleft, //bounding box
174 ICOORD &topright) {
175 inT16 length; //length of loop
176 inT16 leftmost; //on top row
177 CRACKEDGE *edgept; //current point
178 CRACKEDGE *realstart; //topleft start
179
180 edgept = start;
181 realstart = start;
182 botleft = topright = ICOORD (edgept->pos.x (), edgept->pos.y ());
183 leftmost = edgept->pos.x ();
184 length = 0; //coutn length
185 do {
186 edgept = edgept->next;
187 if (edgept->pos.x () < botleft.x ())
188 //get bounding box
189 botleft.set_x (edgept->pos.x ());
190 else if (edgept->pos.x () > topright.x ())
191 topright.set_x (edgept->pos.x ());
192 if (edgept->pos.y () < botleft.y ())
193 //get bounding box
194 botleft.set_y (edgept->pos.y ());
195 else if (edgept->pos.y () > topright.y ()) {
196 realstart = edgept;
197 leftmost = edgept->pos.x ();
198 topright.set_y (edgept->pos.y ());
199 }
200 else if (edgept->pos.y () == topright.y ()
201 && edgept->pos.x () < leftmost) {
202 //leftmost on line
203 leftmost = edgept->pos.x ();
204 realstart = edgept;
205 }
206 length++; //count elements
207 }
208 while (edgept != start);
209 start = realstart; //shift it to topleft
210 return length;
211 }
212