• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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