tesseract  3.03
/usr/local/google/home/jbreiden/tesseract-ocr-read-only/textord/scanedg.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines