20#include "config_auto.h"
127 bool any_done =
false;
129 bool merge_done =
false;
139 if (!box_cb->
Run(part, &box))
142 ColPartition_CLIST merge_candidates;
143 FindMergeCandidates(part, box, debug, &merge_candidates);
145 int 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);
185 if (candidate == part)
192 tprintf(
"Examining merge candidate:");
198 if (h_dist >= std::max(part_box.
width(), c_box.
width()) / 2) {
200 tprintf(
"Too far away: h_dist = %d\n", h_dist);
206 if (v_dist >= std::max(part_box.
height(), c_box.
height()) / 2) {
208 tprintf(
"Too far away: v_dist = %d\n", v_dist);
217 tprintf(
"Candidate fails overlap and diacritic tests!\n");
229static int IncreaseInOverlap(
const ColPartition* merge1,
230 const ColPartition* merge2,
232 ColPartition_CLIST* parts) {
233 ASSERT_HOST(merge1 !=
nullptr && merge2 !=
nullptr);
235 ColPartition_C_IT it(parts);
236 TBOX merged_box(merge1->bounding_box());
237 merged_box += merge2->bounding_box();
238 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
239 ColPartition* part = it.data();
240 if (part == merge1 || part == merge2)
242 TBOX part_box = part->bounding_box();
245 if (overlap_area > 0 && !part->OKMergeOverlap(*merge1, *merge2,
246 ok_overlap,
false)) {
247 total_area += overlap_area;
250 if (overlap_area > 0)
251 total_area -= overlap_area;
253 overlap_area = intersection_box.
area();
254 if (overlap_area > 0) {
255 total_area -= overlap_area;
257 intersection_box &= merge1->bounding_box();
258 overlap_area = intersection_box.
area();
259 if (overlap_area > 0)
260 total_area += overlap_area;
288static bool TestCompatibleCandidates(
const ColPartition& part,
bool debug,
289 ColPartition_CLIST* candidates) {
290 ColPartition_C_IT it(candidates);
291 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
292 ColPartition* candidate = it.data();
293 if (!candidate->OKDiacriticMerge(part,
false)) {
294 ColPartition_C_IT it2(it);
295 for (it2.mark_cycle_pt(); !it2.cycled_list(); it2.forward()) {
296 ColPartition* candidate2 = it2.data();
297 if (candidate2 != candidate &&
298 !OKMergeCandidate(candidate, candidate2,
false)) {
300 tprintf(
"NC overlap failed:Candidate:");
301 candidate2->bounding_box().print();
302 tprintf(
"fails to be a good merge with:");
303 candidate->bounding_box().print();
317 int total_overlap = 0;
323 ColPartition_CLIST neighbors;
326 ColPartition_C_IT n_it(&neighbors);
327 bool any_part_overlap =
false;
328 for (n_it.mark_cycle_pt(); !n_it.cycled_list(); n_it.forward()) {
329 const TBOX& n_box = n_it.data()->bounding_box();
331 if (overlap > 0 && overlap_grid !=
nullptr) {
332 if (*overlap_grid ==
nullptr) {
335 (*overlap_grid)->InsertBBox(
true,
true, n_it.data()->ShallowCopy());
336 if (!any_part_overlap) {
337 (*overlap_grid)->InsertBBox(
true,
true, part->
ShallowCopy());
340 any_part_overlap =
true;
341 total_overlap += overlap;
344 return total_overlap;
352 ColPartition_CLIST* parts) {
357 if (part != not_this)
358 parts->add_sorted(SortByBoxLeft<ColPartition>,
true, part);
404 const ColPartition* part, ColPartition_CLIST* candidates,
bool debug,
406 int* overlap_increase) {
407 if (overlap_increase !=
nullptr)
408 *overlap_increase = 0;
409 if (candidates->empty())
418 ColPartition_C_IT it(candidates);
421 TBOX full_box(part_box);
422 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
427 ColPartition_CLIST neighbours;
432 tprintf(
"Finding best merge candidate from %d, %d neighbours for box:",
433 candidates->length(), neighbours.length());
441 ColPartition_CLIST non_candidate_neighbours;
442 non_candidate_neighbours.set_subtract(SortByBoxLeft<ColPartition>,
true,
443 &neighbours, candidates);
444 int worst_nc_increase = 0;
445 int best_increase = INT32_MAX;
447 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
449 if (confirm_cb !=
nullptr && !confirm_cb->
Run(part, candidate)) {
451 tprintf(
"Candidate not confirmed:");
456 int increase = IncreaseInOverlap(part, candidate, ok_overlap, &neighbours);
458 if (best_candidate ==
nullptr || increase < best_increase) {
459 best_candidate = candidate;
460 best_increase = increase;
463 tprintf(
"New best merge candidate has increase %d, area %d, over box:",
464 increase, best_area);
468 }
else if (increase == best_increase) {
470 if (area < best_area) {
472 best_candidate = candidate;
475 increase = IncreaseInOverlap(part, candidate, ok_overlap,
476 &non_candidate_neighbours);
477 if (increase > worst_nc_increase)
478 worst_nc_increase = increase;
480 if (best_increase > 0) {
487 if (worst_nc_increase < best_increase &&
488 TestCompatibleCandidates(*part, debug, candidates)) {
489 best_increase = worst_nc_increase;
492 if (overlap_increase !=
nullptr)
493 *overlap_increase = best_increase;
494 return best_candidate;
500 ColPartition_LIST* part_list) {
513 ColPartition_LIST* big_parts) {
526 int unresolved_overlaps = 0;
530 if (neighbour == part)
544 if (!shrunken.
overlap(neighbour_box) &&
549 RemoveBadBox(excluded, part, big_parts);
554 }
else if (box.
contains(neighbour_box)) {
555 ++unresolved_overlaps;
566 RemoveBadBox(excluded, neighbour, big_parts);
575 if (neighbour_overlap_count <= part_overlap_count ||
579 if (split_blob !=
nullptr) {
588 if (split_blob !=
nullptr) {
595 if (right_part !=
nullptr) {
602 if (unresolved_overlaps > 2 && part->
IsSingleton()) {
605 ColPartition_IT big_it(big_parts);
607 big_it.add_to_end(part);
630 bool any_changed =
false;
636 if (SmoothRegionType(nontext_map, im_box, rotation, debug, part))
645 ColPartition_LIST parts;
646 ColPartition_IT part_it(&parts);
652 part_it.add_after_then_move(part);
659 for (part_it.move_to_first(); !part_it.empty(); part_it.forward()) {
660 part = part_it.extract();
673 TO_BLOCK_LIST* to_blocks) {
674 TO_BLOCK_IT to_block_it(to_blocks);
675 BLOCK_IT block_it(blocks);
677 ColPartition_LIST parts;
678 ColPartition_IT part_it(&parts);
684 part_it.add_after_then_move(part);
697 if (row ==
nullptr) {
704 block->pdblk.set_poly_block(
new POLY_BLOCK(box, type));
705 auto* to_block =
new TO_BLOCK(block);
706 TO_ROW_IT row_it(to_block->get_rows());
707 row_it.add_after_then_move(row);
711 to_block->line_size =
static_cast<float>(median_width);
712 to_block->line_spacing =
static_cast<float>(box.
width());
713 to_block->max_blob_size =
static_cast<float>(box.
width() + 1);
715 to_block->line_size =
static_cast<float>(median_height);
716 to_block->line_spacing =
static_cast<float>(box.
height());
717 to_block->max_blob_size =
static_cast<float>(box.
height() + 1);
719 if (to_block->line_size == 0) to_block->line_size = 1;
720 block_it.add_to_end(block);
721 to_block_it.add_to_end(to_block);
734 ColPartition_LIST parts;
735 ColPartition_IT part_it(&parts);
741 part_it.add_after_then_move(part);
749 for (part_it.move_to_first(); !part_it.empty(); part_it.forward()) {
750 part = part_it.extract();
766 if (left_line !=
nullptr && !left_line->
IsLeftTab())
768 if (left_line !=
nullptr && left_line->
IsLeftTab())
771 if (right_line !=
nullptr && !right_line->
IsRightTab())
773 if (right_line !=
nullptr && right_line->
IsRightTab())
782 auto* part_lists =
new ColPartition_LIST[
gridheight()];
789 bool any_parts_found =
false;
797 ColPartition_IT part_it(&part_lists[grid_y]);
798 part_it.add_to_end(part);
799 any_parts_found =
true;
802 if (any_parts_found) {
803 for (
int grid_y = 0; grid_y <
gridheight(); ++grid_y) {
805 if (!part_lists[grid_y].empty()) {
811 delete [] part_lists;
812 return any_parts_found;
836 if (single_column_part ==
nullptr) {
840 single_column_part->
CopyLeftTab(*single_column_part,
false);
841 single_column_part->
CopyRightTab(*single_column_part,
false);
851 if (single_column_part !=
nullptr) {
875 BLOBNBOX_IT im_blob_it(im_blobs);
876 ColPartition_LIST dead_parts;
877 ColPartition_IT dead_part_it(&dead_parts);
885 bool any_blobs_moved =
false;
887 BLOBNBOX_C_IT blob_it(part->
boxes());
888 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
890 im_blob_it.add_after_then_move(blob);
894 BLOBNBOX_C_IT blob_it(part->
boxes());
895 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
903 any_blobs_moved =
true;
912 BLOBNBOX_C_IT blob_it(part->
boxes());
914 dead_part_it.add_to_end(part);
916 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
920 delete blob->
cblob();
924 }
else if (any_blobs_moved) {
939 ColPartition_LIST saved_parts;
940 ColPartition_IT part_it(&saved_parts);
946 part_it.add_to_end(part);
951 for (part_it.move_to_first(); !part_it.empty(); part_it.forward()) {
952 part = part_it.extract();
972 ? best_columns[gsearch.
GridY()]
974 FindPartitionMargins(columns, part);
977 tprintf(
"Computed margins for part:");
989 ColPartition_LIST* parts) {
990 ColPartition_IT part_it(parts);
991 for (part_it.mark_cycle_pt(); !part_it.cycled_list(); part_it.forward()) {
994 if (best_columns !=
nullptr) {
999 columns = best_columns[grid_y];
1001 FindPartitionMargins(columns, part);
1007 ColPartition_LIST dead_parts;
1008 ColPartition_IT dead_it(&dead_parts);
1014 dead_it.add_to_end(part);
1073 for (
int upper = 0; upper < 2; ++upper) {
1077 for (partner_it.mark_cycle_pt(); !partner_it.cycled_list();
1078 partner_it.forward()) {
1084 if (!partner_it.cycled_list())
continue;
1086 for (partner_it.mark_cycle_pt(); !partner_it.cycled_list();
1087 partner_it.forward()) {
1092 tprintf(
"Finding figure captions for image part:");
1094 tprintf(
"Considering partner:");
1095 partner_box.
print();
1097 if (partner_box.
left() >= part_box.
left() &&
1099 int dist = partner_box.
y_gap(part_box);
1100 if (best_caption ==
nullptr || dist < best_dist) {
1102 best_caption = partner;
1108 if (best_caption !=
nullptr) {
1110 tprintf(
"Best caption candidate:");
1117 int biggest_gap = 0;
1118 int smallest_gap = INT16_MAX;
1119 int total_height = 0;
1120 int mean_height = 0;
1123 for (
ColPartition* partner = best_caption; partner !=
nullptr &&
1125 partner = next_partner) {
1126 if (!partner->IsTextType()) {
1127 end_partner = partner;
1133 if (next_partner !=
nullptr) {
1136 if (gap > biggest_gap) {
1138 end_partner = next_partner;
1139 mean_height = total_height / line_count;
1140 }
else if (gap < smallest_gap) {
1151 tprintf(
"Line count=%d, biggest gap %d, smallest%d, mean height %d\n",
1152 line_count, biggest_gap, smallest_gap, mean_height);
1153 if (end_partner !=
nullptr) {
1159 end_partner =
nullptr;
1162 for (
ColPartition* partner = best_caption; partner !=
nullptr &&
1163 partner != end_partner;
1164 partner = next_partner) {
1166 partner->SetBlobTypes();
1168 tprintf(
"Set caption type for partition:");
1169 partner->bounding_box().print();
1206 int height = top - bottom;
1207 int mid_y = (bottom + top) / 2;
1213 int best_dist = INT32_MAX;
1215 if (neighbour == part || neighbour->
type() ==
PT_NOISE)
1219 int neighbour_y = (neighbour_bottom + neighbour_top) / 2;
1220 if (upper != (neighbour_y > mid_y))
1225 if (best_neighbour ==
nullptr)
1226 best_neighbour = neighbour;
1229 int dist = upper ? neighbour_bottom - top : bottom - neighbour_top;
1231 if (dist < best_dist) {
1233 best_neighbour = neighbour;
1239 if (best_neighbour !=
nullptr)
1252 int width = right >= left ? right - left : -1;
1253 int mid_x = (left + right) / 2;
1259 int best_dist = INT32_MAX;
1260 while ((neighbour = hsearch.
NextSideSearch(to_the_left)) !=
nullptr) {
1261 if (neighbour == part || neighbour->
type() ==
PT_NOISE)
1265 int neighbour_x = (neighbour_left + neighbour_right) / 2;
1266 if (to_the_left != (neighbour_x < mid_x))
1272 int dist = to_the_left ? left - neighbour_right : neighbour_left - right;
1274 if (dist < best_dist || best_neighbour ==
nullptr) {
1276 best_neighbour = neighbour;
1284 if (best_neighbour !=
nullptr)
1285 part->
AddPartner(to_the_left, best_neighbour);
1301 get_desperate,
this);
1314void ColPartitionGrid::FindMergeCandidates(
const ColPartition* part,
1315 const TBOX& search_box,
bool debug,
1316 ColPartition_CLIST* candidates) {
1322 rsearch.SetUniqueMode(
true);
1323 rsearch.StartRectSearch(search_box);
1325 while ((candidate = rsearch.NextRectSearch()) !=
nullptr) {
1326 if (!OKMergeCandidate(part, candidate, debug))
1343 TBOX merged_box(part_box);
1344 merged_box += c_box;
1346 msearch.SetUniqueMode(
true);
1347 msearch.StartRectSearch(merged_box);
1349 while ((neighbour = msearch.NextRectSearch()) !=
nullptr) {
1350 if (neighbour == part || neighbour == candidate)
1352 if (neighbour->
OKMergeOverlap(*part, *candidate, ok_overlap,
false))
1359 !OKMergeCandidate(part, neighbour,
false) &&
1360 !OKMergeCandidate(candidate, neighbour,
false))
1363 if (neighbour !=
nullptr) {
1365 tprintf(
"Combined box overlaps another that is not OK despite"
1366 " allowance of %d:", ok_overlap);
1369 OKMergeCandidate(part, neighbour,
true);
1371 OKMergeCandidate(candidate, neighbour,
true);
1383 candidates->add_sorted(SortByBoxLeft<ColPartition>,
true, candidate);
1398bool ColPartitionGrid::SmoothRegionType(Pix* nontext_map,
1400 const FCOORD& rerotation,
1402 ColPartition* part) {
1403 const TBOX& part_box = part->bounding_box();
1405 tprintf(
"Smooothing part at:");
1409 int best_dist = INT32_MAX;
1410 int max_dist = std::min(part_box.
width(), part_box.
height());
1413 bool any_image =
false;
1414 bool all_image =
true;
1419 rerotation, debug, *part,
1422 tprintf(
"Result in dir %d = %d at dist %d\n", dir, type, dist);
1433 if (best_dist > max_dist)
1440 if (best_type ==
BRT_TEXT && !any_image) {
1450 if (new_type != part->blob_type() || new_flow != part->flow()) {
1451 part->set_flow(new_flow);
1452 part->set_blob_type(new_type);
1453 part->SetBlobTypes();
1468 const TBOX& part_box,
1472 *search_box = part_box;
1475 int padding = std::min(part_box.
height(), part_box.
width());
1476 padding = std::max(padding, min_padding);
1478 search_box->
pad(padding, padding);
1481 switch (direction) {
1484 *dist_scaling =
ICOORD(2, 1);
1488 *dist_scaling =
ICOORD(1, 2);
1492 *dist_scaling =
ICOORD(2, 1);
1496 *dist_scaling =
ICOORD(1, 2);
1524 const TBOX& im_box,
const FCOORD& rerotation,
1525 bool debug,
const ColPartition& part,
int* best_distance) {
1527 const TBOX& part_box = part.bounding_box();
1530 ComputeSearchBoxAndScaling(direction, part_box,
gridsize(),
1531 &search_box, &dist_scaling);
1536 AccumulatePartDistances(part, dist_scaling, search_box,
1537 nontext_map, im_box, rerotation, debug, dists);
1542 memset(counts, 0,
sizeof(counts[0]) *
NPT_COUNT);
1550 min_dist = INT32_MAX;
1552 if (counts[i] < dists[i].size() && dists[i][counts[i]] < min_dist)
1553 min_dist = dists[i][counts[i]];
1557 while (counts[i] < dists[i].size() && dists[i][counts[i]] <= min_dist)
1560 *best_distance = min_dist;
1562 tprintf(
"Totals: htext=%d+%d, vtext=%d+%d, image=%d+%d, at dist=%d\n",
1565 counts[
NPT_IMAGE], image_bias, min_dist);
1573 if (image_count > 0 &&
1594 }
while (min_dist < INT32_MAX);
1605void ColPartitionGrid::AccumulatePartDistances(
const ColPartition& base_part,
1606 const ICOORD& dist_scaling,
1607 const TBOX& search_box,
1610 const FCOORD& rerotation,
1613 const TBOX& part_box = base_part.bounding_box();
1615 rsearch.SetUniqueMode(
true);
1616 rsearch.StartRectSearch(search_box);
1617 ColPartition* neighbour;
1620 while ((neighbour = rsearch.NextRectSearch()) !=
nullptr) {
1621 if (neighbour->IsUnMergeableType() ||
1622 !base_part.ConfirmNoTabViolation(*neighbour) ||
1623 neighbour == &base_part)
1625 TBOX nbox = neighbour->bounding_box();
1633 int x_gap = std::max(part_box.
x_gap(nbox), 0);
1634 int y_gap = std::max(part_box.
y_gap(nbox), 0);
1635 int n_dist = x_gap * dist_scaling.
x() + y_gap* dist_scaling.
y();
1637 tprintf(
"Part has x-gap=%d, y=%d, dist=%d at:",
1638 x_gap, y_gap, n_dist);
1660 if (debug)
tprintf(
"Weak %d\n", n_boxes);
1663 if (debug)
tprintf(
"Image %d\n", n_boxes);
1665 if (count_vector !=
nullptr) {
1666 for (
int i = 0; i < n_boxes; ++i)
1681void ColPartitionGrid::FindPartitionMargins(ColPartitionSet* columns,
1682 ColPartition* part) {
1685 int y = part->MidY();
1687 int left_margin =
bleft().
x();
1688 int right_margin =
tright().
x();
1689 if (columns !=
nullptr) {
1690 ColPartition* column = columns->ColumnContaining(box.
left(), y);
1691 if (column !=
nullptr)
1692 left_margin = column->LeftAtY(y);
1693 column = columns->ColumnContaining(box.
right(), y);
1694 if (column !=
nullptr)
1695 right_margin = column->RightAtY(y);
1700 left_margin = FindMargin(box.
left() + box.
height(),
true, left_margin,
1702 part->set_left_margin(left_margin);
1704 right_margin = FindMargin(box.
right() - box.
height(),
false, right_margin,
1706 part->set_right_margin(right_margin);
1712int ColPartitionGrid::FindMargin(
int x,
bool right_to_left,
int x_limit,
1713 int y_bottom,
int y_top,
1714 const ColPartition* not_this) {
1715 int height = y_top - y_bottom;
1718 side_search.SetUniqueMode(
true);
1719 side_search.StartSideSearch(x, y_bottom, y_top);
1721 while ((part = side_search.NextSideSearch(right_to_left)) !=
nullptr) {
1723 if (part == not_this)
1727 TBOX box = part->bounding_box();
1728 int min_overlap = std::min(height,
static_cast<int>(box.
height()));
1730 int y_overlap = std::min(y_top,
static_cast<int>(box.
top())) - std::max(y_bottom,
static_cast<int>(box.
bottom()));
1731 if (y_overlap < min_overlap)
1734 int x_edge = right_to_left ? box.
right() : box.
left();
1735 if ((x_edge < x) != right_to_left)
1738 if ((x_edge < x_limit) == right_to_left)
DLLSYM void tprintf(const char *format,...)
const double kMaxPartitionSpacing
const int kSmoothDecisionMargin
const int kColumnWidthFactor
const int kMaxCaptionLines
const double kTinyEnoughTextlineOverlapFraction
const double kMinCaptionGapHeightRatio
const double kBigPartSizeRatio
GridSearch< ColPartition, ColPartition_CLIST, ColPartition_C_IT > ColPartitionGridSearch
const double kMarginOverlapFraction
const int kMaxNeighbourDistFactor
const double kMinCaptionGapRatio
static bool IsTextType(BlobRegionType type)
BlobRegionType region_type() const
void set_flow(BlobTextFlowType value)
static bool IsLineType(BlobRegionType type)
void set_region_type(BlobRegionType new_type)
const TBOX & bounding_box() const
BlobTextFlowType flow() const
void set_owner(tesseract::ColPartition *new_owner)
void DeleteUnownedNoise()
int16_t y() const
access_function
int16_t x() const
access function
const ICOORD & botleft() const
void rotate_large(const FCOORD &vec)
bool overlap(const TBOX &box) const
int y_gap(const TBOX &box) const
TBOX bounding_union(const TBOX &box) const
TBOX intersection(const TBOX &box) const
bool contains(const FCOORD pt) const
void pad(int xpad, int ypad)
const ICOORD & topright() const
int x_gap(const TBOX &box) 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)
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 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)
void SetColumnGoodness(WidthCallback *cb)
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 set_block_owned(bool owned)
void Absorb(ColPartition *other, WidthCallback *cb)
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)
ColPartition * BestMergeCandidate(const ColPartition *part, ColPartition_CLIST *candidates, bool debug, TessResultCallback2< bool, const ColPartition *, const ColPartition * > *confirm_cb, int *overlap_increase)
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)
void Merges(TessResultCallback2< bool, ColPartition *, TBOX * > *box_cb, TessResultCallback2< bool, const ColPartition *, const ColPartition * > *confirm_cb)
int ComputeTotalOverlap(ColPartitionGrid **overlap_grid)
void GridFindMargins(ColPartitionSet **best_columns)
bool MakeColPartSets(PartSetVector *part_sets)
void FindPartitionPartners()
ColPartitionSet * MakeSingleColumnSet(WidthCallback *cb)
void SplitOverlappingPartitions(ColPartition_LIST *big_parts)
bool GridSmoothNeighbours(BlobTextFlowType source_type, Pix *nontext_map, const TBOX &im_box, const FCOORD &rerotation)
bool MergePart(TessResultCallback2< bool, ColPartition *, TBOX * > *box_cb, TessResultCallback2< bool, const ColPartition *, const ColPartition * > *confirm_cb, ColPartition *part)
void HandleClick(int x, int y) override
void DeleteUnknownParts(TO_BLOCK *block)
void FindOverlappingPartitions(const TBOX &box, const ColPartition *not_this, ColPartition_CLIST *parts)
void Deskew(const FCOORD &deskew)
void FindFigureCaptions()
void ReTypeBlobs(BLOBNBOX_LIST *im_blobs)
void DeleteNonLeaderParts()
void ListFindMargins(ColPartitionSet **best_columns, ColPartition_LIST *parts)
static int CountPixelsInRotatedBox(TBOX box, const TBOX &im_box, const FCOORD &rotation, Pix *pix)
static bool BlankImageInBetween(const TBOX &box1, const TBOX &box2, const TBOX &im_box, const FCOORD &rotation, Pix *pix)
TabVector * RightTabForBox(const TBOX &box, bool crossing, bool extended)
WidthCallback * WidthCB()
TabVector * LeftTabForBox(const TBOX &box, bool crossing, bool extended)