tesseract
3.03
|
00001 /********************************************************************** 00002 * File: scanedg.c (Formerly scanedge.c) 00003 * Description: Raster scanning crack based edge extractor. 00004 * Author: Ray Smith 00005 * Created: Fri Mar 22 16:11:50 GMT 1991 00006 * 00007 * (C) Copyright 1991, Hewlett-Packard Ltd. 00008 ** Licensed under the Apache License, Version 2.0 (the "License"); 00009 ** you may not use this file except in compliance with the License. 00010 ** You may obtain a copy of the License at 00011 ** http://www.apache.org/licenses/LICENSE-2.0 00012 ** Unless required by applicable law or agreed to in writing, software 00013 ** distributed under the License is distributed on an "AS IS" BASIS, 00014 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00015 ** See the License for the specific language governing permissions and 00016 ** limitations under the License. 00017 * 00018 **********************************************************************/ 00019 00020 #include "scanedg.h" 00021 00022 #include "allheaders.h" 00023 #include "edgloop.h" 00024 00025 #define WHITE_PIX 1 /*thresholded colours */ 00026 #define BLACK_PIX 0 00027 /*W->B->W */ 00028 #define FLIP_COLOUR(pix) (1-(pix)) 00029 00030 /********************************************************************** 00031 * block_edges 00032 * 00033 * Extract edges from a PDBLK. 00034 **********************************************************************/ 00035 00036 void block_edges(Pix *t_pix, // thresholded image 00037 PDBLK *block, // block in image 00038 C_OUTLINE_IT* outline_it) { 00039 ICOORD bleft; // bounding box 00040 ICOORD tright; 00041 BLOCK_LINE_IT line_it = block; // line iterator 00042 00043 int width = pixGetWidth(t_pix); 00044 int height = pixGetHeight(t_pix); 00045 int wpl = pixGetWpl(t_pix); 00046 // lines in progress 00047 CRACKEDGE **ptrline = new CRACKEDGE*[width + 1]; 00048 CRACKEDGE *free_cracks = NULL; 00049 00050 block->bounding_box(bleft, tright); // block box 00051 int block_width = tright.x() - bleft.x(); 00052 for (int x = block_width; x >= 0; x--) 00053 ptrline[x] = NULL; // no lines in progress 00054 00055 uinT8* bwline = new uinT8[width]; 00056 00057 uinT8 margin = WHITE_PIX; 00058 00059 for (int y = tright.y() - 1; y >= bleft.y() - 1; y--) { 00060 if (y >= bleft.y() && y < tright.y()) { 00061 // Get the binary pixels from the image. 00062 l_uint32* line = pixGetData(t_pix) + wpl * (height - 1 - y); 00063 for (int x = 0; x < block_width; ++x) { 00064 bwline[x] = GET_DATA_BIT(line, x + bleft.x()) ^ 1; 00065 } 00066 make_margins(block, &line_it, bwline, margin, bleft.x(), tright.x(), y); 00067 } else { 00068 memset(bwline, margin, block_width * sizeof(bwline[0])); 00069 } 00070 line_edges(bleft.x(), y, block_width, 00071 margin, bwline, ptrline, &free_cracks, outline_it); 00072 } 00073 00074 free_crackedges(free_cracks); // really free them 00075 delete[] ptrline; 00076 delete[] bwline; 00077 } 00078 00079 00080 /********************************************************************** 00081 * make_margins 00082 * 00083 * Get an image line and set to margin non-text pixels. 00084 **********************************************************************/ 00085 00086 void make_margins( //get a line 00087 PDBLK *block, //block in image 00088 BLOCK_LINE_IT *line_it, //for old style 00089 uinT8 *pixels, //pixels to strip 00090 uinT8 margin, //white-out pixel 00091 inT16 left, //block edges 00092 inT16 right, 00093 inT16 y //line coord 00094 ) { 00095 PB_LINE_IT *lines; 00096 ICOORDELT_LIST *segments; //bits of a line 00097 ICOORDELT_IT seg_it; 00098 inT32 start; //of segment 00099 inT16 xext; //of segment 00100 int xindex; //index to pixel 00101 00102 if (block->poly_block () != NULL) { 00103 lines = new PB_LINE_IT (block->poly_block ()); 00104 segments = lines->get_line (y); 00105 if (!segments->empty ()) { 00106 seg_it.set_to_list (segments); 00107 seg_it.mark_cycle_pt (); 00108 start = seg_it.data ()->x (); 00109 xext = seg_it.data ()->y (); 00110 for (xindex = left; xindex < right; xindex++) { 00111 if (xindex >= start && !seg_it.cycled_list ()) { 00112 xindex = start + xext - 1; 00113 seg_it.forward (); 00114 start = seg_it.data ()->x (); 00115 xext = seg_it.data ()->y (); 00116 } 00117 else 00118 pixels[xindex - left] = margin; 00119 } 00120 } 00121 else { 00122 for (xindex = left; xindex < right; xindex++) 00123 pixels[xindex - left] = margin; 00124 } 00125 delete segments; 00126 delete lines; 00127 } 00128 else { 00129 start = line_it->get_line (y, xext); 00130 for (xindex = left; xindex < start; xindex++) 00131 pixels[xindex - left] = margin; 00132 for (xindex = start + xext; xindex < right; xindex++) 00133 pixels[xindex - left] = margin; 00134 } 00135 } 00136 00137 /********************************************************************** 00138 * line_edges 00139 * 00140 * Scan a line for edges and update the edges in progress. 00141 * When edges close into loops, send them for approximation. 00142 **********************************************************************/ 00143 00144 void line_edges(inT16 x, // coord of line start 00145 inT16 y, // coord of line 00146 inT16 xext, // width of line 00147 uinT8 uppercolour, // start of prev line 00148 uinT8 * bwpos, // thresholded line 00149 CRACKEDGE ** prevline, // edges in progress 00150 CRACKEDGE **free_cracks, 00151 C_OUTLINE_IT* outline_it) { 00152 CrackPos pos = {free_cracks, x, y }; 00153 int xmax; // max x coord 00154 int colour; // of current pixel 00155 int prevcolour; // of previous pixel 00156 CRACKEDGE *current; // current h edge 00157 CRACKEDGE *newcurrent; // new h edge 00158 00159 xmax = x + xext; // max allowable coord 00160 prevcolour = uppercolour; // forced plain margin 00161 current = NULL; // nothing yet 00162 00163 // do each pixel 00164 for (; pos.x < xmax; pos.x++, prevline++) { 00165 colour = *bwpos++; // current pixel 00166 if (*prevline != NULL) { 00167 // changed above 00168 // change colour 00169 uppercolour = FLIP_COLOUR(uppercolour); 00170 if (colour == prevcolour) { 00171 if (colour == uppercolour) { 00172 // finish a line 00173 join_edges(current, *prevline, free_cracks, outline_it); 00174 current = NULL; // no edge now 00175 } else { 00176 // new horiz edge 00177 current = h_edge(uppercolour - colour, *prevline, &pos); 00178 } 00179 *prevline = NULL; // no change this time 00180 } else { 00181 if (colour == uppercolour) 00182 *prevline = v_edge(colour - prevcolour, *prevline, &pos); 00183 // 8 vs 4 connection 00184 else if (colour == WHITE_PIX) { 00185 join_edges(current, *prevline, free_cracks, outline_it); 00186 current = h_edge(uppercolour - colour, NULL, &pos); 00187 *prevline = v_edge(colour - prevcolour, current, &pos); 00188 } else { 00189 newcurrent = h_edge(uppercolour - colour, *prevline, &pos); 00190 *prevline = v_edge(colour - prevcolour, current, &pos); 00191 current = newcurrent; // right going h edge 00192 } 00193 prevcolour = colour; // remember new colour 00194 } 00195 } else { 00196 if (colour != prevcolour) { 00197 *prevline = current = v_edge(colour - prevcolour, current, &pos); 00198 prevcolour = colour; 00199 } 00200 if (colour != uppercolour) 00201 current = h_edge(uppercolour - colour, current, &pos); 00202 else 00203 current = NULL; // no edge now 00204 } 00205 } 00206 if (current != NULL) { 00207 // out of block 00208 if (*prevline != NULL) { // got one to join to? 00209 join_edges(current, *prevline, free_cracks, outline_it); 00210 *prevline = NULL; // tidy now 00211 } else { 00212 // fake vertical 00213 *prevline = v_edge(FLIP_COLOUR(prevcolour)-prevcolour, current, &pos); 00214 } 00215 } else if (*prevline != NULL) { 00216 //continue fake 00217 *prevline = v_edge(FLIP_COLOUR(prevcolour)-prevcolour, *prevline, &pos); 00218 } 00219 } 00220 00221 00222 /********************************************************************** 00223 * h_edge 00224 * 00225 * Create a new horizontal CRACKEDGE and join it to the given edge. 00226 **********************************************************************/ 00227 00228 CRACKEDGE *h_edge(int sign, // sign of edge 00229 CRACKEDGE* join, // edge to join to 00230 CrackPos* pos) { 00231 CRACKEDGE *newpt; // return value 00232 00233 if (*pos->free_cracks != NULL) { 00234 newpt = *pos->free_cracks; 00235 *pos->free_cracks = newpt->next; // get one fast 00236 } else { 00237 newpt = new CRACKEDGE; 00238 } 00239 newpt->pos.set_y(pos->y + 1); // coords of pt 00240 newpt->stepy = 0; // edge is horizontal 00241 00242 if (sign > 0) { 00243 newpt->pos.set_x(pos->x + 1); // start location 00244 newpt->stepx = -1; 00245 newpt->stepdir = 0; 00246 } else { 00247 newpt->pos.set_x(pos->x); // start location 00248 newpt->stepx = 1; 00249 newpt->stepdir = 2; 00250 } 00251 00252 if (join == NULL) { 00253 newpt->next = newpt; // ptrs to other ends 00254 newpt->prev = newpt; 00255 } else { 00256 if (newpt->pos.x() + newpt->stepx == join->pos.x() 00257 && newpt->pos.y() == join->pos.y()) { 00258 newpt->prev = join->prev; // update other ends 00259 newpt->prev->next = newpt; 00260 newpt->next = join; // join up 00261 join->prev = newpt; 00262 } else { 00263 newpt->next = join->next; // update other ends 00264 newpt->next->prev = newpt; 00265 newpt->prev = join; // join up 00266 join->next = newpt; 00267 } 00268 } 00269 return newpt; 00270 } 00271 00272 00273 /********************************************************************** 00274 * v_edge 00275 * 00276 * Create a new vertical CRACKEDGE and join it to the given edge. 00277 **********************************************************************/ 00278 00279 CRACKEDGE *v_edge(int sign, // sign of edge 00280 CRACKEDGE* join, 00281 CrackPos* pos) { 00282 CRACKEDGE *newpt; // return value 00283 00284 if (*pos->free_cracks != NULL) { 00285 newpt = *pos->free_cracks; 00286 *pos->free_cracks = newpt->next; // get one fast 00287 } else { 00288 newpt = new CRACKEDGE; 00289 } 00290 newpt->pos.set_x(pos->x); // coords of pt 00291 newpt->stepx = 0; // edge is vertical 00292 00293 if (sign > 0) { 00294 newpt->pos.set_y(pos->y); // start location 00295 newpt->stepy = 1; 00296 newpt->stepdir = 3; 00297 } else { 00298 newpt->pos.set_y(pos->y + 1); // start location 00299 newpt->stepy = -1; 00300 newpt->stepdir = 1; 00301 } 00302 00303 if (join == NULL) { 00304 newpt->next = newpt; //ptrs to other ends 00305 newpt->prev = newpt; 00306 } else { 00307 if (newpt->pos.x() == join->pos.x() 00308 && newpt->pos.y() + newpt->stepy == join->pos.y()) { 00309 newpt->prev = join->prev; // update other ends 00310 newpt->prev->next = newpt; 00311 newpt->next = join; // join up 00312 join->prev = newpt; 00313 } else { 00314 newpt->next = join->next; // update other ends 00315 newpt->next->prev = newpt; 00316 newpt->prev = join; // join up 00317 join->next = newpt; 00318 } 00319 } 00320 return newpt; 00321 } 00322 00323 00324 /********************************************************************** 00325 * join_edges 00326 * 00327 * Join 2 edges together. Send the outline for approximation when a 00328 * closed loop is formed. 00329 **********************************************************************/ 00330 00331 void join_edges(CRACKEDGE *edge1, // edges to join 00332 CRACKEDGE *edge2, // no specific order 00333 CRACKEDGE **free_cracks, 00334 C_OUTLINE_IT* outline_it) { 00335 if (edge1->pos.x() + edge1->stepx != edge2->pos.x() 00336 || edge1->pos.y() + edge1->stepy != edge2->pos.y()) { 00337 CRACKEDGE *tempedge = edge1; 00338 edge1 = edge2; // swap araound 00339 edge2 = tempedge; 00340 } 00341 00342 if (edge1->next == edge2) { 00343 // already closed 00344 complete_edge(edge1, outline_it); 00345 // attach freelist to end 00346 edge1->prev->next = *free_cracks; 00347 *free_cracks = edge1; // and free list 00348 } else { 00349 // update opposite ends 00350 edge2->prev->next = edge1->next; 00351 edge1->next->prev = edge2->prev; 00352 edge1->next = edge2; // make joins 00353 edge2->prev = edge1; 00354 } 00355 } 00356 00357 00358 /********************************************************************** 00359 * free_crackedges 00360 * 00361 * Really free the CRACKEDGEs by giving them back to delete. 00362 **********************************************************************/ 00363 00364 void free_crackedges(CRACKEDGE *start) { 00365 CRACKEDGE *current; // current edge to free 00366 CRACKEDGE *next; // next one to free 00367 00368 for (current = start; current != NULL; current = next) { 00369 next = current->next; 00370 delete current; // delete them all 00371 } 00372 }