tesseract  4.00.00dev
tesseract::ImageFind Class Reference

#include <imagefind.h>

Static Public Member Functions

static Pix * FindImages (Pix *pix, DebugPixa *pixa_debug)
 
static void ConnCompAndRectangularize (Pix *pix, DebugPixa *pixa_debug, Boxa **boxa, Pixa **pixa)
 
static bool pixNearlyRectangular (Pix *pix, double min_fraction, double max_fraction, double max_skew_gradient, int *x_start, int *y_start, int *x_end, int *y_end)
 
static bool BoundsWithinRect (Pix *pix, int *x_start, int *y_start, int *x_end, int *y_end)
 
static double ColorDistanceFromLine (const uinT8 *line1, const uinT8 *line2, const uinT8 *point)
 
static uinT32 ComposeRGB (uinT32 r, uinT32 g, uinT32 b)
 
static uinT8 ClipToByte (double pixel)
 
static void ComputeRectangleColors (const TBOX &rect, Pix *pix, int factor, Pix *color_map1, Pix *color_map2, Pix *rms_map, uinT8 *color1, uinT8 *color2)
 
static bool BlankImageInBetween (const TBOX &box1, const TBOX &box2, const TBOX &im_box, const FCOORD &rotation, Pix *pix)
 
static int CountPixelsInRotatedBox (TBOX box, const TBOX &im_box, const FCOORD &rotation, Pix *pix)
 
static void TransferImagePartsToImageMask (const FCOORD &rerotation, ColPartitionGrid *part_grid, Pix *image_mask)
 
static void FindImagePartitions (Pix *image_pix, const FCOORD &rotation, const FCOORD &rerotation, TO_BLOCK *block, TabFind *tab_grid, DebugPixa *pixa_debug, ColPartitionGrid *part_grid, ColPartition_LIST *big_parts)
 

Detailed Description

Definition at line 43 of file imagefind.h.

Member Function Documentation

◆ BlankImageInBetween()

bool tesseract::ImageFind::BlankImageInBetween ( const TBOX box1,
const TBOX box2,
const TBOX im_box,
const FCOORD rotation,
Pix *  pix 
)
static

Definition at line 580 of file imagefind.cpp.

582  {
583  TBOX search_box(box1);
584  search_box += box2;
585  if (box1.x_gap(box2) >= box1.y_gap(box2)) {
586  if (box1.x_gap(box2) <= 0)
587  return true;
588  search_box.set_left(MIN(box1.right(), box2.right()));
589  search_box.set_right(MAX(box1.left(), box2.left()));
590  } else {
591  if (box1.y_gap(box2) <= 0)
592  return true;
593  search_box.set_top(MAX(box1.bottom(), box2.bottom()));
594  search_box.set_bottom(MIN(box1.top(), box2.top()));
595  }
596  return CountPixelsInRotatedBox(search_box, im_box, rotation, pix) == 0;
597 }
#define MIN(x, y)
Definition: ndminx.h:28
#define MAX(x, y)
Definition: ndminx.h:24
int y_gap(const TBOX &box) const
Definition: rect.h:225
inT16 top() const
Definition: rect.h:54
void set_left(int x)
Definition: rect.h:71
inT16 bottom() const
Definition: rect.h:61
int x_gap(const TBOX &box) const
Definition: rect.h:217
Definition: rect.h:30
inT16 left() const
Definition: rect.h:68
static int CountPixelsInRotatedBox(TBOX box, const TBOX &im_box, const FCOORD &rotation, Pix *pix)
Definition: imagefind.cpp:601
inT16 right() const
Definition: rect.h:75

◆ BoundsWithinRect()

bool tesseract::ImageFind::BoundsWithinRect ( Pix *  pix,
int *  x_start,
int *  y_start,
int *  x_end,
int *  y_end 
)
static

Definition at line 336 of file imagefind.cpp.

337  {
338  Box* input_box = boxCreate(*x_start, *y_start, *x_end - *x_start,
339  *y_end - *y_start);
340  Box* output_box = NULL;
341  pixClipBoxToForeground(pix, input_box, NULL, &output_box);
342  bool result = output_box != NULL;
343  if (result) {
344  l_int32 x, y, width, height;
345  boxGetGeometry(output_box, &x, &y, &width, &height);
346  *x_start = x;
347  *y_start = y;
348  *x_end = x + width;
349  *y_end = y + height;
350  boxDestroy(&output_box);
351  }
352  boxDestroy(&input_box);
353  return result;
354 }

◆ ClipToByte()

uinT8 tesseract::ImageFind::ClipToByte ( double  pixel)
static

Definition at line 400 of file imagefind.cpp.

400  {
401  if (pixel < 0.0)
402  return 0;
403  else if (pixel >= 255.0)
404  return 255;
405  return static_cast<uinT8>(pixel);
406 }
uint8_t uinT8
Definition: host.h:35

◆ ColorDistanceFromLine()

double tesseract::ImageFind::ColorDistanceFromLine ( const uinT8 line1,
const uinT8 line2,
const uinT8 point 
)
static

Definition at line 359 of file imagefind.cpp.

361  {
362  int line_vector[kRGBRMSColors];
363  int point_vector[kRGBRMSColors];
364  for (int i = 0; i < kRGBRMSColors; ++i) {
365  line_vector[i] = static_cast<int>(line2[i]) - static_cast<int>(line1[i]);
366  point_vector[i] = static_cast<int>(point[i]) - static_cast<int>(line1[i]);
367  }
368  line_vector[L_ALPHA_CHANNEL] = 0;
369  // Now the cross product in 3d.
370  int cross[kRGBRMSColors];
371  cross[COLOR_RED] = line_vector[COLOR_GREEN] * point_vector[COLOR_BLUE]
372  - line_vector[COLOR_BLUE] * point_vector[COLOR_GREEN];
373  cross[COLOR_GREEN] = line_vector[COLOR_BLUE] * point_vector[COLOR_RED]
374  - line_vector[COLOR_RED] * point_vector[COLOR_BLUE];
375  cross[COLOR_BLUE] = line_vector[COLOR_RED] * point_vector[COLOR_GREEN]
376  - line_vector[COLOR_GREEN] * point_vector[COLOR_RED];
377  cross[L_ALPHA_CHANNEL] = 0;
378  // Now the sums of the squares.
379  double cross_sq = 0.0;
380  double line_sq = 0.0;
381  for (int j = 0; j < kRGBRMSColors; ++j) {
382  cross_sq += static_cast<double>(cross[j]) * cross[j];
383  line_sq += static_cast<double>(line_vector[j]) * line_vector[j];
384  }
385  if (line_sq == 0.0) {
386  return 0.0;
387  }
388  return cross_sq / line_sq; // This is the squared distance.
389 }
const int kRGBRMSColors
Definition: colpartition.h:36

◆ ComposeRGB()

uinT32 tesseract::ImageFind::ComposeRGB ( uinT32  r,
uinT32  g,
uinT32  b 
)
static

Definition at line 393 of file imagefind.cpp.

393  {
394  l_uint32 result;
395  composeRGBPixel(r, g, b, &result);
396  return result;
397 }

◆ ComputeRectangleColors()

void tesseract::ImageFind::ComputeRectangleColors ( const TBOX rect,
Pix *  pix,
int  factor,
Pix *  color_map1,
Pix *  color_map2,
Pix *  rms_map,
uinT8 color1,
uinT8 color2 
)
static

Definition at line 418 of file imagefind.cpp.

421  {
422  ASSERT_HOST(pix != NULL && pixGetDepth(pix) == 32);
423  // Pad the rectangle outwards by 2 (scaled) pixels if possible to get more
424  // background.
425  int width = pixGetWidth(pix);
426  int height = pixGetHeight(pix);
427  int left_pad = MAX(rect.left() - 2 * factor, 0) / factor;
428  int top_pad = (rect.top() + 2 * factor + (factor - 1)) / factor;
429  top_pad = MIN(height, top_pad);
430  int right_pad = (rect.right() + 2 * factor + (factor - 1)) / factor;
431  right_pad = MIN(width, right_pad);
432  int bottom_pad = MAX(rect.bottom() - 2 * factor, 0) / factor;
433  int width_pad = right_pad - left_pad;
434  int height_pad = top_pad - bottom_pad;
435  if (width_pad < 1 || height_pad < 1 || width_pad + height_pad < 4)
436  return;
437  // Now crop the pix to the rectangle.
438  Box* scaled_box = boxCreate(left_pad, height - top_pad,
439  width_pad, height_pad);
440  Pix* scaled = pixClipRectangle(pix, scaled_box, NULL);
441 
442  // Compute stats over the whole image.
443  STATS red_stats(0, 256);
444  STATS green_stats(0, 256);
445  STATS blue_stats(0, 256);
446  uinT32* data = pixGetData(scaled);
447  ASSERT_HOST(pixGetWpl(scaled) == width_pad);
448  for (int y = 0; y < height_pad; ++y) {
449  for (int x = 0; x < width_pad; ++x, ++data) {
450  int r = GET_DATA_BYTE(data, COLOR_RED);
451  int g = GET_DATA_BYTE(data, COLOR_GREEN);
452  int b = GET_DATA_BYTE(data, COLOR_BLUE);
453  red_stats.add(r, 1);
454  green_stats.add(g, 1);
455  blue_stats.add(b, 1);
456  }
457  }
458  // Find the RGB component with the greatest 8th-ile-range.
459  // 8th-iles are used instead of quartiles to get closer to the true
460  // foreground color, which is going to be faint at best because of the
461  // pre-scaling of the input image.
462  int best_l8 = static_cast<int>(red_stats.ile(0.125f));
463  int best_u8 = static_cast<int>(ceil(red_stats.ile(0.875f)));
464  int best_i8r = best_u8 - best_l8;
465  int x_color = COLOR_RED;
466  int y1_color = COLOR_GREEN;
467  int y2_color = COLOR_BLUE;
468  int l8 = static_cast<int>(green_stats.ile(0.125f));
469  int u8 = static_cast<int>(ceil(green_stats.ile(0.875f)));
470  if (u8 - l8 > best_i8r) {
471  best_i8r = u8 - l8;
472  best_l8 = l8;
473  best_u8 = u8;
474  x_color = COLOR_GREEN;
475  y1_color = COLOR_RED;
476  }
477  l8 = static_cast<int>(blue_stats.ile(0.125f));
478  u8 = static_cast<int>(ceil(blue_stats.ile(0.875f)));
479  if (u8 - l8 > best_i8r) {
480  best_i8r = u8 - l8;
481  best_l8 = l8;
482  best_u8 = u8;
483  x_color = COLOR_BLUE;
484  y1_color = COLOR_GREEN;
485  y2_color = COLOR_RED;
486  }
487  if (best_i8r >= kMinColorDifference) {
488  LLSQ line1;
489  LLSQ line2;
490  uinT32* data = pixGetData(scaled);
491  for (int im_y = 0; im_y < height_pad; ++im_y) {
492  for (int im_x = 0; im_x < width_pad; ++im_x, ++data) {
493  int x = GET_DATA_BYTE(data, x_color);
494  int y1 = GET_DATA_BYTE(data, y1_color);
495  int y2 = GET_DATA_BYTE(data, y2_color);
496  line1.add(x, y1);
497  line2.add(x, y2);
498  }
499  }
500  double m1 = line1.m();
501  double c1 = line1.c(m1);
502  double m2 = line2.m();
503  double c2 = line2.c(m2);
504  double rms = line1.rms(m1, c1) + line2.rms(m2, c2);
505  rms *= kRMSFitScaling;
506  // Save the results.
507  color1[x_color] = ClipToByte(best_l8);
508  color1[y1_color] = ClipToByte(m1 * best_l8 + c1 + 0.5);
509  color1[y2_color] = ClipToByte(m2 * best_l8 + c2 + 0.5);
510  color1[L_ALPHA_CHANNEL] = ClipToByte(rms);
511  color2[x_color] = ClipToByte(best_u8);
512  color2[y1_color] = ClipToByte(m1 * best_u8 + c1 + 0.5);
513  color2[y2_color] = ClipToByte(m2 * best_u8 + c2 + 0.5);
514  color2[L_ALPHA_CHANNEL] = ClipToByte(rms);
515  } else {
516  // There is only one color.
517  color1[COLOR_RED] = ClipToByte(red_stats.median());
518  color1[COLOR_GREEN] = ClipToByte(green_stats.median());
519  color1[COLOR_BLUE] = ClipToByte(blue_stats.median());
520  color1[L_ALPHA_CHANNEL] = 0;
521  memcpy(color2, color1, 4);
522  }
523  if (color_map1 != NULL) {
524  pixSetInRectArbitrary(color_map1, scaled_box,
525  ComposeRGB(color1[COLOR_RED],
526  color1[COLOR_GREEN],
527  color1[COLOR_BLUE]));
528  pixSetInRectArbitrary(color_map2, scaled_box,
529  ComposeRGB(color2[COLOR_RED],
530  color2[COLOR_GREEN],
531  color2[COLOR_BLUE]));
532  pixSetInRectArbitrary(rms_map, scaled_box, color1[L_ALPHA_CHANNEL]);
533  }
534  pixDestroy(&scaled);
535  boxDestroy(&scaled_box);
536 }
#define MIN(x, y)
Definition: ndminx.h:28
static uinT8 ClipToByte(double pixel)
Definition: imagefind.cpp:400
Definition: linlsq.h:26
uint32_t uinT32
Definition: host.h:39
#define MAX(x, y)
Definition: ndminx.h:24
double rms(double m, double c) const
Definition: linlsq.cpp:131
void add(double x, double y)
Definition: linlsq.cpp:49
inT16 top() const
Definition: rect.h:54
double c(double m) const
Definition: linlsq.cpp:117
const double kRMSFitScaling
Definition: imagefind.cpp:53
inT16 bottom() const
Definition: rect.h:61
const int kMinColorDifference
Definition: imagefind.cpp:55
inT16 left() const
Definition: rect.h:68
#define ASSERT_HOST(x)
Definition: errcode.h:84
Definition: statistc.h:33
double m() const
Definition: linlsq.cpp:101
inT16 right() const
Definition: rect.h:75
static uinT32 ComposeRGB(uinT32 r, uinT32 g, uinT32 b)
Definition: imagefind.cpp:393

◆ ConnCompAndRectangularize()

void tesseract::ImageFind::ConnCompAndRectangularize ( Pix *  pix,
DebugPixa pixa_debug,
Boxa **  boxa,
Pixa **  pixa 
)
static

Definition at line 158 of file imagefind.cpp.

159  {
160  *boxa = NULL;
161  *pixa = NULL;
162 
163  if (textord_tabfind_show_images && pixa_debug != nullptr)
164  pixa_debug->AddPix(pix, "Conncompimage");
165  // Find the individual image regions in the mask image.
166  *boxa = pixConnComp(pix, pixa, 8);
167  // Rectangularize the individual images. If a sharp edge in vertical and/or
168  // horizontal occupancy can be found, it indicates a probably rectangular
169  // image with unwanted bits merged on, so clip to the approximate rectangle.
170  int npixes = 0;
171  if (*boxa != nullptr && *pixa != nullptr) npixes = pixaGetCount(*pixa);
172  for (int i = 0; i < npixes; ++i) {
173  int x_start, x_end, y_start, y_end;
174  Pix* img_pix = pixaGetPix(*pixa, i, L_CLONE);
175  if (textord_tabfind_show_images && pixa_debug != nullptr)
176  pixa_debug->AddPix(img_pix, "A component");
180  &x_start, &y_start, &x_end, &y_end)) {
181  Pix* simple_pix = pixCreate(x_end - x_start, y_end - y_start, 1);
182  pixSetAll(simple_pix);
183  pixDestroy(&img_pix);
184  // pixaReplacePix takes ownership of the simple_pix.
185  pixaReplacePix(*pixa, i, simple_pix, NULL);
186  img_pix = pixaGetPix(*pixa, i, L_CLONE);
187  // Fix the box to match the new pix.
188  l_int32 x, y, width, height;
189  boxaGetBoxGeometry(*boxa, i, &x, &y, &width, &height);
190  Box* simple_box = boxCreate(x + x_start, y + y_start,
191  x_end - x_start, y_end - y_start);
192  boxaReplaceBox(*boxa, i, simple_box);
193  }
194  pixDestroy(&img_pix);
195  }
196 }
const double kMinRectangularFraction
Definition: imagefind.cpp:44
const double kMaxRectangularGradient
Definition: imagefind.cpp:49
static bool pixNearlyRectangular(Pix *pix, double min_fraction, double max_fraction, double max_skew_gradient, int *x_start, int *y_start, int *x_end, int *y_end)
Definition: imagefind.cpp:270
int textord_tabfind_show_images
Definition: imagefind.cpp:38
const double kMaxRectangularFraction
Definition: imagefind.cpp:46

◆ CountPixelsInRotatedBox()

int tesseract::ImageFind::CountPixelsInRotatedBox ( TBOX  box,
const TBOX im_box,
const FCOORD rotation,
Pix *  pix 
)
static

Definition at line 601 of file imagefind.cpp.

602  {
603  // Intersect it with the image box.
604  box &= im_box; // This is in-place box intersection.
605  if (box.null_box())
606  return 0;
607  box.rotate(rotation);
608  TBOX rotated_im_box(im_box);
609  rotated_im_box.rotate(rotation);
610  Pix* rect_pix = pixCreate(box.width(), box.height(), 1);
611  pixRasterop(rect_pix, 0, 0, box.width(), box.height(),
612  PIX_SRC, pix, box.left() - rotated_im_box.left(),
613  rotated_im_box.top() - box.top());
614  l_int32 result;
615  pixCountPixels(rect_pix, &result, NULL);
616  pixDestroy(&rect_pix);
617  return result;
618 }
bool null_box() const
Definition: rect.h:46
inT16 top() const
Definition: rect.h:54
inT16 height() const
Definition: rect.h:104
Definition: rect.h:30
inT16 left() const
Definition: rect.h:68
void rotate(const FCOORD &vec)
Definition: rect.h:189
inT16 width() const
Definition: rect.h:111

◆ FindImagePartitions()

void tesseract::ImageFind::FindImagePartitions ( Pix *  image_pix,
const FCOORD rotation,
const FCOORD rerotation,
TO_BLOCK block,
TabFind tab_grid,
DebugPixa pixa_debug,
ColPartitionGrid part_grid,
ColPartition_LIST *  big_parts 
)
static

Definition at line 1302 of file imagefind.cpp.

1306  {
1307  int imageheight = pixGetHeight(image_pix);
1308  Boxa* boxa;
1309  Pixa* pixa;
1310  ConnCompAndRectangularize(image_pix, pixa_debug, &boxa, &pixa);
1311  // Iterate the connected components in the image regions mask.
1312  int nboxes = 0;
1313  if (boxa != nullptr && pixa != nullptr) nboxes = boxaGetCount(boxa);
1314  for (int i = 0; i < nboxes; ++i) {
1315  l_int32 x, y, width, height;
1316  boxaGetBoxGeometry(boxa, i, &x, &y, &width, &height);
1317  Pix* pix = pixaGetPix(pixa, i, L_CLONE);
1318  TBOX im_box(x, imageheight -y - height, x + width, imageheight - y);
1319  im_box.rotate(rotation); // Now matches all partitions and blobs.
1320  ColPartitionGridSearch rectsearch(part_grid);
1321  rectsearch.SetUniqueMode(true);
1322  ColPartition_LIST part_list;
1323  DivideImageIntoParts(im_box, rotation, rerotation, pix,
1324  &rectsearch, &part_list);
1325  if (textord_tabfind_show_images && pixa_debug != nullptr) {
1326  pixa_debug->AddPix(pix, "ImageComponent");
1327  tprintf("Component has %d parts\n", part_list.length());
1328  }
1329  pixDestroy(&pix);
1330  if (!part_list.empty()) {
1331  ColPartition_IT part_it(&part_list);
1332  if (part_list.singleton()) {
1333  // We didn't have to chop it into a polygon to fit around text, so
1334  // try expanding it to merge fragmented image parts, as long as it
1335  // doesn't touch strong text.
1336  ColPartition* part = part_it.extract();
1337  TBOX text_box(im_box);
1338  MaximalImageBoundingBox(part_grid, &text_box);
1339  while (ExpandImageIntoParts(text_box, &rectsearch, part_grid, &part));
1340  part_it.set_to_list(&part_list);
1341  part_it.add_after_then_move(part);
1342  im_box = part->bounding_box();
1343  }
1344  EliminateWeakParts(im_box, part_grid, big_parts, &part_list);
1345  // Iterate the part_list and put the parts into the grid.
1346  for (part_it.move_to_first(); !part_it.empty(); part_it.forward()) {
1347  ColPartition* image_part = part_it.extract();
1348  im_box = image_part->bounding_box();
1349  part_grid->InsertBBox(true, true, image_part);
1350  if (!part_it.at_last()) {
1351  ColPartition* neighbour = part_it.data_relative(1);
1352  image_part->AddPartner(false, neighbour);
1353  neighbour->AddPartner(true, image_part);
1354  }
1355  }
1356  }
1357  }
1358  boxaDestroy(&boxa);
1359  pixaDestroy(&pixa);
1360  DeleteSmallImages(part_grid);
1362  ScrollView* images_win_ = part_grid->MakeWindow(1000, 400, "With Images");
1363  part_grid->DisplayBoxes(images_win_);
1364  }
1365 }
#define tprintf(...)
Definition: tprintf.h:31
Definition: rect.h:30
static void ConnCompAndRectangularize(Pix *pix, DebugPixa *pixa_debug, Boxa **boxa, Pixa **pixa)
Definition: imagefind.cpp:158
int textord_tabfind_show_images
Definition: imagefind.cpp:38
GridSearch< ColPartition, ColPartition_CLIST, ColPartition_C_IT > ColPartitionGridSearch
Definition: colpartition.h:930

◆ FindImages()

Pix * tesseract::ImageFind::FindImages ( Pix *  pix,
DebugPixa pixa_debug 
)
static

Definition at line 66 of file imagefind.cpp.

66  {
67  // Not worth looking at small images.
68  if (pixGetWidth(pix) < kMinImageFindSize ||
69  pixGetHeight(pix) < kMinImageFindSize)
70  return pixCreate(pixGetWidth(pix), pixGetHeight(pix), 1);
71 
72  // Reduce by factor 2.
73  Pix *pixr = pixReduceRankBinaryCascade(pix, 1, 0, 0, 0);
74  if (textord_tabfind_show_images && pixa_debug != nullptr)
75  pixa_debug->AddPix(pixr, "CascadeReduced");
76 
77  // Get the halftone mask directly from Leptonica.
78  //
79  // Leptonica will print an error message and return NULL if we call
80  // pixGenHalftoneMask(pixr, NULL, ...) with too small image, so we
81  // want to bypass that.
82  if (pixGetWidth(pixr) < kMinImageFindSize ||
83  pixGetHeight(pixr) < kMinImageFindSize) {
84  pixDestroy(&pixr);
85  return pixCreate(pixGetWidth(pix), pixGetHeight(pix), 1);
86  }
87  // Get the halftone mask.
88  l_int32 ht_found = 0;
89  Pixa* pixadb = (textord_tabfind_show_images && pixa_debug != nullptr)
90  ? pixaCreate(0)
91  : nullptr;
92  Pix* pixht2 = pixGenerateHalftoneMask(pixr, NULL, &ht_found, pixadb);
93  if (pixadb) {
94  Pix* pixdb = pixaDisplayTiledInColumns(pixadb, 3, 1.0, 20, 2);
95  if (textord_tabfind_show_images && pixa_debug != nullptr)
96  pixa_debug->AddPix(pixdb, "HalftoneMask");
97  pixDestroy(&pixdb);
98  pixaDestroy(&pixadb);
99  }
100  pixDestroy(&pixr);
101  if (!ht_found && pixht2 != NULL)
102  pixDestroy(&pixht2);
103  if (pixht2 == NULL)
104  return pixCreate(pixGetWidth(pix), pixGetHeight(pix), 1);
105 
106  // Expand back up again.
107  Pix *pixht = pixExpandReplicate(pixht2, 2);
108  if (textord_tabfind_show_images && pixa_debug != nullptr)
109  pixa_debug->AddPix(pixht, "HalftoneReplicated");
110  pixDestroy(&pixht2);
111 
112  // Fill to capture pixels near the mask edges that were missed
113  Pix *pixt = pixSeedfillBinary(NULL, pixht, pix, 8);
114  pixOr(pixht, pixht, pixt);
115  pixDestroy(&pixt);
116 
117  // Eliminate lines and bars that may be joined to images.
118  Pix* pixfinemask = pixReduceRankBinaryCascade(pixht, 1, 1, 3, 3);
119  pixDilateBrick(pixfinemask, pixfinemask, 5, 5);
120  if (textord_tabfind_show_images && pixa_debug != nullptr)
121  pixa_debug->AddPix(pixfinemask, "FineMask");
122  Pix* pixreduced = pixReduceRankBinaryCascade(pixht, 1, 1, 1, 1);
123  Pix* pixreduced2 = pixReduceRankBinaryCascade(pixreduced, 3, 3, 3, 0);
124  pixDestroy(&pixreduced);
125  pixDilateBrick(pixreduced2, pixreduced2, 5, 5);
126  Pix* pixcoarsemask = pixExpandReplicate(pixreduced2, 8);
127  pixDestroy(&pixreduced2);
128  if (textord_tabfind_show_images && pixa_debug != nullptr)
129  pixa_debug->AddPix(pixcoarsemask, "CoarseMask");
130  // Combine the coarse and fine image masks.
131  pixAnd(pixcoarsemask, pixcoarsemask, pixfinemask);
132  pixDestroy(&pixfinemask);
133  // Dilate a bit to make sure we get everything.
134  pixDilateBrick(pixcoarsemask, pixcoarsemask, 3, 3);
135  Pix* pixmask = pixExpandReplicate(pixcoarsemask, 16);
136  pixDestroy(&pixcoarsemask);
137  if (textord_tabfind_show_images && pixa_debug != nullptr)
138  pixa_debug->AddPix(pixmask, "MaskDilated");
139  // And the image mask with the line and bar remover.
140  pixAnd(pixht, pixht, pixmask);
141  pixDestroy(&pixmask);
142  if (textord_tabfind_show_images && pixa_debug != nullptr)
143  pixa_debug->AddPix(pixht, "FinalMask");
144  // Make the result image the same size as the input.
145  Pix* result = pixCreate(pixGetWidth(pix), pixGetHeight(pix), 1);
146  pixOr(result, result, pixht);
147  pixDestroy(&pixht);
148  return result;
149 }
const int kMinImageFindSize
Definition: imagefind.cpp:51
int textord_tabfind_show_images
Definition: imagefind.cpp:38

◆ pixNearlyRectangular()

bool tesseract::ImageFind::pixNearlyRectangular ( Pix *  pix,
double  min_fraction,
double  max_fraction,
double  max_skew_gradient,
int *  x_start,
int *  y_start,
int *  x_end,
int *  y_end 
)
static

Definition at line 270 of file imagefind.cpp.

274  {
275  ASSERT_HOST(pix != NULL);
276  *x_start = 0;
277  *x_end = pixGetWidth(pix);
278  *y_start = 0;
279  *y_end = pixGetHeight(pix);
280 
281  uinT32* data = pixGetData(pix);
282  int wpl = pixGetWpl(pix);
283  bool any_cut = false;
284  bool left_done = false;
285  bool right_done = false;
286  bool top_done = false;
287  bool bottom_done = false;
288  do {
289  any_cut = false;
290  // Find the top/bottom edges.
291  int width = *x_end - *x_start;
292  int min_count = static_cast<int>(width * min_fraction);
293  int max_count = static_cast<int>(width * max_fraction);
294  int edge_width = static_cast<int>(width * max_skew_gradient);
295  if (HScanForEdge(data, wpl, *x_start, *x_end, min_count, edge_width,
296  max_count, *y_end, 1, y_start) && !top_done) {
297  top_done = true;
298  any_cut = true;
299  }
300  --(*y_end);
301  if (HScanForEdge(data, wpl, *x_start, *x_end, min_count, edge_width,
302  max_count, *y_start, -1, y_end) && !bottom_done) {
303  bottom_done = true;
304  any_cut = true;
305  }
306  ++(*y_end);
307 
308  // Find the left/right edges.
309  int height = *y_end - *y_start;
310  min_count = static_cast<int>(height * min_fraction);
311  max_count = static_cast<int>(height * max_fraction);
312  edge_width = static_cast<int>(height * max_skew_gradient);
313  if (VScanForEdge(data, wpl, *y_start, *y_end, min_count, edge_width,
314  max_count, *x_end, 1, x_start) && !left_done) {
315  left_done = true;
316  any_cut = true;
317  }
318  --(*x_end);
319  if (VScanForEdge(data, wpl, *y_start, *y_end, min_count, edge_width,
320  max_count, *x_start, -1, x_end) && !right_done) {
321  right_done = true;
322  any_cut = true;
323  }
324  ++(*x_end);
325  } while (any_cut);
326 
327  // All edges must satisfy the condition of sharp gradient in pixel density
328  // in order for the full rectangle to be present.
329  return left_done && right_done && top_done && bottom_done;
330 }
uint32_t uinT32
Definition: host.h:39
#define ASSERT_HOST(x)
Definition: errcode.h:84

◆ TransferImagePartsToImageMask()

void tesseract::ImageFind::TransferImagePartsToImageMask ( const FCOORD rerotation,
ColPartitionGrid part_grid,
Pix *  image_mask 
)
static

Definition at line 1249 of file imagefind.cpp.

1251  {
1252  // Extract the noise parts from the grid and put them on a temporary list.
1253  ColPartition_LIST parts_list;
1254  ColPartition_IT part_it(&parts_list);
1255  ColPartitionGridSearch gsearch(part_grid);
1256  gsearch.StartFullSearch();
1257  ColPartition* part;
1258  while ((part = gsearch.NextFullSearch()) != NULL) {
1259  BlobRegionType type = part->blob_type();
1260  if (type == BRT_NOISE || type == BRT_RECTIMAGE || type == BRT_POLYIMAGE) {
1261  part_it.add_after_then_move(part);
1262  gsearch.RemoveBBox();
1263  }
1264  }
1265  // Render listed noise partitions to the image mask.
1266  MarkAndDeleteImageParts(rerotation, part_grid, &parts_list, image_mask);
1267 }
BlobRegionType
Definition: blobbox.h:57
GridSearch< ColPartition, ColPartition_CLIST, ColPartition_C_IT > ColPartitionGridSearch
Definition: colpartition.h:930

The documentation for this class was generated from the following files: