ccmain/charcut.cpp

Go to the documentation of this file.
00001 
00020 #include          "mfcpch.h"
00021 #include          "charcut.h"
00022 #include          "imgs.h"
00023 #include          "showim.h"
00024 #include          "evnts.h"
00025 #include          "notdll.h"
00026 
00027 #define LARGEST(a,b) ( (a) > (b) ? (a) : (b) )
00028 #define SMALLEST(a,b) ( (a) > (b) ? (b) : (a) )
00029 #define BUG_OFFSET 1
00030 
00031 #define EXTERN
00032 
00035 EXTERN INT_VAR (pix_word_margin, 3, "How far outside word BB to grow");
00036 
00037 extern IMAGE page_image;   // not used in this file
00040 ELISTIZE (PIXROW)
00049 PIXROW::PIXROW(INT16 pos, INT16 count, PBLOB *blob) { 
00050   OUTLINE_LIST *outline_list;
00051   OUTLINE_IT outline_it;
00052   POLYPT_LIST *pts_list;
00053   POLYPT_IT pts_it;
00054   INT16 i;
00055   FCOORD pt;
00056   FCOORD vec;
00057   float y_coord;
00058   INT16 x_coord;
00059 
00060   row_offset = pos;
00061   row_count = count;
00062   min = (INT16 *) alloc_mem (count * sizeof (INT16));
00063   max = (INT16 *) alloc_mem (count * sizeof (INT16));
00064   outline_list = blob->out_list ();
00065   outline_it.set_to_list (outline_list);
00066 
00067   for (i = 0; i < count; i++) {
00068     min[i] = MAX_INT16 - 1;
00069     max[i] = -MAX_INT16 + 1;
00070     y_coord = row_offset + i + 0.5;
00071     for (outline_it.mark_cycle_pt ();
00072     !outline_it.cycled_list (); outline_it.forward ()) {
00073       pts_list = outline_it.data ()->polypts ();
00074       pts_it.set_to_list (pts_list);
00075       for (pts_it.mark_cycle_pt ();
00076       !pts_it.cycled_list (); pts_it.forward ()) {
00077         pt = pts_it.data ()->pos;
00078         vec = pts_it.data ()->vec;
00079         if ((vec.y () != 0) &&
00080           (((pt.y () <= y_coord) && (pt.y () + vec.y () >= y_coord))
00081           || ((pt.y () >= y_coord)
00082         && (pt.y () + vec.y () <= y_coord)))) {
00083           /* The segment crosses y_coord so find x-point and check for min/max. */
00084           x_coord = (INT16) floor ((y_coord -
00085             pt.y ()) * vec.x () / vec.y () +
00086             pt.x () + 0.5);
00087           if (x_coord < min[i])
00088             min[i] = x_coord;
00089           x_coord--;             //to get pix to left of line
00090           if (x_coord > max[i])
00091             max[i] = x_coord;
00092         }
00093       }
00094     }
00095   }
00096 }
00097 
00098 
00105 #ifndef GRAPHICS_DISABLED
00106 void PIXROW::plot(WINDOW fd  //where to paint
00107                  ) const {
00108   INT16 i;
00109   INT16 y_coord;
00110 
00111   for (i = 0; i < row_count; i++) {
00112     y_coord = row_offset + i;
00113     if (min[i] <= max[i]) {
00114       rectangle (fd, min[i], y_coord, max[i] + 1, y_coord + 1);
00115     }
00116   }
00117 }
00118 #endif
00119 
00127 bool PIXROW::bad_box(
00128                      int xsize,
00129                      int ysize) const {
00130   BOX bbox = bounding_box ();
00131   if (bbox.left () < 0 || bbox.right () > xsize
00132   || bbox.top () > ysize || bbox.bottom () < 0) {
00133     tprintf("Box (%d,%d)->(%d,%d) bad compared to %d,%d\n",
00134             bbox.left(),bbox.bottom(), bbox.right(), bbox.top(),
00135             xsize, ysize);
00136     return true;
00137   }
00138   return false;
00139 }
00140 
00141 
00147 BOX PIXROW::bounding_box() const { 
00148   INT16 i;
00149   INT16 y_coord;
00150   INT16 min_x = MAX_INT16 - 1;
00151   INT16 min_y = MAX_INT16 - 1;
00152   INT16 max_x = -MAX_INT16 + 1;
00153   INT16 max_y = -MAX_INT16 + 1;
00154 
00155   for (i = 0; i < row_count; i++) {
00156     y_coord = row_offset + i;
00157     if (min[i] <= max[i]) {
00158       if (y_coord < min_y)
00159         min_y = y_coord;
00160       if (y_coord + 1 > max_y)
00161         max_y = y_coord + 1;
00162       if (min[i] < min_x)
00163         min_x = min[i];
00164       if (max[i] + 1 > max_x)
00165         max_x = max[i] + 1;
00166     }
00167   }
00168   if (min_x > max_x || min_y > max_y)
00169     return BOX ();
00170   else
00171     return BOX (ICOORD (min_x, min_y), ICOORD (max_x, max_y));
00172 }
00173 
00174 
00183 void PIXROW::contract(
00184                       IMAGELINE *imlines,
00185                       INT16 x_offset,          // of pixels[0]
00186                       INT16 foreground_colour  // 0 or 1
00187                      ) {
00188   INT16 i;
00189   UINT8 *line_pixels;
00190 
00191   for (i = 0; i < row_count; i++) {
00192     if (min[i] > max[i])
00193       continue;
00194 
00195     line_pixels = imlines[i].pixels;
00196     while (line_pixels[min[i] - x_offset] != foreground_colour) {
00197       if (min[i] == max[i]) {
00198         min[i] = MAX_INT16 - 1;
00199         max[i] = -MAX_INT16 + 1;
00200         goto nextline;
00201       }
00202       else
00203         min[i]++;
00204     }
00205     while (line_pixels[max[i] - x_offset] != foreground_colour) {
00206       if (min[i] == max[i]) {
00207         min[i] = MAX_INT16 - 1;
00208         max[i] = -MAX_INT16 + 1;
00209         goto nextline;
00210       }
00211       else
00212         max[i]--;
00213     }
00214     nextline:;
00215     //goto label!
00216   }
00217 }
00218 
00219 
00230 BOOL8 PIXROW::extend(
00231                      IMAGELINE *imlines,
00232                      BOX &imbox,
00233                      PIXROW *prev,
00234                      PIXROW *next,
00235                      INT16 foreground_colour) {
00236   INT16 i;
00237   INT16 x_offset = imbox.left ();
00238   INT16 limit;
00239   INT16 left_limit;
00240   INT16 right_limit;
00241   UINT8 *pixels = NULL;
00242   UINT8 *pixels_below = NULL;    //row below current
00243   UINT8 *pixels_above = NULL;    //row above current
00244   BOOL8 changed = FALSE;
00245 
00246   pixels_above = imlines[0].pixels;
00247   for (i = 0; i < row_count; i++) {
00248     pixels_below = pixels;
00249     pixels = pixels_above;
00250     if (i < (row_count - 1))
00251       pixels_above = imlines[i + 1].pixels;
00252     else
00253       pixels_above = NULL;
00254 
00255     /* Extend Left by one pixel*/
00256     if (prev == NULL || prev->max[i] < prev->min[i])
00257       limit = imbox.left ();
00258     else
00259       limit = prev->max[i] + 1;
00260     if ((min[i] <= max[i]) &&
00261       (min[i] > limit) &&
00262     (pixels[min[i] - 1 - x_offset] == foreground_colour)) {
00263       min[i]--;
00264       changed = TRUE;
00265     }
00266 
00267     /* Extend Right by one pixel*/
00268     if (next == NULL || next->min[i] > next->max[i])
00269       limit = imbox.right () - 1;//-1 to index inside pix
00270     else
00271       limit = next->min[i] - 1;
00272     if ((min[i] <= max[i]) &&
00273       (max[i] < limit) &&
00274     (pixels[max[i] + 1 - x_offset] == foreground_colour)) {
00275       max[i]++;
00276       changed = TRUE;
00277     }
00278 
00279     /* Extend down by one row */
00280     if (pixels_below != NULL) {
00281       if (min[i] < min[i - 1]) { //row goes left of row below
00282         if (prev == NULL || prev->max[i - 1] < prev->min[i - 1])
00283           left_limit = min[i];
00284         else
00285           left_limit = LARGEST (min[i], prev->max[i - 1] + 1);
00286       }
00287       else
00288         left_limit = min[i - 1];
00289 
00290       if (max[i] > max[i - 1]) { //row goes right of row below
00291         if (next == NULL || next->min[i - 1] > next->max[i - 1])
00292           right_limit = max[i];
00293         else
00294           right_limit = SMALLEST (max[i], next->min[i - 1] - 1);
00295       }
00296       else
00297         right_limit = max[i - 1];
00298 
00299       while ((left_limit <= right_limit) &&
00300         (pixels_below[left_limit - x_offset] != foreground_colour))
00301         left_limit++;            //find black extremity
00302 
00303       if ((left_limit <= right_limit) && (left_limit < min[i - 1])) {
00304         min[i - 1] = left_limit; //widen left if poss
00305         changed = TRUE;
00306       }
00307 
00308       while ((left_limit <= right_limit) &&
00309         (pixels_below[right_limit - x_offset] != foreground_colour))
00310         right_limit--;           //find black extremity
00311 
00312       if ((left_limit <= right_limit) && (right_limit > max[i - 1])) {
00313         max[i - 1] = right_limit;//widen right if poss
00314         changed = TRUE;
00315       }
00316     }
00317 
00318     /* Extend up by one row */
00319     if (pixels_above != NULL) {
00320       if (min[i] < min[i + 1]) { //row goes left of row above
00321         if (prev == NULL || prev->min[i + 1] > prev->max[i + 1])
00322           left_limit = min[i];
00323         else
00324           left_limit = LARGEST (min[i], prev->max[i + 1] + 1);
00325       }
00326       else
00327         left_limit = min[i + 1];
00328 
00329       if (max[i] > max[i + 1]) { //row goes right of row above
00330         if (next == NULL || next->min[i + 1] > next->max[i + 1])
00331           right_limit = max[i];
00332         else
00333           right_limit = SMALLEST (max[i], next->min[i + 1] - 1);
00334       }
00335       else
00336         right_limit = max[i + 1];
00337 
00338       while ((left_limit <= right_limit) &&
00339         (pixels_above[left_limit - x_offset] != foreground_colour))
00340         left_limit++;            //find black extremity
00341 
00342       if ((left_limit <= right_limit) && (left_limit < min[i + 1])) {
00343         min[i + 1] = left_limit; //widen left if poss
00344         changed = TRUE;
00345       }
00346 
00347       while ((left_limit <= right_limit) &&
00348         (pixels_above[right_limit - x_offset] != foreground_colour))
00349         right_limit--;           //find black extremity
00350 
00351       if ((left_limit <= right_limit) && (right_limit > max[i + 1])) {
00352         max[i + 1] = right_limit;//widen right if poss
00353         changed = TRUE;
00354       }
00355     }
00356   }
00357   return changed;
00358 }
00359 
00360 
00371 void PIXROW::char_clip_image(
00372                              IMAGELINE *imlines,
00373                              BOX &im_box,
00374                              ROW *row,
00375                              IMAGE &clip_image,
00376                              float &baseline_pos
00377                             ) {
00378   INT16 clip_image_xsize;        //sub image x size
00379   INT16 clip_image_ysize;        //sub image y size
00384   INT16 x_shift;
00390   INT16 y_shift;
00391   BOX char_pix_box;              //bbox of char pixels
00392   INT16 y_dest;
00393   INT16 x_min;
00394   INT16 x_max;
00395   INT16 x_min_dest;
00396   INT16 x_max_dest;
00397   INT16 x_width;
00398   INT16 y;
00399 
00400   clip_image_xsize = clip_image.get_xsize ();
00401   clip_image_ysize = clip_image.get_ysize ();
00402 
00403   char_pix_box = bounding_box ();
00404   y_shift = char_pix_box.bottom () - row_offset -
00405     (INT16) floor ((clip_image_ysize - char_pix_box.height () + 0.5) / 2);
00406 
00407   x_shift = char_pix_box.left () -
00408     (INT16) floor ((clip_image_xsize - char_pix_box.width () + 0.5) / 2);
00409 
00410   for (y = 0; y < row_count; y++) {
00411     /*
00412       Check that there is something in this row of the source that will fit in the
00413       sub image.  If there is, reduce x range if necessary, then copy it
00414     */
00415     y_dest = y - y_shift;
00416     if ((min[y] <= max[y]) && (y_dest >= 0) && (y_dest < clip_image_ysize)) {
00417       x_min = min[y];
00418       x_min_dest = x_min - x_shift;
00419       if (x_min_dest < 0) {
00420         x_min = x_min - x_min_dest;
00421         x_min_dest = 0;
00422       }
00423       x_max = max[y];
00424       x_max_dest = x_max - x_shift;
00425       if (x_max_dest > clip_image_xsize - 1) {
00426         x_max = x_max - (x_max_dest - (clip_image_xsize - 1));
00427         x_max_dest = clip_image_xsize - 1;
00428       }
00429       x_width = x_max - x_min + 1;
00430       if (x_width > 0) {
00431         x_min -= im_box.left ();
00432                                  //offset pixel ptr
00433         imlines[y].pixels += x_min;
00434         clip_image.put_line (x_min_dest, y_dest, x_width, imlines + y,
00435           0);
00436         imlines[y].init ();      //reset pixel ptr
00437       }
00438     }
00439   }
00440   /*
00441     Baseline position relative to clip image: First find the baseline relative
00442     to the page origin at the x coord of the centre of the character. Then
00443     make this relative to the character bottom. Finally shift by the margin
00444     between the bottom of the character and the bottom of the clip image.
00445   */
00446   if (row == NULL)
00447     baseline_pos = 0;            //Not needed
00448   else
00449     baseline_pos = row->base_line ((char_pix_box.left () +
00450       char_pix_box.right ()) / 2.0)
00451       - char_pix_box.bottom ()
00452       + ((clip_image_ysize - char_pix_box.height ()) / 2);
00453 }
00454 
00455 
00468 void char_clip_word(
00469                     WERD *word,
00470                     IMAGE &bin_image,
00471                     PIXROW_LIST *&pixrow_list,
00472                     IMAGELINE *&imlines,
00473                     BOX &pix_box
00474                    ) {
00475   BOX word_box = word->bounding_box ();
00476   PBLOB_LIST *blob_list;
00477   PBLOB_IT blob_it;
00478   PIXROW_IT pixrow_it;
00479   INT16 pix_offset;              //Y pos of pixrow[0]
00480   INT16 row_height;              //No of pix rows
00481   INT16 imlines_x_offset;
00482   PIXROW *prev;
00483   PIXROW *next;
00484   PIXROW *current;
00485   BOOL8 changed;                 //still improving
00486   BOOL8 just_changed;            //still improving
00487   INT16 iteration_count = 0;
00488   INT16 foreground_colour;
00489 
00490   if (word->flag (W_INVERSE))
00491     foreground_colour = 1;
00492   else
00493     foreground_colour = 0;
00494 
00495   /* Define region for max pixrow expansion */
00496   pix_box = word_box;
00497   pix_box.move_bottom_edge (-pix_word_margin);
00498   pix_box.move_top_edge (pix_word_margin);
00499   pix_box.move_left_edge (-pix_word_margin);
00500   pix_box.move_right_edge (pix_word_margin);
00501   pix_box -= BOX (ICOORD (0, 0 + BUG_OFFSET),
00502     ICOORD (bin_image.get_xsize (),
00503     bin_image.get_ysize () - BUG_OFFSET));
00504 
00505   /* Generate pixrows list */
00506 
00507   pix_offset = pix_box.bottom ();
00508   row_height = pix_box.height ();
00509   blob_list = word->blob_list ();
00510   blob_it.set_to_list (blob_list);
00511 
00512   pixrow_list = new PIXROW_LIST;
00513   pixrow_it.set_to_list (pixrow_list);
00514 
00515   for (blob_it.mark_cycle_pt (); !blob_it.cycled_list (); blob_it.forward ()) {
00516     PIXROW *row = new PIXROW (pix_offset, row_height, blob_it.data ());
00517     ASSERT_HOST (!row->
00518       bad_box (bin_image.get_xsize (), bin_image.get_ysize ()));
00519     pixrow_it.add_after_then_move (row);
00520   }
00521 
00522   imlines = generate_imlines (bin_image, pix_box);
00523 
00524   /* Contract pixrows - shrink min and max back to black pixels */
00525 
00526   imlines_x_offset = pix_box.left ();
00527 
00528   pixrow_it.move_to_first ();
00529   for (pixrow_it.mark_cycle_pt ();
00530   !pixrow_it.cycled_list (); pixrow_it.forward ()) {
00531     ASSERT_HOST (!pixrow_it.data ()->
00532       bad_box (bin_image.get_xsize (), bin_image.get_ysize ()));
00533     pixrow_it.data ()->contract (imlines, imlines_x_offset,
00534       foreground_colour);
00535     ASSERT_HOST (!pixrow_it.data ()->
00536       bad_box (bin_image.get_xsize (), bin_image.get_ysize ()));
00537   }
00538 
00539   /* Expand pixrows iteratively 1 pixel at a time */
00540   do {
00541     changed = FALSE;
00542     pixrow_it.move_to_first ();
00543     prev = NULL;
00544     current = NULL;
00545     next = pixrow_it.data ();
00546     for (pixrow_it.mark_cycle_pt ();
00547     !pixrow_it.cycled_list (); pixrow_it.forward ()) {
00548       prev = current;
00549       current = next;
00550       if (pixrow_it.at_last ())
00551         next = NULL;
00552       else
00553         next = pixrow_it.data_relative (1);
00554       just_changed = current->extend (imlines, pix_box, prev, next,
00555         foreground_colour);
00556       ASSERT_HOST (!current->
00557         bad_box (bin_image.get_xsize (),
00558         bin_image.get_ysize ()));
00559       changed = changed || just_changed;
00560     }
00561     iteration_count++;
00562   }
00563   while (changed);
00564 }
00565 
00566 
00574 IMAGELINE *generate_imlines(
00575                             IMAGE &bin_image,
00576                             BOX &pix_box) {
00577   IMAGELINE *imlines;            //array of lines
00578   int i;
00579 
00580   imlines = new IMAGELINE[pix_box.height ()];
00581   for (i = 0; i < pix_box.height (); i++) {
00582     imlines[i].init (pix_box.width ());
00583                                  //coord to start at
00584     bin_image.fast_get_line (pix_box.left (),
00585       pix_box.bottom () + i + BUG_OFFSET,
00586     //line to get
00587       pix_box.width (),          //width to get
00588       imlines + i);              //dest imline
00589   }
00590   return imlines;
00591 }
00592 
00593 
00603 #ifndef GRAPHICS_DISABLED
00604 WINDOW display_clip_image(WERD *word,
00605                           IMAGE &bin_image,
00606                           PIXROW_LIST *pixrow_list,
00607                           BOX &pix_box
00608                          ) {
00609   WINDOW clip_window;            //window for debug
00610   BOX word_box = word->bounding_box ();
00611   int border = word_box.height () / 2;
00612   BOX display_box = word_box;
00613 
00614   display_box.move_bottom_edge (-border);
00615   display_box.move_top_edge (border);
00616   display_box.move_left_edge (-border);
00617   display_box.move_right_edge (border);
00618   display_box -= BOX (ICOORD (0, 0 - BUG_OFFSET),
00619     ICOORD (bin_image.get_xsize (),
00620     bin_image.get_ysize () - BUG_OFFSET));
00621 
00622   pgeditor_msg ("Creating Clip window...");
00623   clip_window =
00624     create_window ("Clipped Blobs",
00625     SCROLLINGWIN,
00626     editor_word_xpos, editor_word_ypos,
00627     3 * (word_box.width () + 2 * border),
00628     3 * (word_box.height () + 2 * border),
00629   //window width,height
00630                                  // xmin, xmax
00631     display_box.left (), display_box.right (),
00632     display_box.bottom () - BUG_OFFSET,
00633     display_box.top () - BUG_OFFSET,
00634   // ymin, ymax
00635     TRUE, FALSE, FALSE, TRUE);   // down event & key only
00636   pgeditor_msg ("Creating Clip window...Done");
00637 
00638   clear_view_surface(clip_window); 
00639   show_sub_image (&bin_image,
00640     display_box.left (),
00641     display_box.bottom (),
00642     display_box.width (),
00643     display_box.height (),
00644     clip_window,
00645     display_box.left (), display_box.bottom () - BUG_OFFSET);
00646 
00647   word->plot (clip_window, RED);
00648   word_box.plot (clip_window, INT_HOLLOW, TRUE, BLUE, BLUE);
00649   pix_box.plot (clip_window, INT_HOLLOW, TRUE, BLUE, BLUE);
00650   plot_pixrows(pixrow_list, clip_window); 
00651   overlap_picture_ops(TRUE); 
00652   return clip_window;
00653 }
00654 
00655 
00660 void display_images(IMAGE &clip_image, IMAGE &scaled_image) {
00661   WINDOW clip_im_window;         //window for debug
00662   WINDOW scale_im_window;        //window for debug
00663   INT16 i;
00664   GRAPHICS_EVENT event;          // c;
00665 
00666                                  // xmin xmax ymin ymax
00667   clip_im_window = create_window ("Clipped Blob", SCROLLINGWIN,
00668    editor_word_xpos - 20, editor_word_ypos - 100,
00669    5 * clip_image.get_xsize (), 5 * clip_image.get_ysize (),
00670    0, clip_image.get_xsize (), 0, clip_image.get_ysize (),
00671     TRUE, FALSE, FALSE, TRUE);   // down event & key only
00672 
00673   clear_view_surface(clip_im_window); 
00674   show_sub_image (&clip_image,
00675     0, 0,
00676     clip_image.get_xsize (), clip_image.get_ysize (),
00677     clip_im_window, 0, 0);
00678 
00679   line_color_index(clip_im_window, RED); 
00680   for (i = 1; i < clip_image.get_xsize (); i++) {
00681     move2d (clip_im_window, i, 0);
00682     draw2d (clip_im_window, i, clip_image.get_xsize ());
00683   }
00684   for (i = 1; i < clip_image.get_ysize (); i++) {
00685     move2d (clip_im_window, 0, i);
00686     draw2d (clip_im_window, clip_image.get_xsize (), i);
00687   }
00688 
00689                                  // xmin xmax ymin ymax
00690   scale_im_window = create_window ("Scaled Blob", SCROLLINGWIN,
00691    editor_word_xpos + 300, editor_word_ypos - 100,
00692    5 * scaled_image.get_xsize (), 5 * scaled_image.get_ysize (),
00693    0, scaled_image.get_xsize (), 0, scaled_image.get_ysize (),
00694     TRUE, FALSE, FALSE, TRUE);   // down event & key only
00695 
00696   clear_view_surface(scale_im_window); 
00697   show_sub_image (&scaled_image,
00698     0, 0,
00699     scaled_image.get_xsize (), scaled_image.get_ysize (),
00700     scale_im_window, 0, 0);
00701 
00702   line_color_index(scale_im_window, RED); 
00703   for (i = 1; i < scaled_image.get_xsize (); i++) {
00704     move2d (scale_im_window, i, 0);
00705     draw2d (scale_im_window, i, scaled_image.get_xsize ());
00706   }
00707   for (i = 1; i < scaled_image.get_ysize (); i++) {
00708     move2d (scale_im_window, 0, i);
00709     draw2d (scale_im_window, scaled_image.get_xsize (), i);
00710   }
00711 
00712   overlap_picture_ops(TRUE); 
00713   await_event(scale_im_window, TRUE, ANY_EVENT, &event); 
00714   destroy_window(clip_im_window); 
00715   destroy_window(scale_im_window); 
00716 }
00717 
00718 
00722 void plot_pixrows(  //plot for all blobs
00723                   PIXROW_LIST *pixrow_list,
00724                   WINDOW win) {
00725   PIXROW_IT pixrow_it(pixrow_list); 
00726   INT16 colour = RED;
00727 
00728   for (pixrow_it.mark_cycle_pt ();
00729   !pixrow_it.cycled_list (); pixrow_it.forward ()) {
00730     if (colour > RED + 7)
00731       colour = RED;
00732 
00733     perimeter_color_index (win, (COLOUR) colour);
00734     interior_style(win, INT_HOLLOW, TRUE); 
00735     pixrow_it.data ()->plot (win);
00736     colour++;
00737   }
00738 }
00739 #endif // GRAPHICS_DISABLED

Generated on Wed Feb 28 19:49:07 2007 for Tesseract by  doxygen 1.5.1