20# include "config_auto.h"
70 gridsize, bleft, tright) {}
108 if (
MergePart(box_cb, confirm_cb, part)) {
127 bool any_done =
false;
129 bool merge_done =
false;
139 if (!box_cb(part, &box)) {
143 ColPartition_CLIST merge_candidates;
144 FindMergeCandidates(part, box, debug, &merge_candidates);
146 int overlap_increase;
148 confirm_cb, &overlap_increase);
149 if (neighbour !=
nullptr && overlap_increase <= 0) {
151 tprintf(
"Merging:hoverlap=%d, voverlap=%d, OLI=%d\n",
160 part->
Absorb(neighbour,
nullptr);
164 }
else if (neighbour !=
nullptr) {
166 tprintf(
"Overlapped when merged with increase %d: ", overlap_increase);
170 tprintf(
"No candidate neighbour returned\n");
172 }
while (merge_done);
184 if (candidate == part) {
193 tprintf(
"Examining merge candidate:");
199 if (h_dist >= std::max(part_box.
width(), c_box.width()) / 2) {
201 tprintf(
"Too far away: h_dist = %d\n", h_dist);
208 if (v_dist >= std::max(part_box.
height(), c_box.height()) / 2) {
210 tprintf(
"Too far away: v_dist = %d\n", v_dist);
220 tprintf(
"Candidate fails overlap and diacritic tests!\n");
233static int IncreaseInOverlap(
const ColPartition *merge1,
234 const ColPartition *merge2,
int ok_overlap,
235 ColPartition_CLIST *parts) {
236 ASSERT_HOST(merge1 !=
nullptr && merge2 !=
nullptr);
238 ColPartition_C_IT it(parts);
239 TBOX merged_box(merge1->bounding_box());
240 merged_box += merge2->bounding_box();
241 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
242 ColPartition *part = it.data();
243 if (part == merge1 || part == merge2) {
246 TBOX part_box = part->bounding_box();
249 if (overlap_area > 0 &&
250 !part->OKMergeOverlap(*merge1, *merge2, ok_overlap,
false)) {
251 total_area += overlap_area;
253 overlap_area = part_box.intersection(merge1->bounding_box()).area();
254 if (overlap_area > 0) {
255 total_area -= overlap_area;
257 TBOX intersection_box = part_box.intersection(merge2->bounding_box());
258 overlap_area = intersection_box.area();
259 if (overlap_area > 0) {
260 total_area -= overlap_area;
262 intersection_box &= merge1->bounding_box();
263 overlap_area = intersection_box.area();
264 if (overlap_area > 0) {
265 total_area += overlap_area;
294static bool TestCompatibleCandidates(
const ColPartition &part,
bool debug,
295 ColPartition_CLIST *candidates) {
296 ColPartition_C_IT it(candidates);
297 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
298 ColPartition *candidate = it.data();
299 if (!candidate->OKDiacriticMerge(part,
false)) {
300 ColPartition_C_IT it2(it);
301 for (it2.mark_cycle_pt(); !it2.cycled_list(); it2.forward()) {
302 ColPartition *candidate2 = it2.data();
303 if (candidate2 != candidate &&
304 !OKMergeCandidate(candidate, candidate2,
false)) {
306 tprintf(
"NC overlap failed:Candidate:");
307 candidate2->bounding_box().print();
308 tprintf(
"fails to be a good merge with:");
309 candidate->bounding_box().print();
323 int total_overlap = 0;
329 ColPartition_CLIST neighbors;
332 ColPartition_C_IT n_it(&neighbors);
333 bool any_part_overlap =
false;
334 for (n_it.mark_cycle_pt(); !n_it.cycled_list(); n_it.forward()) {
335 const TBOX &n_box = n_it.data()->bounding_box();
337 if (overlap > 0 && overlap_grid !=
nullptr) {
338 if (*overlap_grid ==
nullptr) {
341 (*overlap_grid)->InsertBBox(
true,
true, n_it.data()->ShallowCopy());
342 if (!any_part_overlap) {
343 (*overlap_grid)->InsertBBox(
true,
true, part->
ShallowCopy());
346 any_part_overlap =
true;
347 total_overlap += overlap;
350 return total_overlap;
358 ColPartition_CLIST *parts) {
363 if (part != not_this) {
364 parts->add_sorted(SortByBoxLeft<ColPartition>,
true, part);
411 const ColPartition *part, ColPartition_CLIST *candidates,
bool debug,
414 int *overlap_increase) {
415 if (overlap_increase !=
nullptr) {
416 *overlap_increase = 0;
418 if (candidates->empty()) {
428 ColPartition_C_IT it(candidates);
431 TBOX full_box(part_box);
432 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
437 ColPartition_CLIST neighbours;
442 tprintf(
"Finding best merge candidate from %d, %d neighbours for box:",
443 candidates->length(), neighbours.length());
451 ColPartition_CLIST non_candidate_neighbours;
452 non_candidate_neighbours.set_subtract(SortByBoxLeft<ColPartition>,
true,
453 &neighbours, candidates);
454 int worst_nc_increase = 0;
455 int best_increase = INT32_MAX;
457 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
459 if (confirm_cb !=
nullptr && !confirm_cb(part, candidate)) {
461 tprintf(
"Candidate not confirmed:");
466 int increase = IncreaseInOverlap(part, candidate, ok_overlap, &neighbours);
468 if (best_candidate ==
nullptr || increase < best_increase) {
469 best_candidate = candidate;
470 best_increase = increase;
473 tprintf(
"New best merge candidate has increase %d, area %d, over box:",
474 increase, best_area);
478 }
else if (increase == best_increase) {
480 if (area < best_area) {
482 best_candidate = candidate;
485 increase = IncreaseInOverlap(part, candidate, ok_overlap,
486 &non_candidate_neighbours);
487 if (increase > worst_nc_increase) {
488 worst_nc_increase = increase;
491 if (best_increase > 0) {
498 if (worst_nc_increase < best_increase &&
499 TestCompatibleCandidates(*part, debug, candidates)) {
500 best_increase = worst_nc_increase;
503 if (overlap_increase !=
nullptr) {
504 *overlap_increase = best_increase;
506 return best_candidate;
512 ColPartition_LIST *part_list) {
524 ColPartition_LIST *big_parts) {
537 int unresolved_overlaps = 0;
541 if (neighbour == part) {
546 part->
OKMergeOverlap(*neighbour, *neighbour, ok_overlap,
false)) {
557 if (!shrunken.
overlap(neighbour_box) &&
562 RemoveBadBox(excluded, part, big_parts);
567 }
else if (box.
contains(neighbour_box)) {
568 ++unresolved_overlaps;
579 RemoveBadBox(excluded, neighbour, big_parts);
588 if (neighbour_overlap_count <= part_overlap_count ||
592 if (split_blob !=
nullptr) {
601 if (split_blob !=
nullptr) {
608 if (right_part !=
nullptr) {
615 if (unresolved_overlaps > 2 && part->
IsSingleton()) {
618 ColPartition_IT big_it(big_parts);
620 big_it.add_to_end(part);
643 bool any_changed =
false;
645 if (part->
flow() != source_type ||
651 if (SmoothRegionType(nontext_map, im_box, rotation, debug, part)) {
661 ColPartition_LIST parts;
662 ColPartition_IT part_it(&parts);
668 part_it.add_after_then_move(part);
675 for (part_it.move_to_first(); !part_it.empty(); part_it.forward()) {
676 part = part_it.extract();
689 TO_BLOCK_LIST *to_blocks) {
690 TO_BLOCK_IT to_block_it(to_blocks);
691 BLOCK_IT block_it(blocks);
693 ColPartition_LIST parts;
694 ColPartition_IT part_it(&parts);
700 part_it.add_after_then_move(part);
713 if (row ==
nullptr) {
721 auto *to_block =
new TO_BLOCK(block);
722 TO_ROW_IT row_it(to_block->get_rows());
723 row_it.add_after_then_move(row);
727 to_block->line_size =
static_cast<float>(median_width);
728 to_block->line_spacing =
static_cast<float>(box.
width());
729 to_block->max_blob_size =
static_cast<float>(box.
width() + 1);
731 to_block->line_size =
static_cast<float>(median_height);
732 to_block->line_spacing =
static_cast<float>(box.
height());
733 to_block->max_blob_size =
static_cast<float>(box.
height() + 1);
735 if (to_block->line_size == 0) {
736 to_block->line_size = 1;
738 block_it.add_to_end(block);
739 to_block_it.add_to_end(to_block);
752 ColPartition_LIST parts;
753 ColPartition_IT part_it(&parts);
759 part_it.add_after_then_move(part);
767 for (part_it.move_to_first(); !part_it.empty(); part_it.forward()) {
768 part = part_it.extract();
784 if (left_line !=
nullptr && !left_line->
IsLeftTab()) {
787 if (left_line !=
nullptr && left_line->
IsLeftTab()) {
791 if (right_line !=
nullptr && !right_line->
IsRightTab()) {
794 if (right_line !=
nullptr && right_line->
IsRightTab()) {
804 auto *part_lists =
new ColPartition_LIST[
gridheight()];
811 bool any_parts_found =
false;
819 ColPartition_IT part_it(&part_lists[grid_y]);
820 part_it.add_to_end(part);
821 any_parts_found =
true;
824 if (any_parts_found) {
825 for (
int grid_y = 0; grid_y <
gridheight(); ++grid_y) {
827 if (!part_lists[grid_y].empty()) {
830 part_sets->push_back(line_set);
834 return any_parts_found;
858 if (single_column_part ==
nullptr) {
862 single_column_part->
CopyLeftTab(*single_column_part,
false);
863 single_column_part->
CopyRightTab(*single_column_part,
false);
875 if (single_column_part !=
nullptr) {
899 BLOBNBOX_IT im_blob_it(im_blobs);
900 ColPartition_LIST dead_parts;
901 ColPartition_IT dead_part_it(&dead_parts);
909 bool any_blobs_moved =
false;
911 BLOBNBOX_C_IT blob_it(part->
boxes());
912 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
914 im_blob_it.add_after_then_move(blob);
918 BLOBNBOX_C_IT blob_it(part->
boxes());
919 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
927 any_blobs_moved =
true;
937 BLOBNBOX_C_IT blob_it(part->
boxes());
939 dead_part_it.add_to_end(part);
941 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
945 delete blob->
cblob();
949 }
else if (any_blobs_moved) {
963 ColPartition_LIST saved_parts;
964 ColPartition_IT part_it(&saved_parts);
970 part_it.add_to_end(part);
975 for (part_it.move_to_first(); !part_it.empty(); part_it.forward()) {
976 part = part_it.extract();
996 best_columns !=
nullptr ? best_columns[gsearch.
GridY()] :
nullptr;
997 FindPartitionMargins(columns, part);
1000 tprintf(
"Computed margins for part:");
1012 ColPartition_LIST *parts) {
1013 ColPartition_IT part_it(parts);
1014 for (part_it.mark_cycle_pt(); !part_it.cycled_list(); part_it.forward()) {
1017 if (best_columns !=
nullptr) {
1022 columns = best_columns[grid_y];
1024 FindPartitionMargins(columns, part);
1030 ColPartition_LIST dead_parts;
1031 ColPartition_IT dead_it(&dead_parts);
1037 dead_it.add_to_end(part);
1096 for (
int upper = 0; upper < 2; ++upper) {
1100 for (partner_it.mark_cycle_pt(); !partner_it.cycled_list();
1101 partner_it.forward()) {
1107 if (!partner_it.cycled_list()) {
1111 for (partner_it.mark_cycle_pt(); !partner_it.cycled_list();
1112 partner_it.forward()) {
1119 tprintf(
"Finding figure captions for image part:");
1121 tprintf(
"Considering partner:");
1122 partner_box.
print();
1124 if (partner_box.
left() >= part_box.
left() &&
1126 int dist = partner_box.
y_gap(part_box);
1127 if (best_caption ==
nullptr || dist < best_dist) {
1129 best_caption = partner;
1135 if (best_caption !=
nullptr) {
1137 tprintf(
"Best caption candidate:");
1144 int biggest_gap = 0;
1145 int smallest_gap = INT16_MAX;
1146 int total_height = 0;
1147 int mean_height = 0;
1152 partner = next_partner) {
1153 if (!partner->IsTextType()) {
1154 end_partner = partner;
1160 if (next_partner !=
nullptr) {
1163 if (gap > biggest_gap) {
1165 end_partner = next_partner;
1166 mean_height = total_height / line_count;
1167 }
else if (gap < smallest_gap) {
1179 tprintf(
"Line count=%d, biggest gap %d, smallest%d, mean height %d\n",
1180 line_count, biggest_gap, smallest_gap, mean_height);
1181 if (end_partner !=
nullptr) {
1187 end_partner =
nullptr;
1192 partner !=
nullptr && partner != end_partner;
1193 partner = next_partner) {
1195 partner->SetBlobTypes();
1197 tprintf(
"Set caption type for partition:");
1198 partner->bounding_box().print();
1236 int height = top - bottom;
1237 int mid_y = (bottom + top) / 2;
1243 int best_dist = INT32_MAX;
1245 if (neighbour == part || neighbour->
type() ==
PT_NOISE) {
1250 int neighbour_y = (neighbour_bottom + neighbour_top) / 2;
1251 if (upper != (neighbour_y > mid_y)) {
1258 if (best_neighbour ==
nullptr) {
1259 best_neighbour = neighbour;
1263 int dist = upper ? neighbour_bottom - top : bottom - neighbour_top;
1265 if (dist < best_dist) {
1267 best_neighbour = neighbour;
1273 if (best_neighbour !=
nullptr) {
1288 int width = right >= left ? right - left : -1;
1289 int mid_x = (left + right) / 2;
1295 int best_dist = INT32_MAX;
1296 while ((neighbour = hsearch.
NextSideSearch(to_the_left)) !=
nullptr) {
1297 if (neighbour == part || neighbour->
type() ==
PT_NOISE) {
1302 int neighbour_x = (neighbour_left + neighbour_right) / 2;
1303 if (to_the_left != (neighbour_x < mid_x)) {
1312 int dist = to_the_left ? left - neighbour_right : neighbour_left - right;
1314 if (dist < best_dist || best_neighbour ==
nullptr) {
1316 best_neighbour = neighbour;
1324 if (best_neighbour !=
nullptr) {
1325 part->
AddPartner(to_the_left, best_neighbour);
1354void ColPartitionGrid::FindMergeCandidates(
const ColPartition *part,
1355 const TBOX &search_box,
bool debug,
1356 ColPartition_CLIST *candidates) {
1362 rsearch.SetUniqueMode(
true);
1363 rsearch.StartRectSearch(search_box);
1365 while ((candidate = rsearch.NextRectSearch()) !=
nullptr) {
1366 if (!OKMergeCandidate(part, candidate, debug)) {
1373 if (!part_box.
contains(c_box) && !c_box.contains(part_box)) {
1384 TBOX merged_box(part_box);
1385 merged_box += c_box;
1387 msearch.SetUniqueMode(
true);
1388 msearch.StartRectSearch(merged_box);
1389 ColPartition *neighbour;
1390 while ((neighbour = msearch.NextRectSearch()) !=
nullptr) {
1391 if (neighbour == part || neighbour == candidate) {
1394 if (neighbour->OKMergeOverlap(*part, *candidate, ok_overlap,
false)) {
1397 TBOX n_box = neighbour->bounding_box();
1401 if (!n_box.overlap(part_box) && !n_box.overlap(c_box) &&
1402 !OKMergeCandidate(part, neighbour,
false) &&
1403 !OKMergeCandidate(candidate, neighbour,
false)) {
1407 if (neighbour !=
nullptr) {
1410 "Combined box overlaps another that is not OK despite"
1411 " allowance of %d:",
1413 neighbour->bounding_box().print();
1415 OKMergeCandidate(part, neighbour,
true);
1417 OKMergeCandidate(candidate, neighbour,
true);
1419 neighbour->OKMergeOverlap(*part, *candidate, ok_overlap,
true);
1429 candidates->add_sorted(SortByBoxLeft<ColPartition>,
true, candidate);
1444bool ColPartitionGrid::SmoothRegionType(Image nontext_map,
const TBOX &im_box,
1445 const FCOORD &rerotation,
bool debug,
1446 ColPartition *part) {
1447 const TBOX &part_box = part->bounding_box();
1449 tprintf(
"Smooothing part at:");
1453 int best_dist = INT32_MAX;
1454 int max_dist = std::min(part_box.width(), part_box.height());
1457 bool any_image =
false;
1458 bool all_image =
true;
1463 rerotation, debug, *part, &dist);
1465 tprintf(
"Result in dir %d = %d at dist %d\n", dir,
type, dist);
1477 if (best_dist > max_dist) {
1485 if (best_type ==
BRT_TEXT && !any_image) {
1495 if (new_type != part->blob_type() || new_flow != part->flow()) {
1496 part->set_flow(new_flow);
1497 part->set_blob_type(new_type);
1498 part->SetBlobTypes();
1513 const TBOX &part_box,
int min_padding,
1514 TBOX *search_box, ICOORD *dist_scaling) {
1515 *search_box = part_box;
1518 int padding = std::min(part_box.height(), part_box.width());
1519 padding = std::max(padding, min_padding);
1521 search_box->pad(padding, padding);
1524 switch (direction) {
1526 search_box->set_left(part_box.left());
1527 *dist_scaling = ICOORD(2, 1);
1530 search_box->set_bottom(part_box.bottom());
1531 *dist_scaling = ICOORD(1, 2);
1534 search_box->set_right(part_box.right());
1535 *dist_scaling = ICOORD(2, 1);
1538 search_box->set_top(part_box.top());
1539 *dist_scaling = ICOORD(1, 2);
1567 const FCOORD &rerotation,
bool debug,
const ColPartition &part,
1568 int *best_distance) {
1570 const TBOX &part_box = part.bounding_box();
1572 ICOORD dist_scaling;
1573 ComputeSearchBoxAndScaling(direction, part_box,
gridsize(), &search_box,
1576 search_box, im_box, rerotation, nontext_map) > 0;
1578 AccumulatePartDistances(part, dist_scaling, search_box, nontext_map, im_box,
1579 rerotation, debug, dists);
1584 memset(counts, 0,
sizeof(counts));
1592 min_dist = INT32_MAX;
1594 if (counts[
i] < dists[
i].size() && dists[
i][counts[
i]] < min_dist) {
1595 min_dist = dists[
i][counts[
i]];
1600 while (counts[
i] < dists[
i].size() && dists[
i][counts[
i]] <= min_dist) {
1604 *best_distance = min_dist;
1606 tprintf(
"Totals: htext=%u+%u, vtext=%u+%u, image=%u+%u, at dist=%d\n",
1638 }
while (min_dist < INT32_MAX);
1649void ColPartitionGrid::AccumulatePartDistances(
1650 const ColPartition &base_part,
const ICOORD &dist_scaling,
1651 const TBOX &search_box, Image nontext_map,
const TBOX &im_box,
1652 const FCOORD &rerotation,
bool debug, std::vector<int> *dists) {
1653 const TBOX &part_box = base_part.bounding_box();
1655 rsearch.SetUniqueMode(
true);
1656 rsearch.StartRectSearch(search_box);
1657 ColPartition *neighbour;
1660 while ((neighbour = rsearch.NextRectSearch()) !=
nullptr) {
1661 if (neighbour->IsUnMergeableType() ||
1662 !base_part.ConfirmNoTabViolation(*neighbour) ||
1663 neighbour == &base_part) {
1666 TBOX nbox = neighbour->bounding_box();
1676 int x_gap = std::max(part_box.x_gap(nbox), 0);
1677 int y_gap = std::max(part_box.y_gap(nbox), 0);
1678 int n_dist = x_gap * dist_scaling.x() + y_gap * dist_scaling.y();
1680 tprintf(
"Part has x-gap=%d, y=%d, dist=%d at:", x_gap, y_gap, n_dist);
1686 std::vector<int> *count_vector =
nullptr;
1705 tprintf(
"Weak %d\n", n_boxes);
1710 tprintf(
"Image %d\n", n_boxes);
1713 if (count_vector !=
nullptr) {
1714 for (
int i = 0;
i < n_boxes; ++
i) {
1715 count_vector->push_back(n_dist);
1723 std::sort(dists[
i].begin(), dists[
i].end());
1731void ColPartitionGrid::FindPartitionMargins(ColPartitionSet *columns,
1732 ColPartition *part) {
1735 int y = part->MidY();
1737 int left_margin =
bleft().
x();
1738 int right_margin =
tright().
x();
1739 if (columns !=
nullptr) {
1740 ColPartition *column = columns->ColumnContaining(box.left(),
y);
1741 if (column !=
nullptr) {
1742 left_margin = column->LeftAtY(
y);
1744 column = columns->ColumnContaining(box.right(),
y);
1745 if (column !=
nullptr) {
1746 right_margin = column->RightAtY(
y);
1752 left_margin = FindMargin(box.left() + box.height(),
true, left_margin,
1753 box.bottom(), box.top(), part);
1754 part->set_left_margin(left_margin);
1756 right_margin = FindMargin(box.right() - box.height(),
false, right_margin,
1757 box.bottom(), box.top(), part);
1758 part->set_right_margin(right_margin);
1764int ColPartitionGrid::FindMargin(
int x,
bool right_to_left,
int x_limit,
1765 int y_bottom,
int y_top,
1766 const ColPartition *not_this) {
1767 int height = y_top - y_bottom;
1770 side_search.SetUniqueMode(
true);
1771 side_search.StartSideSearch(
x, y_bottom, y_top);
1773 while ((part = side_search.NextSideSearch(right_to_left)) !=
nullptr) {
1775 if (part == not_this) {
1780 TBOX box = part->bounding_box();
1781 int min_overlap = std::min(height,
static_cast<int>(box.height()));
1783 int y_overlap = std::min(y_top,
static_cast<int>(box.top())) -
1784 std::max(y_bottom,
static_cast<int>(box.bottom()));
1785 if (y_overlap < min_overlap) {
1789 int x_edge = right_to_left ? box.right() : box.left();
1790 if ((x_edge <
x) != right_to_left) {
1794 if ((x_edge < x_limit) == right_to_left) {
const double kMaxPartitionSpacing
const int kSmoothDecisionMargin
const int kColumnWidthFactor
const int kMaxCaptionLines
const double kTinyEnoughTextlineOverlapFraction
const double kMinCaptionGapHeightRatio
void tprintf(const char *format,...)
const double kBigPartSizeRatio
std::function< bool(int)> WidthCallback
GridSearch< ColPartition, ColPartition_CLIST, ColPartition_C_IT > ColPartitionGridSearch
std::vector< ColPartitionSet * > PartSetVector
const double kMarginOverlapFraction
const int kMaxNeighbourDistFactor
const double kMinCaptionGapRatio
const TBOX & bounding_box() const
static bool IsTextType(BlobRegionType type)
BlobRegionType region_type() const
void set_flow(BlobTextFlowType value)
static bool IsLineType(BlobRegionType type)
void set_owner(tesseract::ColPartition *new_owner)
BlobTextFlowType flow() const
void set_region_type(BlobRegionType new_type)
void DeleteUnownedNoise()
TDimension x() const
access function
int y_gap(const TBOX &box) const
TDimension height() const
const ICOORD & botleft() const
TBOX bounding_union(const TBOX &box) const
TBOX intersection(const TBOX &box) const
void rotate_large(const FCOORD &vec)
const ICOORD & topright() const
bool overlap(const TBOX &box) const
TDimension bottom() const
bool contains(const FCOORD pt) const
static bool WithinTestRegion(int detail_level, int x, int y)
void StartVerticalSearch(int xmin, int xmax, int y)
void StartRadSearch(int x, int y, int max_radius)
void SetUniqueMode(bool mode)
BBC * NextSideSearch(bool right_to_left)
void StartSideSearch(int x, int ymin, int ymax)
BBC * NextVerticalSearch(bool top_to_bottom)
void RepositionIterator()
void StartRectSearch(const TBOX &rect)
const ICOORD & bleft() const
void GridCoords(int x, int y, int *grid_x, int *grid_y) const
const ICOORD & tright() const
void Init(int gridsize, const ICOORD &bleft, const ICOORD &tright)
void InsertBBox(bool h_spread, bool v_spread, ColPartition *bbox)
virtual void HandleClick(int x, int y)
void RemoveBBox(ColPartition *bbox)
bool ReleaseNonLeaderBoxes()
BlobTextFlowType flow() const
TBOX BoundsWithoutBox(BLOBNBOX *box)
bool TypesMatch(const ColPartition &other) const
PolyBlockType type() const
static ColPartition * MakeBigPartition(BLOBNBOX *box, ColPartition_LIST *big_part_list)
void SetColumnGoodness(const WidthCallback &cb)
void RefinePartners(PolyBlockType type, bool get_desperate, ColPartitionGrid *grid)
ColPartition_CLIST * upper_partners()
int median_bottom() const
void SetRightTab(const TabVector *tab_vector)
bool VOverlaps(const ColPartition &other) const
bool VSignificantCoreOverlap(const ColPartition &other) const
BlobRegionType blob_type() const
BLOBNBOX * OverlapSplitBlob(const TBOX &box)
void set_blob_type(BlobRegionType t)
int VCoreOverlap(const ColPartition &other) const
const TBOX & bounding_box() const
int HCoreOverlap(const ColPartition &other) const
bool IsVerticalType() const
void SetLeftTab(const TabVector *tab_vector)
bool HOverlaps(const ColPartition &other) const
int CountOverlappingBoxes(const TBOX &box)
void set_vertical(const ICOORD &v)
bool OKDiacriticMerge(const ColPartition &candidate, bool debug) const
bool OKMergeOverlap(const ColPartition &merge1, const ColPartition &merge2, int ok_box_overlap, bool debug)
bool WithinSameMargins(const ColPartition &other) const
void set_type(PolyBlockType t)
ColPartition * ShallowCopy() const
void CopyRightTab(const ColPartition &src, bool take_box)
ColPartition * SplitAtBlob(BLOBNBOX *split_blob)
ColPartition * SingletonPartner(bool upper)
ColPartition_CLIST * lower_partners()
bool IsUnMergeableType() const
void Absorb(ColPartition *other, const WidthCallback &cb)
void set_block_owned(bool owned)
void RemoveBox(BLOBNBOX *box)
void AddPartner(bool upper, ColPartition *partner)
int median_height() const
void set_flow(BlobTextFlowType f)
void CopyLeftTab(const ColPartition &src, bool take_box)
ColPartitionGrid()=default
void FindVPartitionPartners(bool to_the_left, ColPartition *part)
void Merges(const std::function< bool(ColPartition *, TBOX *)> &box_cb, const std::function< bool(const ColPartition *, const ColPartition *)> &confirm_cb)
void ExtractPartitionsAsBlocks(BLOCK_LIST *blocks, TO_BLOCK_LIST *to_blocks)
void SetTabStops(TabFind *tabgrid)
void RefinePartitionPartners(bool get_desperate)
void RecomputeBounds(int gridsize, const ICOORD &bleft, const ICOORD &tright, const ICOORD &vertical)
int ComputeTotalOverlap(ColPartitionGrid **overlap_grid)
void GridFindMargins(ColPartitionSet **best_columns)
bool MakeColPartSets(PartSetVector *part_sets)
void FindPartitionPartners()
void SplitOverlappingPartitions(ColPartition_LIST *big_parts)
void HandleClick(int x, int y) override
void DeleteUnknownParts(TO_BLOCK *block)
bool MergePart(const std::function< bool(ColPartition *, TBOX *)> &box_cb, const std::function< bool(const ColPartition *, const ColPartition *)> &confirm_cb, ColPartition *part)
bool GridSmoothNeighbours(BlobTextFlowType source_type, Image nontext_map, const TBOX &im_box, const FCOORD &rerotation)
void FindOverlappingPartitions(const TBOX &box, const ColPartition *not_this, ColPartition_CLIST *parts)
ColPartitionSet * MakeSingleColumnSet(WidthCallback cb)
void Deskew(const FCOORD &deskew)
ColPartition * BestMergeCandidate(const ColPartition *part, ColPartition_CLIST *candidates, bool debug, const std::function< bool(const ColPartition *, const ColPartition *)> &confirm_cb, int *overlap_increase)
void FindFigureCaptions()
void ReTypeBlobs(BLOBNBOX_LIST *im_blobs)
void DeleteNonLeaderParts()
void ListFindMargins(ColPartitionSet **best_columns, ColPartition_LIST *parts)
static bool BlankImageInBetween(const TBOX &box1, const TBOX &box2, const TBOX &im_box, const FCOORD &rotation, Image pix)
static int CountPixelsInRotatedBox(TBOX box, const TBOX &im_box, const FCOORD &rotation, Image pix)
TabVector * RightTabForBox(const TBOX &box, bool crossing, bool extended)
TabVector * LeftTabForBox(const TBOX &box, bool crossing, bool extended)