22 #pragma warning(disable:4244) // Conversion warnings 26 #include "config_auto.h" 36 #include "allheaders.h" 68 if (pixGetWidth(pix) < kMinImageFindSize ||
69 pixGetHeight(pix) < kMinImageFindSize)
70 return pixCreate(pixGetWidth(pix), pixGetHeight(pix), 1);
73 Pix *pixr = pixReduceRankBinaryCascade(pix, 1, 0, 0, 0);
75 pixa_debug->
AddPix(pixr,
"CascadeReduced");
82 if (pixGetWidth(pixr) < kMinImageFindSize ||
83 pixGetHeight(pixr) < kMinImageFindSize) {
85 return pixCreate(pixGetWidth(pix), pixGetHeight(pix), 1);
92 Pix* pixht2 = pixGenerateHalftoneMask(pixr, NULL, &ht_found, pixadb);
94 Pix* pixdb = pixaDisplayTiledInColumns(pixadb, 3, 1.0, 20, 2);
96 pixa_debug->
AddPix(pixdb,
"HalftoneMask");
101 if (!ht_found && pixht2 != NULL)
104 return pixCreate(pixGetWidth(pix), pixGetHeight(pix), 1);
107 Pix *pixht = pixExpandReplicate(pixht2, 2);
109 pixa_debug->
AddPix(pixht,
"HalftoneReplicated");
113 Pix *pixt = pixSeedfillBinary(NULL, pixht, pix, 8);
114 pixOr(pixht, pixht, pixt);
118 Pix* pixfinemask = pixReduceRankBinaryCascade(pixht, 1, 1, 3, 3);
119 pixDilateBrick(pixfinemask, pixfinemask, 5, 5);
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);
129 pixa_debug->
AddPix(pixcoarsemask,
"CoarseMask");
131 pixAnd(pixcoarsemask, pixcoarsemask, pixfinemask);
132 pixDestroy(&pixfinemask);
134 pixDilateBrick(pixcoarsemask, pixcoarsemask, 3, 3);
135 Pix* pixmask = pixExpandReplicate(pixcoarsemask, 16);
136 pixDestroy(&pixcoarsemask);
138 pixa_debug->
AddPix(pixmask,
"MaskDilated");
140 pixAnd(pixht, pixht, pixmask);
141 pixDestroy(&pixmask);
143 pixa_debug->
AddPix(pixht,
"FinalMask");
145 Pix* result = pixCreate(pixGetWidth(pix), pixGetHeight(pix), 1);
146 pixOr(result, result, pixht);
159 Boxa** boxa, Pixa** pixa) {
164 pixa_debug->
AddPix(pix,
"Conncompimage");
166 *boxa = pixConnComp(pix, pixa, 8);
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);
176 pixa_debug->
AddPix(img_pix,
"A component");
178 kMaxRectangularFraction,
179 kMaxRectangularGradient,
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);
185 pixaReplacePix(*pixa, i, simple_pix, NULL);
186 img_pix = pixaGetPix(*pixa, i, L_CLONE);
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);
194 pixDestroy(&img_pix);
205 static bool HScanForEdge(
uinT32* data,
int wpl,
int x_start,
int x_end,
206 int min_count,
int mid_width,
int max_count,
207 int y_end,
int y_step,
int* y_start) {
209 for (
int y = *y_start; y != y_end; y += y_step) {
212 uinT32* line = data + wpl * y;
213 for (
int x = x_start; x < x_end; ++x) {
214 if (GET_DATA_BIT(line, x))
217 if (mid_rows == 0 && pix_count < min_count)
221 if (pix_count > max_count)
224 if (mid_rows > mid_width)
237 static bool VScanForEdge(
uinT32* data,
int wpl,
int y_start,
int y_end,
238 int min_count,
int mid_width,
int max_count,
239 int x_end,
int x_step,
int* x_start) {
241 for (
int x = *x_start; x != x_end; x += x_step) {
243 uinT32* line = data + y_start * wpl;
244 for (
int y = y_start; y < y_end; ++y, line += wpl) {
245 if (GET_DATA_BIT(line, x))
248 if (mid_cols == 0 && pix_count < min_count)
252 if (pix_count > max_count)
255 if (mid_cols > mid_width)
271 double min_fraction,
double max_fraction,
272 double max_skew_gradient,
273 int* x_start,
int* y_start,
274 int* x_end,
int* y_end) {
277 *x_end = pixGetWidth(pix);
279 *y_end = pixGetHeight(pix);
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;
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) {
301 if (HScanForEdge(data, wpl, *x_start, *x_end, min_count, edge_width,
302 max_count, *y_start, -1, y_end) && !bottom_done) {
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) {
319 if (VScanForEdge(data, wpl, *y_start, *y_end, min_count, edge_width,
320 max_count, *x_start, -1, x_end) && !right_done) {
329 return left_done && right_done && top_done && bottom_done;
337 int* x_end,
int* y_end) {
338 Box* input_box = boxCreate(*x_start, *y_start, *x_end - *x_start,
340 Box* output_box = NULL;
341 pixClipBoxToForeground(pix, input_box, NULL, &output_box);
342 bool result = output_box != NULL;
344 l_int32 x, y, width, height;
345 boxGetGeometry(output_box, &x, &y, &width, &height);
350 boxDestroy(&output_box);
352 boxDestroy(&input_box);
361 const uinT8* point) {
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]);
368 line_vector[L_ALPHA_CHANNEL] = 0;
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;
379 double cross_sq = 0.0;
380 double line_sq = 0.0;
382 cross_sq +=
static_cast<double>(cross[j]) * cross[j];
383 line_sq +=
static_cast<double>(line_vector[j]) * line_vector[j];
385 if (line_sq == 0.0) {
388 return cross_sq / line_sq;
395 composeRGBPixel(r, g, b, &result);
403 else if (pixel >= 255.0)
405 return static_cast<uinT8>(pixel);
419 Pix* color_map1, Pix* color_map2,
422 ASSERT_HOST(pix != NULL && pixGetDepth(pix) == 32);
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)
438 Box* scaled_box = boxCreate(left_pad, height - top_pad,
439 width_pad, height_pad);
440 Pix* scaled = pixClipRectangle(pix, scaled_box, NULL);
443 STATS red_stats(0, 256);
444 STATS green_stats(0, 256);
445 STATS blue_stats(0, 256);
446 uinT32* data = pixGetData(scaled);
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);
454 green_stats.
add(g, 1);
455 blue_stats.
add(b, 1);
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) {
474 x_color = COLOR_GREEN;
475 y1_color = COLOR_RED;
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) {
483 x_color = COLOR_BLUE;
484 y1_color = COLOR_GREEN;
485 y2_color = COLOR_RED;
487 if (best_i8r >= kMinColorDifference) {
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);
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);
508 color1[y1_color] =
ClipToByte(m1 * best_l8 + c1 + 0.5);
509 color1[y2_color] =
ClipToByte(m2 * best_l8 + c2 + 0.5);
512 color2[y1_color] =
ClipToByte(m1 * best_u8 + c1 + 0.5);
513 color2[y2_color] =
ClipToByte(m2 * best_u8 + c2 + 0.5);
520 color1[L_ALPHA_CHANNEL] = 0;
521 memcpy(color2, color1, 4);
523 if (color_map1 != NULL) {
524 pixSetInRectArbitrary(color_map1, scaled_box,
527 color1[COLOR_BLUE]));
528 pixSetInRectArbitrary(color_map2, scaled_box,
531 color2[COLOR_BLUE]));
532 pixSetInRectArbitrary(rms_map, scaled_box, color1[L_ALPHA_CHANNEL]);
535 boxDestroy(&scaled_box);
583 TBOX search_box(box1);
586 if (box1.
x_gap(box2) <= 0)
591 if (box1.
y_gap(box2) <= 0)
602 const FCOORD& rotation, Pix* pix) {
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());
615 pixCountPixels(rect_pix, &result, NULL);
616 pixDestroy(&rect_pix);
624 static void AttemptToShrinkBox(
const FCOORD& rotation,
const FCOORD& rerotation,
625 const TBOX& im_box, Pix* pix,
TBOX* slice) {
626 TBOX rotated_box(*slice);
627 rotated_box.
rotate(rerotation);
628 TBOX rotated_im_box(im_box);
629 rotated_im_box.
rotate(rerotation);
630 int left = rotated_box.
left() - rotated_im_box.
left();
631 int right = rotated_box.
right() - rotated_im_box.
left();
632 int top = rotated_im_box.
top() - rotated_box.
top();
633 int bottom = rotated_im_box.
top() - rotated_box.
bottom();
635 top = rotated_im_box.
top() - top;
636 bottom = rotated_im_box.
top() - bottom;
637 left += rotated_im_box.
left();
638 right += rotated_im_box.
left();
640 rotated_box.
rotate(rotation);
669 static void CutChunkFromParts(
const TBOX& box,
const TBOX& im_box,
671 Pix* pix, ColPartition_LIST* part_list) {
673 ColPartition_IT part_it(part_list);
683 if (box.
top() < part_box.
top()) {
684 TBOX slice(part_box);
688 AttemptToShrinkBox(rotation, rerotation, im_box, pix, &slice);
689 part_it.add_before_stay_put(
696 TBOX slice(part_box);
698 if (box.
top() < part_box.
top())
704 AttemptToShrinkBox(rotation, rerotation, im_box, pix, &slice);
705 part_it.add_before_stay_put(
712 TBOX slice(part_box);
714 if (box.
top() < part_box.
top())
720 AttemptToShrinkBox(rotation, rerotation, im_box, pix, &slice);
721 part_it.add_before_stay_put(
728 TBOX slice(part_box);
732 AttemptToShrinkBox(rotation, rerotation, im_box, pix, &slice);
733 part_it.add_before_stay_put(
739 delete part_it.extract();
742 }
while (!part_it.at_first());
752 static void DivideImageIntoParts(
const TBOX& im_box,
const FCOORD& rotation,
753 const FCOORD& rerotation, Pix* pix,
755 ColPartition_LIST* part_list) {
760 ColPartition_IT part_it(part_list);
761 part_it.add_after_then_move(pix_part);
769 for (part_it.move_to_first(); !part_it.empty(); part_it.forward()) {
780 if (black_area * 2 < part_box.
area() || !im_box.
contains(part_box)) {
785 part_box.
set_top(part_box.
top() + padding / 2);
787 CutChunkFromParts(part_box, im_box, rotation, rerotation,
794 if (part_list->empty()) {
802 static int ExpandImageLeft(
const TBOX& box,
int left_limit,
811 if (part_box.y_gap(box) < 0) {
812 if (part_box.right() > left_limit && part_box.right() < box.
left())
813 left_limit = part_box.
right();
825 if (part_box.y_gap(box) < 0) {
826 if (part_box.right() > left_limit && part_box.right() < box.
left()) {
827 left_limit = part_box.
right();
838 static int ExpandImageRight(
const TBOX& box,
int right_limit,
847 if (part_box.y_gap(box) < 0) {
848 if (part_box.left() < right_limit && part_box.left() > box.
right())
849 right_limit = part_box.
left();
861 if (part_box.y_gap(box) < 0) {
862 if (part_box.left() < right_limit && part_box.left() > box.
right())
863 right_limit = part_box.
left();
873 static int ExpandImageBottom(
const TBOX& box,
int bottom_limit,
882 if (part_box.x_gap(box) < 0) {
883 if (part_box.top() > bottom_limit && part_box.top() < box.
bottom())
884 bottom_limit = part_box.
top();
896 if (part_box.x_gap(box) < 0) {
897 if (part_box.top() > bottom_limit && part_box.top() < box.
bottom())
898 bottom_limit = part_box.
top();
908 static int ExpandImageTop(
const TBOX& box,
int top_limit,
917 if (part_box.x_gap(box) < 0) {
918 if (part_box.bottom() < top_limit && part_box.bottom() > box.
top())
919 top_limit = part_box.
bottom();
931 if (part_box.x_gap(box) < 0) {
932 if (part_box.bottom() < top_limit && part_box.bottom() > box.
top())
933 top_limit = part_box.
bottom();
946 const TBOX& limit_box,
948 *expanded_box = im_box;
951 expanded_box->
set_left(ExpandImageLeft(im_box, limit_box.
left(),
955 expanded_box->
set_right(ExpandImageRight(im_box, limit_box.
right(),
959 expanded_box->
set_top(ExpandImageTop(im_box, limit_box.
top(), part_grid));
968 return expanded_box->
area() - im_box.
area();
977 memset(dunnit, 0,
sizeof(dunnit));
980 TBOX text_box(*im_box);
981 for (
int iteration = 0; iteration <
BND_COUNT; ++iteration) {
986 for (
int dir = 0; dir <
BND_COUNT; ++dir) {
990 int area_delta = ExpandImageDir(bnd, text_box, limit_box, part_grid,
991 &expanded_boxes[bnd]);
992 if (best_delta < 0 || area_delta < best_delta) {
993 best_delta = area_delta;
999 dunnit[best_dir] =
true;
1000 text_box = expanded_boxes[best_dir];
1036 static bool ExpandImageIntoParts(
const TBOX& max_image_box,
1043 tprintf(
"Searching for merge with image part:");
1044 im_part_box.
print();
1046 max_image_box.
print();
1054 tprintf(
"Considering merge with part:");
1059 tprintf(
"Not within text box\n");
1074 DeletePartition(part);
1077 int x_dist =
MAX(0, box.
x_gap(im_part_box));
1078 int y_dist =
MAX(0, box.
y_gap(im_part_box));
1079 int dist = x_dist * x_dist + y_dist * y_dist;
1080 if (dist > box.
area() || dist > im_part_box.
area())
1082 if (best_part == NULL || dist < best_dist) {
1089 if (best_part != NULL) {
1093 tprintf(
"Merging image part:");
1094 im_part_box.
print();
1102 DeletePartition(image_part);
1104 DeletePartition(best_part);
1113 static int IntersectArea(
const TBOX& box, ColPartition_LIST* part_list) {
1114 int intersect_area = 0;
1115 ColPartition_IT part_it(part_list);
1117 for (part_it.mark_cycle_pt(); !part_it.cycled_list();
1118 part_it.forward()) {
1121 intersect_area += intersect.
area();
1123 return intersect_area;
1131 static bool TestWeakIntersectedPart(
const TBOX& im_box,
1132 ColPartition_LIST* part_list,
1138 int area = part_box.
area();
1139 int intersect_area = IntersectArea(part_box, part_list);
1140 if (area < 2 * intersect_area) {
1153 static void EliminateWeakParts(
const TBOX& im_box,
1155 ColPartition_LIST* big_parts,
1156 ColPartition_LIST* part_list) {
1161 if (TestWeakIntersectedPart(im_box, part_list, part)) {
1165 DeletePartition(part);
1175 ColPartition_IT big_it(big_parts);
1176 for (big_it.mark_cycle_pt(); !big_it.cycled_list(); big_it.forward()) {
1177 part = big_it.data();
1178 if (TestWeakIntersectedPart(im_box, part_list, part)) {
1180 DeletePartition(big_it.extract());
1191 TBOX padded_box(*box);
1192 padded_box.
pad(kNoisePadding, kNoisePadding);
1195 bool any_text_in_padded_rect =
false;
1200 any_text_in_padded_rect =
true;
1207 if (!any_text_in_padded_rect)
1216 static void MarkAndDeleteImageParts(
const FCOORD& rerotate,
1218 ColPartition_LIST* image_parts,
1220 if (image_pix == NULL)
1222 int imageheight = pixGetHeight(image_pix);
1223 ColPartition_IT part_it(image_parts);
1224 for (; !part_it.empty(); part_it.forward()) {
1228 if (!ScanForOverlappingText(part_grid, &part_box) ||
1232 part_box.
rotate(rerotate);
1233 int left = part_box.
left();
1234 int top = part_box.
top();
1235 pixRasterop(image_pix, left, imageheight - top,
1236 part_box.
width(), part_box.
height(), PIX_SET, NULL, 0, 0);
1238 DeletePartition(part);
1253 ColPartition_LIST parts_list;
1254 ColPartition_IT part_it(&parts_list);
1261 part_it.add_after_then_move(part);
1266 MarkAndDeleteImageParts(rerotation, part_grid, &parts_list, image_mask);
1273 if (part_grid != NULL)
return;
1282 if (part_box.
width() < kMinImageFindSize ||
1286 DeletePartition(part);
1306 ColPartition_LIST* big_parts) {
1307 int imageheight = pixGetHeight(image_pix);
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);
1322 ColPartition_LIST part_list;
1323 DivideImageIntoParts(im_box, rotation, rerotation, pix,
1324 &rectsearch, &part_list);
1326 pixa_debug->
AddPix(pix,
"ImageComponent");
1327 tprintf(
"Component has %d parts\n", part_list.length());
1330 if (!part_list.empty()) {
1331 ColPartition_IT part_it(&part_list);
1332 if (part_list.singleton()) {
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);
1344 EliminateWeakParts(im_box, part_grid, big_parts, &part_list);
1346 for (part_it.move_to_first(); !part_it.empty(); part_it.forward()) {
1349 part_grid->
InsertBBox(
true,
true, image_part);
1350 if (!part_it.at_last()) {
1360 DeleteSmallImages(part_grid);
static bool BlankImageInBetween(const TBOX &box1, const TBOX &box2, const TBOX &im_box, const FCOORD &rotation, Pix *pix)
void SetUniqueMode(bool mode)
const int kMinImageFindSize
const TBOX & bounding_box() const
void StartRectSearch(const TBOX &rect)
void set_blob_type(BlobRegionType t)
void add(inT32 value, inT32 count)
void RemoveBBox(BBC *bbox)
void StartSideSearch(int x, int ymin, int ymax)
static uinT8 ClipToByte(double pixel)
TBOX intersection(const TBOX &box) const
const ICOORD & bleft() const
const double kMinRectangularFraction
static void ComputeRectangleColors(const TBOX &rect, Pix *pix, int factor, Pix *color_map1, Pix *color_map2, Pix *rms_map, uinT8 *color1, uinT8 *color2)
BlobTextFlowType flow() const
inT16 x() const
access function
ScrollView * MakeWindow(int x, int y, const char *window_name)
const double kMaxRectangularGradient
void AddPix(const Pix *pix, const char *caption)
static void TransferImagePartsToImageMask(const FCOORD &rerotation, ColPartitionGrid *part_grid, Pix *image_mask)
static bool BoundsWithinRect(Pix *pix, int *x_start, int *y_start, int *x_end, int *y_end)
void RepositionIterator()
static ColPartition * FakePartition(const TBOX &box, PolyBlockType block_type, BlobRegionType blob_type, BlobTextFlowType flow)
int y_gap(const TBOX &box) const
double rms(double m, double c) const
void set_to_given_coords(int x_min, int y_min, int x_max, int y_max)
BBC * NextSideSearch(bool right_to_left)
BBC * NextVerticalSearch(bool top_to_bottom)
BlobRegionType blob_type() const
void add(double x, double y)
void DisplayBoxes(ScrollView *window)
#define INT_VAR(name, val, comment)
void AddPartner(bool upper, ColPartition *partner)
LIST search(LIST list, void *key, int_compare is_equal)
const double kRMSFitScaling
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 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)
void pad(int xpad, int ypad)
void InsertBBox(bool h_spread, bool v_spread, BBC *bbox)
int x_gap(const TBOX &box) const
static Pix * FindImages(Pix *pix, DebugPixa *pixa_debug)
void set_flow(BlobTextFlowType f)
const ICOORD & tright() const
const int kMinColorDifference
static void ConnCompAndRectangularize(Pix *pix, DebugPixa *pixa_debug, Boxa **boxa, Pixa **pixa)
bool contains(const FCOORD pt) const
static int CountPixelsInRotatedBox(TBOX box, const TBOX &im_box, const FCOORD &rotation, Pix *pix)
inT16 y() const
access_function
void rotate(const FCOORD &vec)
int textord_tabfind_show_images
double ile(double frac) const
void StartVerticalSearch(int xmin, int xmax, int y)
const double kMaxRectangularFraction
static double ColorDistanceFromLine(const uinT8 *line1, const uinT8 *line2, const uinT8 *point)
bool overlap(const TBOX &box) const
static uinT32 ComposeRGB(uinT32 r, uinT32 g, uinT32 b)