tesseract 4.1.1
Loading...
Searching...
No Matches
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 576 of file imagefind.cpp.

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

◆ BoundsWithinRect()

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

Definition at line 332 of file imagefind.cpp.

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

◆ ClipToByte()

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

Definition at line 396 of file imagefind.cpp.

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

◆ ColorDistanceFromLine()

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

Definition at line 355 of file imagefind.cpp.

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

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

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

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

◆ ConnCompAndRectangularize()

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

Definition at line 154 of file imagefind.cpp.

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

◆ CountPixelsInRotatedBox()

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

Definition at line 597 of file imagefind.cpp.

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

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

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

◆ FindImages()

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

Definition at line 62 of file imagefind.cpp.

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

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

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

◆ TransferImagePartsToImageMask()

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

Definition at line 1245 of file imagefind.cpp.

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

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