22 #pragma warning(disable:4244) // Conversion warnings 36 #include "allheaders.h" 69 return pixCreate(pixGetWidth(pix), pixGetHeight(pix), 1);
72 Pix *pixr = pixReduceRankBinaryCascade(pix, 1, 0, 0, 0);
83 return pixCreate(pixGetWidth(pix), pixGetHeight(pix), 1);
86 Pix *pixht2 = pixGenHalftoneMask(pixr, NULL, &ht_found,
89 if (!ht_found && pixht2 != NULL)
92 return pixCreate(pixGetWidth(pix), pixGetHeight(pix), 1);
95 Pix *pixht = pixExpandReplicate(pixht2, 2);
100 Pix *pixt = pixSeedfillBinary(NULL, pixht, pix, 8);
101 pixOr(pixht, pixht, pixt);
105 Pix* pixfinemask = pixReduceRankBinaryCascade(pixht, 1, 1, 3, 3);
106 pixDilateBrick(pixfinemask, pixfinemask, 5, 5);
108 Pix* pixreduced = pixReduceRankBinaryCascade(pixht, 1, 1, 1, 1);
109 Pix* pixreduced2 = pixReduceRankBinaryCascade(pixreduced, 3, 3, 3, 0);
110 pixDestroy(&pixreduced);
111 pixDilateBrick(pixreduced2, pixreduced2, 5, 5);
112 Pix* pixcoarsemask = pixExpandReplicate(pixreduced2, 8);
113 pixDestroy(&pixreduced2);
116 pixAnd(pixcoarsemask, pixcoarsemask, pixfinemask);
117 pixDestroy(&pixfinemask);
119 pixDilateBrick(pixcoarsemask, pixcoarsemask, 3, 3);
120 Pix* pixmask = pixExpandReplicate(pixcoarsemask, 16);
121 pixDestroy(&pixcoarsemask);
123 pixWrite(
"junkexpandedcoarsemask.png", pixmask, IFF_PNG);
125 pixAnd(pixht, pixht, pixmask);
126 pixDestroy(&pixmask);
128 pixWrite(
"junkfinalimagemask.png", pixht, IFF_PNG);
130 Pix* result = pixCreate(pixGetWidth(pix), pixGetHeight(pix), 1);
131 pixOr(result, result, pixht);
148 pixWrite(
"junkconncompimage.png", pix, IFF_PNG);
150 *boxa = pixConnComp(pix, pixa, 8);
154 int npixes = pixaGetCount(*pixa);
155 for (
int i = 0; i < npixes; ++i) {
156 int x_start, x_end, y_start, y_end;
157 Pix* img_pix = pixaGetPix(*pixa, i, L_CLONE);
162 &x_start, &y_start, &x_end, &y_end)) {
163 Pix* simple_pix = pixCreate(x_end - x_start, y_end - y_start, 1);
164 pixSetAll(simple_pix);
165 pixDestroy(&img_pix);
167 pixaReplacePix(*pixa, i, simple_pix, NULL);
168 img_pix = pixaGetPix(*pixa, i, L_CLONE);
170 l_int32 x, y, width, height;
171 boxaGetBoxGeometry(*boxa, i, &x, &y, &width, &height);
172 Box* simple_box = boxCreate(x + x_start, y + y_start,
173 x_end - x_start, y_end - y_start);
174 boxaReplaceBox(*boxa, i, simple_box);
176 pixDestroy(&img_pix);
187 static bool HScanForEdge(
uinT32* data,
int wpl,
int x_start,
int x_end,
188 int min_count,
int mid_width,
int max_count,
189 int y_end,
int y_step,
int* y_start) {
191 for (
int y = *y_start; y != y_end; y += y_step) {
194 uinT32* line = data + wpl * y;
195 for (
int x = x_start; x < x_end; ++x) {
196 if (GET_DATA_BIT(line, x))
199 if (mid_rows == 0 && pix_count < min_count)
203 if (pix_count > max_count)
206 if (mid_rows > mid_width)
219 static bool VScanForEdge(
uinT32* data,
int wpl,
int y_start,
int y_end,
220 int min_count,
int mid_width,
int max_count,
221 int x_end,
int x_step,
int* x_start) {
223 for (
int x = *x_start; x != x_end; x += x_step) {
225 uinT32* line = data + y_start * wpl;
226 for (
int y = y_start; y < y_end; ++y, line += wpl) {
227 if (GET_DATA_BIT(line, x))
230 if (mid_cols == 0 && pix_count < min_count)
234 if (pix_count > max_count)
237 if (mid_cols > mid_width)
253 double min_fraction,
double max_fraction,
254 double max_skew_gradient,
255 int* x_start,
int* y_start,
256 int* x_end,
int* y_end) {
259 *x_end = pixGetWidth(pix);
261 *y_end = pixGetHeight(pix);
263 uinT32* data = pixGetData(pix);
264 int wpl = pixGetWpl(pix);
265 bool any_cut =
false;
266 bool left_done =
false;
267 bool right_done =
false;
268 bool top_done =
false;
269 bool bottom_done =
false;
273 int width = *x_end - *x_start;
274 int min_count =
static_cast<int>(width * min_fraction);
275 int max_count =
static_cast<int>(width * max_fraction);
276 int edge_width =
static_cast<int>(width * max_skew_gradient);
277 if (HScanForEdge(data, wpl, *x_start, *x_end, min_count, edge_width,
278 max_count, *y_end, 1, y_start) && !top_done) {
283 if (HScanForEdge(data, wpl, *x_start, *x_end, min_count, edge_width,
284 max_count, *y_start, -1, y_end) && !bottom_done) {
291 int height = *y_end - *y_start;
292 min_count =
static_cast<int>(height * min_fraction);
293 max_count =
static_cast<int>(height * max_fraction);
294 edge_width =
static_cast<int>(height * max_skew_gradient);
295 if (VScanForEdge(data, wpl, *y_start, *y_end, min_count, edge_width,
296 max_count, *x_end, 1, x_start) && !left_done) {
301 if (VScanForEdge(data, wpl, *y_start, *y_end, min_count, edge_width,
302 max_count, *x_start, -1, x_end) && !right_done) {
311 return left_done && right_done && top_done && bottom_done;
319 int* x_end,
int* y_end) {
320 Box* input_box = boxCreate(*x_start, *y_start, *x_end - *x_start,
322 Box* output_box = NULL;
323 pixClipBoxToForeground(pix, input_box, NULL, &output_box);
324 bool result = output_box != NULL;
326 l_int32 x, y, width, height;
327 boxGetGeometry(output_box, &x, &y, &width, &height);
332 boxDestroy(&output_box);
334 boxDestroy(&input_box);
343 const uinT8* point) {
347 line_vector[i] =
static_cast<int>(line2[i]) - static_cast<int>(line1[i]);
348 point_vector[i] =
static_cast<int>(point[i]) - static_cast<int>(line1[i]);
350 line_vector[L_ALPHA_CHANNEL] = 0;
353 cross[COLOR_RED] = line_vector[COLOR_GREEN] * point_vector[COLOR_BLUE]
354 - line_vector[COLOR_BLUE] * point_vector[COLOR_GREEN];
355 cross[COLOR_GREEN] = line_vector[COLOR_BLUE] * point_vector[COLOR_RED]
356 - line_vector[COLOR_RED] * point_vector[COLOR_BLUE];
357 cross[COLOR_BLUE] = line_vector[COLOR_RED] * point_vector[COLOR_GREEN]
358 - line_vector[COLOR_GREEN] * point_vector[COLOR_RED];
359 cross[L_ALPHA_CHANNEL] = 0;
361 double cross_sq = 0.0;
362 double line_sq = 0.0;
364 cross_sq +=
static_cast<double>(cross[j]) * cross[j];
365 line_sq +=
static_cast<double>(line_vector[j]) * line_vector[j];
367 if (line_sq == 0.0) {
370 return cross_sq / line_sq;
377 composeRGBPixel(r, g, b, &result);
385 else if (pixel >= 255.0)
387 return static_cast<uinT8>(pixel);
401 Pix* color_map1, Pix* color_map2,
404 ASSERT_HOST(pix != NULL && pixGetDepth(pix) == 32);
407 int width = pixGetWidth(pix);
408 int height = pixGetHeight(pix);
409 int left_pad =
MAX(rect.
left() - 2 * factor, 0) / factor;
410 int top_pad = (rect.
top() + 2 * factor + (factor - 1)) / factor;
411 top_pad =
MIN(height, top_pad);
412 int right_pad = (rect.
right() + 2 * factor + (factor - 1)) / factor;
413 right_pad =
MIN(width, right_pad);
414 int bottom_pad =
MAX(rect.
bottom() - 2 * factor, 0) / factor;
415 int width_pad = right_pad - left_pad;
416 int height_pad = top_pad - bottom_pad;
417 if (width_pad < 1 || height_pad < 1 || width_pad + height_pad < 4)
420 Box* scaled_box = boxCreate(left_pad, height - top_pad,
421 width_pad, height_pad);
422 Pix* scaled = pixClipRectangle(pix, scaled_box, NULL);
425 STATS red_stats(0, 256);
426 STATS green_stats(0, 256);
427 STATS blue_stats(0, 256);
428 uinT32* data = pixGetData(scaled);
430 for (
int y = 0; y < height_pad; ++y) {
431 for (
int x = 0; x < width_pad; ++x, ++data) {
432 int r = GET_DATA_BYTE(data, COLOR_RED);
433 int g = GET_DATA_BYTE(data, COLOR_GREEN);
434 int b = GET_DATA_BYTE(data, COLOR_BLUE);
436 green_stats.
add(g, 1);
437 blue_stats.
add(b, 1);
444 int best_l8 =
static_cast<int>(red_stats.
ile(0.125f));
445 int best_u8 =
static_cast<int>(ceil(red_stats.
ile(0.875f)));
446 int best_i8r = best_u8 - best_l8;
447 int x_color = COLOR_RED;
448 int y1_color = COLOR_GREEN;
449 int y2_color = COLOR_BLUE;
450 int l8 =
static_cast<int>(green_stats.
ile(0.125f));
451 int u8 =
static_cast<int>(ceil(green_stats.
ile(0.875f)));
452 if (u8 - l8 > best_i8r) {
456 x_color = COLOR_GREEN;
457 y1_color = COLOR_RED;
459 l8 =
static_cast<int>(blue_stats.
ile(0.125f));
460 u8 =
static_cast<int>(ceil(blue_stats.
ile(0.875f)));
461 if (u8 - l8 > best_i8r) {
465 x_color = COLOR_BLUE;
466 y1_color = COLOR_GREEN;
467 y2_color = COLOR_RED;
472 uinT32* data = pixGetData(scaled);
473 for (
int im_y = 0; im_y < height_pad; ++im_y) {
474 for (
int im_x = 0; im_x < width_pad; ++im_x, ++data) {
475 int x = GET_DATA_BYTE(data, x_color);
476 int y1 = GET_DATA_BYTE(data, y1_color);
477 int y2 = GET_DATA_BYTE(data, y2_color);
482 double m1 = line1.
m();
483 double c1 = line1.
c(m1);
484 double m2 = line2.
m();
485 double c2 = line2.
c(m2);
486 double rms = line1.
rms(m1, c1) + line2.
rms(m2, c2);
490 color1[y1_color] =
ClipToByte(m1 * best_l8 + c1 + 0.5);
491 color1[y2_color] =
ClipToByte(m2 * best_l8 + c2 + 0.5);
494 color2[y1_color] =
ClipToByte(m1 * best_u8 + c1 + 0.5);
495 color2[y2_color] =
ClipToByte(m2 * best_u8 + c2 + 0.5);
502 color1[L_ALPHA_CHANNEL] = 0;
503 memcpy(color2, color1, 4);
505 if (color_map1 != NULL) {
506 pixSetInRectArbitrary(color_map1, scaled_box,
509 color1[COLOR_BLUE]));
510 pixSetInRectArbitrary(color_map2, scaled_box,
513 color2[COLOR_BLUE]));
514 pixSetInRectArbitrary(rms_map, scaled_box, color1[L_ALPHA_CHANNEL]);
517 boxDestroy(&scaled_box);
565 TBOX search_box(box1);
568 if (box1.
x_gap(box2) <= 0)
573 if (box1.
y_gap(box2) <= 0)
584 const FCOORD& rotation, Pix* pix) {
590 TBOX rotated_im_box(im_box);
591 rotated_im_box.
rotate(rotation);
592 Pix* rect_pix = pixCreate(box.
width(), box.
height(), 1);
593 pixRasterop(rect_pix, 0, 0, box.
width(), box.
height(),
594 PIX_SRC, pix, box.
left() - rotated_im_box.
left(),
595 rotated_im_box.
top() - box.
top());
597 pixCountPixels(rect_pix, &result, NULL);
598 pixDestroy(&rect_pix);
606 static void AttemptToShrinkBox(
const FCOORD& rotation,
const FCOORD& rerotation,
607 const TBOX& im_box, Pix* pix,
TBOX* slice) {
608 TBOX rotated_box(*slice);
609 rotated_box.rotate(rerotation);
610 TBOX rotated_im_box(im_box);
611 rotated_im_box.rotate(rerotation);
612 int left = rotated_box.left() - rotated_im_box.left();
613 int right = rotated_box.right() - rotated_im_box.left();
614 int top = rotated_im_box.top() - rotated_box.top();
615 int bottom = rotated_im_box.top() - rotated_box.bottom();
617 top = rotated_im_box.top() - top;
618 bottom = rotated_im_box.top() - bottom;
619 left += rotated_im_box.left();
620 right += rotated_im_box.left();
621 rotated_box.set_to_given_coords(left, bottom, right, top);
622 rotated_box.rotate(rotation);
623 slice->
set_left(rotated_box.left());
651 static void CutChunkFromParts(
const TBOX& box,
const TBOX& im_box,
653 Pix* pix, ColPartition_LIST* part_list) {
655 ColPartition_IT part_it(part_list);
657 ColPartition* part = part_it.data();
658 TBOX part_box = part->bounding_box();
665 if (box.
top() < part_box.
top()) {
666 TBOX slice(part_box);
670 AttemptToShrinkBox(rotation, rerotation, im_box, pix, &slice);
671 part_it.add_before_stay_put(
678 TBOX slice(part_box);
680 if (box.
top() < part_box.
top())
686 AttemptToShrinkBox(rotation, rerotation, im_box, pix, &slice);
687 part_it.add_before_stay_put(
694 TBOX slice(part_box);
696 if (box.
top() < part_box.
top())
702 AttemptToShrinkBox(rotation, rerotation, im_box, pix, &slice);
703 part_it.add_before_stay_put(
710 TBOX slice(part_box);
714 AttemptToShrinkBox(rotation, rerotation, im_box, pix, &slice);
715 part_it.add_before_stay_put(
721 delete part_it.extract();
724 }
while (!part_it.at_first());
734 static void DivideImageIntoParts(
const TBOX& im_box,
const FCOORD& rotation,
735 const FCOORD& rerotation, Pix* pix,
737 ColPartition_LIST* part_list) {
742 ColPartition_IT part_it(part_list);
743 part_it.add_after_then_move(pix_part);
745 rectsearch->StartRectSearch(im_box);
747 while ((part = rectsearch->NextRectSearch()) != NULL) {
748 TBOX part_box = part->bounding_box();
751 for (part_it.move_to_first(); !part_it.empty(); part_it.forward()) {
752 ColPartition* pix_part = part_it.extract();
753 pix_part->DeleteBoxes();
762 if (black_area * 2 < part_box.
area() || !im_box.
contains(part_box)) {
767 part_box.
set_top(part_box.
top() + padding / 2);
769 CutChunkFromParts(part_box, im_box, rotation, rerotation,
776 if (part_list->empty()) {
784 static int ExpandImageLeft(
const TBOX& box,
int left_limit,
785 ColPartitionGrid* part_grid) {
790 while ((part =
search.NextSideSearch(
true)) != NULL) {
792 const TBOX& part_box(part->bounding_box());
793 if (part_box.
y_gap(box) < 0) {
794 if (part_box.
right() > left_limit && part_box.
right() < box.
left())
795 left_limit = part_box.
right();
803 search.StartRectSearch(search_box);
804 while ((part =
search.NextRectSearch()) != NULL) {
806 const TBOX& part_box(part->bounding_box());
807 if (part_box.
y_gap(box) < 0) {
808 if (part_box.
right() > left_limit && part_box.
right() < box.
left()) {
809 left_limit = part_box.
right();
820 static int ExpandImageRight(
const TBOX& box,
int right_limit,
821 ColPartitionGrid* part_grid) {
826 while ((part =
search.NextSideSearch(
false)) != NULL) {
828 const TBOX& part_box(part->bounding_box());
829 if (part_box.
y_gap(box) < 0) {
830 if (part_box.
left() < right_limit && part_box.
left() > box.
right())
831 right_limit = part_box.
left();
839 search.StartRectSearch(search_box);
840 while ((part =
search.NextRectSearch()) != NULL) {
842 const TBOX& part_box(part->bounding_box());
843 if (part_box.
y_gap(box) < 0) {
844 if (part_box.
left() < right_limit && part_box.
left() > box.
right())
845 right_limit = part_box.
left();
855 static int ExpandImageBottom(
const TBOX& box,
int bottom_limit,
856 ColPartitionGrid* part_grid) {
861 while ((part =
search.NextVerticalSearch(
true)) != NULL) {
863 const TBOX& part_box(part->bounding_box());
864 if (part_box.
x_gap(box) < 0) {
865 if (part_box.
top() > bottom_limit && part_box.
top() < box.
bottom())
866 bottom_limit = part_box.
top();
874 search.StartRectSearch(search_box);
875 while ((part =
search.NextRectSearch()) != NULL) {
877 const TBOX& part_box(part->bounding_box());
878 if (part_box.
x_gap(box) < 0) {
879 if (part_box.
top() > bottom_limit && part_box.
top() < box.
bottom())
880 bottom_limit = part_box.
top();
890 static int ExpandImageTop(
const TBOX& box,
int top_limit,
891 ColPartitionGrid* part_grid) {
896 while ((part =
search.NextVerticalSearch(
false)) != NULL) {
898 const TBOX& part_box(part->bounding_box());
899 if (part_box.
x_gap(box) < 0) {
901 top_limit = part_box.
bottom();
909 search.StartRectSearch(search_box);
910 while ((part =
search.NextRectSearch()) != NULL) {
912 const TBOX& part_box(part->bounding_box());
913 if (part_box.
x_gap(box) < 0) {
915 top_limit = part_box.
bottom();
928 const TBOX& limit_box,
929 ColPartitionGrid* part_grid,
TBOX* expanded_box) {
930 *expanded_box = im_box;
933 expanded_box->
set_left(ExpandImageLeft(im_box, limit_box.
left(),
937 expanded_box->
set_right(ExpandImageRight(im_box, limit_box.
right(),
941 expanded_box->
set_top(ExpandImageTop(im_box, limit_box.
top(), part_grid));
950 return expanded_box->
area() - im_box.
area();
957 static void MaximalImageBoundingBox(ColPartitionGrid* part_grid,
TBOX* im_box) {
959 memset(dunnit, 0,
sizeof(dunnit));
960 TBOX limit_box(part_grid->bleft().x(), part_grid->bleft().y(),
961 part_grid->tright().x(), part_grid->tright().y());
962 TBOX text_box(*im_box);
963 for (
int iteration = 0; iteration <
BND_COUNT; ++iteration) {
968 for (
int dir = 0; dir <
BND_COUNT; ++dir) {
972 int area_delta = ExpandImageDir(bnd, text_box, limit_box, part_grid,
973 &expanded_boxes[bnd]);
974 if (best_delta < 0 || area_delta < best_delta) {
975 best_delta = area_delta;
981 dunnit[best_dir] =
true;
982 text_box = expanded_boxes[best_dir];
991 static void DeletePartition(ColPartition* part) {
1000 part->SetBlobTypes();
1001 part->DisownBoxes();
1018 static bool ExpandImageIntoParts(
const TBOX& max_image_box,
1020 ColPartitionGrid* part_grid,
1021 ColPartition** part_ptr) {
1022 ColPartition* image_part = *part_ptr;
1023 TBOX im_part_box = image_part->bounding_box();
1025 tprintf(
"Searching for merge with image part:");
1026 im_part_box.
print();
1028 max_image_box.
print();
1030 rectsearch->StartRectSearch(max_image_box);
1032 ColPartition* best_part = NULL;
1034 while ((part = rectsearch->NextRectSearch()) != NULL) {
1036 tprintf(
"Considering merge with part:");
1038 if (im_part_box.
contains(part->bounding_box()))
1040 else if (!max_image_box.
contains(part->bounding_box()))
1041 tprintf(
"Not within text box\n");
1051 TBOX box = part->bounding_box();
1055 rectsearch->RemoveBBox();
1056 DeletePartition(part);
1059 int x_dist =
MAX(0, box.
x_gap(im_part_box));
1060 int y_dist =
MAX(0, box.
y_gap(im_part_box));
1061 int dist = x_dist * x_dist + y_dist * y_dist;
1062 if (dist > box.
area() || dist > im_part_box.
area())
1064 if (best_part == NULL || dist < best_dist) {
1071 if (best_part != NULL) {
1073 TBOX box = best_part->bounding_box();
1075 tprintf(
"Merging image part:");
1076 im_part_box.
print();
1084 DeletePartition(image_part);
1085 part_grid->RemoveBBox(best_part);
1086 DeletePartition(best_part);
1087 rectsearch->RepositionIterator();
1095 static int IntersectArea(
const TBOX& box, ColPartition_LIST* part_list) {
1096 int intersect_area = 0;
1097 ColPartition_IT part_it(part_list);
1099 for (part_it.mark_cycle_pt(); !part_it.cycled_list();
1100 part_it.forward()) {
1101 ColPartition* image_part = part_it.data();
1103 intersect_area += intersect.
area();
1105 return intersect_area;
1113 static bool TestWeakIntersectedPart(
const TBOX& im_box,
1114 ColPartition_LIST* part_list,
1115 ColPartition* part) {
1118 const TBOX& part_box = part->bounding_box();
1120 int area = part_box.
area();
1121 int intersect_area = IntersectArea(part_box, part_list);
1122 if (area < 2 * intersect_area) {
1135 static void EliminateWeakParts(
const TBOX& im_box,
1136 ColPartitionGrid* part_grid,
1137 ColPartition_LIST* big_parts,
1138 ColPartition_LIST* part_list) {
1141 rectsearch.StartRectSearch(im_box);
1142 while ((part = rectsearch.NextRectSearch()) != NULL) {
1143 if (TestWeakIntersectedPart(im_box, part_list, part)) {
1146 rectsearch.RemoveBBox();
1147 DeletePartition(part);
1153 part->SetBlobTypes();
1157 ColPartition_IT big_it(big_parts);
1158 for (big_it.mark_cycle_pt(); !big_it.cycled_list(); big_it.forward()) {
1159 part = big_it.data();
1160 if (TestWeakIntersectedPart(im_box, part_list, part)) {
1162 DeletePartition(big_it.extract());
1171 static bool ScanForOverlappingText(ColPartitionGrid* part_grid,
TBOX* box) {
1173 TBOX padded_box(*box);
1175 rectsearch.StartRectSearch(padded_box);
1177 bool any_text_in_padded_rect =
false;
1178 while ((part = rectsearch.NextRectSearch()) != NULL) {
1182 any_text_in_padded_rect =
true;
1183 const TBOX& part_box = part->bounding_box();
1189 if (!any_text_in_padded_rect)
1198 static void MarkAndDeleteImageParts(
const FCOORD& rerotate,
1199 ColPartitionGrid* part_grid,
1200 ColPartition_LIST* image_parts,
1202 if (image_pix == NULL)
1204 int imageheight = pixGetHeight(image_pix);
1205 ColPartition_IT part_it(image_parts);
1206 for (; !part_it.empty(); part_it.forward()) {
1207 ColPartition* part = part_it.extract();
1208 TBOX part_box = part->bounding_box();
1210 if (!ScanForOverlappingText(part_grid, &part_box) ||
1214 part_box.
rotate(rerotate);
1215 int left = part_box.
left();
1216 int top = part_box.
top();
1217 pixRasterop(image_pix, left, imageheight - top,
1218 part_box.
width(), part_box.
height(), PIX_SET, NULL, 0, 0);
1220 DeletePartition(part);
1235 ColPartition_LIST parts_list;
1236 ColPartition_IT part_it(&parts_list);
1243 part_it.add_after_then_move(part);
1248 MarkAndDeleteImageParts(rerotation, part_grid, &parts_list, image_mask);
1255 if (part_grid != NULL)
return;
1257 gsearch.StartFullSearch();
1259 while ((part = gsearch.NextFullSearch()) != NULL) {
1267 gsearch.RemoveBBox();
1268 DeletePartition(part);
1286 const FCOORD& rerotation,
1290 ColPartition_LIST* big_parts) {
1291 int imageheight = pixGetHeight(image_pix);
1296 int nboxes = boxaGetCount(boxa);
1297 for (
int i = 0; i < nboxes; ++i) {
1298 l_int32 x, y, width, height;
1299 boxaGetBoxGeometry(boxa, i, &x, &y, &width, &height);
1300 Pix* pix = pixaGetPix(pixa, i, L_CLONE);
1301 TBOX im_box(x, imageheight -y - height, x + width, imageheight - y);
1305 ColPartition_LIST part_list;
1306 DivideImageIntoParts(im_box, rotation, rerotation, pix,
1307 &rectsearch, &part_list);
1309 pixWrite(
"junkimagecomponent.png", pix, IFF_PNG);
1310 tprintf(
"Component has %d parts\n", part_list.length());
1313 if (!part_list.empty()) {
1314 ColPartition_IT part_it(&part_list);
1315 if (part_list.singleton()) {
1320 TBOX text_box(im_box);
1321 MaximalImageBoundingBox(part_grid, &text_box);
1322 while (ExpandImageIntoParts(text_box, &rectsearch, part_grid, &part));
1323 part_it.set_to_list(&part_list);
1324 part_it.add_after_then_move(part);
1327 EliminateWeakParts(im_box, part_grid, big_parts, &part_list);
1329 for (part_it.move_to_first(); !part_it.empty(); part_it.forward()) {
1332 part_grid->
InsertBBox(
true,
true, image_part);
1333 if (!part_it.at_last()) {
1343 DeleteSmallImages(part_grid);
void rotate(const FCOORD &vec)
static void ConnCompAndRectangularize(Pix *pix, Boxa **boxa, Pixa **pixa)
bool overlap(const TBOX &box) const
double rms(double m, double c) const
const double kMaxRectangularGradient
GridSearch< ColPartition, ColPartition_CLIST, ColPartition_C_IT > ColPartitionGridSearch
static Pix * FindImages(Pix *pix)
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)
void add(inT32 value, inT32 count)
static uinT8 ClipToByte(double pixel)
void SetUniqueMode(bool mode)
static uinT32 ComposeRGB(uinT32 r, uinT32 g, uinT32 b)
static bool BoundsWithinRect(Pix *pix, int *x_start, int *y_start, int *x_end, int *y_end)
const double kMinRectangularFraction
void add(double x, double y)
int textord_tabfind_show_images
void DisplayBoxes(ScrollView *window)
LIST search(LIST list, void *key, int_compare is_equal)
int y_gap(const TBOX &box) const
ScrollView * MakeWindow(int x, int y, const char *window_name)
bool contains(const FCOORD pt) const
static double ColorDistanceFromLine(const uinT8 *line1, const uinT8 *line2, const uinT8 *point)
int x_gap(const TBOX &box) const
static void FindImagePartitions(Pix *image_pix, const FCOORD &rotation, const FCOORD &rerotation, TO_BLOCK *block, TabFind *tab_grid, ColPartitionGrid *part_grid, ColPartition_LIST *big_parts)
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 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)
const double kRMSFitScaling
void InsertBBox(bool h_spread, bool v_spread, BBC *bbox)
double ile(double frac) const
void AddPartner(bool upper, ColPartition *partner)
const int kMinImageFindSize
TBOX intersection(const TBOX &box) const
const int kMinColorDifference
const TBOX & bounding_box() const
BlobRegionType blob_type() const
const double kMaxRectangularFraction
static ColPartition * FakePartition(const TBOX &box, PolyBlockType block_type, BlobRegionType blob_type, BlobTextFlowType flow)
#define INT_VAR(name, val, comment)