tesseract  4.0.0-1-g2a2b
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_t *line1, const uint8_t *line2, const uint8_t *point)
 
static uint32_t ComposeRGB (uint32_t r, uint32_t g, uint32_t b)
 
static uint8_t ClipToByte (double pixel)
 
static void ComputeRectangleColors (const TBOX &rect, Pix *pix, int factor, Pix *color_map1, Pix *color_map2, Pix *rms_map, uint8_t *color1, uint8_t *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 577 of file imagefind.cpp.

579  {
580  TBOX search_box(box1);
581  search_box += box2;
582  if (box1.x_gap(box2) >= box1.y_gap(box2)) {
583  if (box1.x_gap(box2) <= 0)
584  return true;
585  search_box.set_left(std::min(box1.right(), box2.right()));
586  search_box.set_right(std::max(box1.left(), box2.left()));
587  } else {
588  if (box1.y_gap(box2) <= 0)
589  return true;
590  search_box.set_top(std::max(box1.bottom(), box2.bottom()));
591  search_box.set_bottom(std::min(box1.top(), box2.top()));
592  }
593  return CountPixelsInRotatedBox(search_box, im_box, rotation, pix) == 0;
594 }
static int CountPixelsInRotatedBox(TBOX box, const TBOX &im_box, const FCOORD &rotation, Pix *pix)
Definition: imagefind.cpp:598
int y_gap(const TBOX &box) const
Definition: rect.h:233
Definition: rect.h:34
int x_gap(const TBOX &box) const
Definition: rect.h:225
int16_t left() const
Definition: rect.h:72
int16_t top() const
Definition: rect.h:58
void set_left(int x)
Definition: rect.h:75
int16_t right() const
Definition: rect.h:79
int16_t bottom() const
Definition: rect.h:65

◆ BoundsWithinRect()

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

Definition at line 333 of file imagefind.cpp.

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

◆ ClipToByte()

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

Definition at line 397 of file imagefind.cpp.

397  {
398  if (pixel < 0.0)
399  return 0;
400  else if (pixel >= 255.0)
401  return 255;
402  return static_cast<uint8_t>(pixel);
403 }

◆ ColorDistanceFromLine()

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

Definition at line 356 of file imagefind.cpp.

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

◆ ComposeRGB()

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

Definition at line 390 of file imagefind.cpp.

390  {
391  l_uint32 result;
392  composeRGBPixel(r, g, b, &result);
393  return result;
394 }

◆ ComputeRectangleColors()

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

Definition at line 415 of file imagefind.cpp.

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

◆ ConnCompAndRectangularize()

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

Definition at line 155 of file imagefind.cpp.

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

◆ CountPixelsInRotatedBox()

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

Definition at line 598 of file imagefind.cpp.

599  {
600  // Intersect it with the image box.
601  box &= im_box; // This is in-place box intersection.
602  if (box.null_box())
603  return 0;
604  box.rotate(rotation);
605  TBOX rotated_im_box(im_box);
606  rotated_im_box.rotate(rotation);
607  Pix* rect_pix = pixCreate(box.width(), box.height(), 1);
608  pixRasterop(rect_pix, 0, 0, box.width(), box.height(),
609  PIX_SRC, pix, box.left() - rotated_im_box.left(),
610  rotated_im_box.top() - box.top());
611  l_int32 result;
612  pixCountPixels(rect_pix, &result, nullptr);
613  pixDestroy(&rect_pix);
614  return result;
615 }
void rotate(const FCOORD &vec)
Definition: rect.h:197
bool null_box() const
Definition: rect.h:50
Definition: rect.h:34
int16_t width() const
Definition: rect.h:115
int16_t left() const
Definition: rect.h:72
int16_t top() const
Definition: rect.h:58
int16_t height() const
Definition: rect.h:108

◆ 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 1299 of file imagefind.cpp.

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

◆ FindImages()

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

Definition at line 63 of file imagefind.cpp.

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

◆ 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 267 of file imagefind.cpp.

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

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

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