21 #include "config_auto.h" 86 ColPartition* neighbour;
133 bool any_done =
false;
135 bool merge_done =
false;
145 if (!box_cb->
Run(part, &box))
148 ColPartition_CLIST merge_candidates;
149 FindMergeCandidates(part, box, debug, &merge_candidates);
151 int overlap_increase;
155 if (neighbour != NULL && overlap_increase <= 0) {
157 tprintf(
"Merging:hoverlap=%d, voverlap=%d, OLI=%d\n",
166 part->
Absorb(neighbour, NULL);
170 }
else if (neighbour != NULL) {
172 tprintf(
"Overlapped when merged with increase %d: ", overlap_increase);
176 tprintf(
"No candidate neighbour returned\n");
178 }
while (merge_done);
191 if (candidate == part)
198 tprintf(
"Examining merge candidate:");
206 tprintf(
"Too far away: h_dist = %d\n", h_dist);
214 tprintf(
"Too far away: v_dist = %d\n", v_dist);
223 tprintf(
"Candidate fails overlap and diacritic tests!\n");
235 static int IncreaseInOverlap(
const ColPartition* merge1,
238 ColPartition_CLIST* parts) {
241 ColPartition_C_IT it(parts);
244 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
246 if (part == merge1 || part == merge2)
252 ok_overlap,
false)) {
253 total_area += overlap_area;
256 if (overlap_area > 0)
257 total_area -= overlap_area;
259 overlap_area = intersection_box.
area();
260 if (overlap_area > 0) {
261 total_area -= overlap_area;
264 overlap_area = intersection_box.
area();
265 if (overlap_area > 0)
266 total_area += overlap_area;
294 static 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()) {
300 ColPartition_C_IT it2(it);
301 for (it2.mark_cycle_pt(); !it2.cycled_list(); it2.forward()) {
303 if (candidate2 != candidate &&
304 !OKMergeCandidate(candidate, candidate2,
false)) {
306 tprintf(
"NC overlap failed:Candidate:");
308 tprintf(
"fails to be a good merge with:");
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 != NULL) {
338 if (*overlap_grid == NULL) {
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);
410 const ColPartition* part, ColPartition_CLIST* candidates,
bool debug,
412 int* overlap_increase) {
413 if (overlap_increase != NULL)
414 *overlap_increase = 0;
415 if (candidates->empty())
418 static_cast<int>(kTinyEnoughTextlineOverlapFraction *
gridsize() + 0.5);
424 ColPartition_C_IT it(candidates);
427 TBOX full_box(part_box);
428 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
433 ColPartition_CLIST neighbours;
438 tprintf(
"Finding best merge candidate from %d, %d neighbours for box:",
439 candidates->length(), neighbours.length());
447 ColPartition_CLIST non_candidate_neighbours;
448 non_candidate_neighbours.set_subtract(SortByBoxLeft<ColPartition>,
true,
449 &neighbours, candidates);
450 int worst_nc_increase = 0;
453 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
455 if (confirm_cb != NULL && !confirm_cb->
Run(part, candidate)) {
457 tprintf(
"Candidate not confirmed:");
462 int increase = IncreaseInOverlap(part, candidate, ok_overlap, &neighbours);
464 if (best_candidate == NULL || increase < best_increase) {
465 best_candidate = candidate;
466 best_increase = increase;
469 tprintf(
"New best merge candidate has increase %d, area %d, over box:",
470 increase, best_area);
474 }
else if (increase == best_increase) {
476 if (area < best_area) {
478 best_candidate = candidate;
481 increase = IncreaseInOverlap(part, candidate, ok_overlap,
482 &non_candidate_neighbours);
483 if (increase > worst_nc_increase)
484 worst_nc_increase = increase;
486 if (best_increase > 0) {
493 if (worst_nc_increase < best_increase &&
494 TestCompatibleCandidates(*part, debug, candidates)) {
495 best_increase = worst_nc_increase;
498 if (overlap_increase != NULL)
499 *overlap_increase = best_increase;
500 return best_candidate;
506 ColPartition_LIST* part_list) {
519 ColPartition_LIST* big_parts) {
521 static_cast<int>(kTinyEnoughTextlineOverlapFraction *
gridsize() + 0.5);
532 int unresolved_overlaps = 0;
536 if (neighbour == part)
550 if (!shrunken.
overlap(neighbour_box) &&
552 kBigPartSizeRatio * shrunken.
height()) {
555 RemoveBadBox(excluded, part, big_parts);
560 }
else if (box.
contains(neighbour_box)) {
561 ++unresolved_overlaps;
569 kBigPartSizeRatio * shrunken.
height()) {
572 RemoveBadBox(excluded, neighbour, big_parts);
581 if (neighbour_overlap_count <= part_overlap_count ||
585 if (split_blob != NULL) {
594 if (split_blob != NULL) {
601 if (right_part != NULL) {
608 if (unresolved_overlaps > 2 && part->
IsSingleton()) {
611 ColPartition_IT big_it(big_parts);
613 big_it.add_to_end(part);
636 bool any_changed =
false;
642 if (SmoothRegionType(nontext_map, im_box, rotation, debug, part))
651 ColPartition_LIST parts;
652 ColPartition_IT part_it(&parts);
658 part_it.add_after_then_move(part);
665 for (part_it.move_to_first(); !part_it.empty(); part_it.forward()) {
666 part = part_it.extract();
679 TO_BLOCK_LIST* to_blocks) {
680 TO_BLOCK_IT to_block_it(to_blocks);
681 BLOCK_IT block_it(blocks);
683 ColPartition_LIST parts;
684 ColPartition_IT part_it(&parts);
690 part_it.add_after_then_move(part);
712 TO_ROW_IT row_it(to_block->
get_rows());
713 row_it.add_after_then_move(row);
717 to_block->
line_size =
static_cast<float>(median_width);
721 to_block->
line_size =
static_cast<float>(median_height);
725 block_it.add_to_end(block);
726 to_block_it.add_to_end(to_block);
739 ColPartition_LIST parts;
740 ColPartition_IT part_it(&parts);
746 part_it.add_after_then_move(part);
754 for (part_it.move_to_first(); !part_it.empty(); part_it.forward()) {
755 part = part_it.extract();
771 if (left_line != NULL && !left_line->
IsLeftTab())
773 if (left_line != NULL && left_line->
IsLeftTab())
776 if (right_line != NULL && !right_line->
IsRightTab())
778 if (right_line != NULL && right_line->
IsRightTab())
787 ColPartition_LIST* part_lists =
new ColPartition_LIST[
gridheight()];
794 bool any_parts_found =
false;
802 ColPartition_IT part_it(&part_lists[grid_y]);
803 part_it.add_to_end(part);
804 any_parts_found =
true;
807 if (any_parts_found) {
808 for (
int grid_y = 0; grid_y <
gridheight(); ++grid_y) {
810 if (!part_lists[grid_y].empty()) {
816 delete [] part_lists;
817 return any_parts_found;
841 if (single_column_part == NULL) {
845 single_column_part->
CopyLeftTab(*single_column_part,
false);
846 single_column_part->
CopyRightTab(*single_column_part,
false);
856 if (single_column_part != NULL) {
880 BLOBNBOX_IT im_blob_it(im_blobs);
881 ColPartition_LIST dead_parts;
882 ColPartition_IT dead_part_it(&dead_parts);
890 bool any_blobs_moved =
false;
892 BLOBNBOX_C_IT blob_it(part->
boxes());
893 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
895 im_blob_it.add_after_then_move(blob);
899 BLOBNBOX_C_IT blob_it(part->
boxes());
900 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
908 any_blobs_moved =
true;
917 BLOBNBOX_C_IT blob_it(part->
boxes());
919 dead_part_it.add_to_end(part);
921 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
925 delete blob->
cblob();
929 }
else if (any_blobs_moved) {
944 ColPartition_LIST saved_parts;
945 ColPartition_IT part_it(&saved_parts);
951 part_it.add_to_end(part);
954 Init(gridsize, bleft, tright);
956 for (part_it.move_to_first(); !part_it.empty(); part_it.forward()) {
957 part = part_it.extract();
977 ? best_columns[gsearch.
GridY()]
979 FindPartitionMargins(columns, part);
982 tprintf(
"Computed margins for part:");
994 ColPartition_LIST* parts) {
995 ColPartition_IT part_it(parts);
996 for (part_it.mark_cycle_pt(); !part_it.cycled_list(); part_it.forward()) {
999 if (best_columns != NULL) {
1004 columns = best_columns[grid_y];
1006 FindPartitionMargins(columns, part);
1012 ColPartition_LIST dead_parts;
1013 ColPartition_IT dead_it(&dead_parts);
1019 dead_it.add_to_end(part);
1078 for (
int upper = 0; upper < 2; ++upper) {
1082 for (partner_it.mark_cycle_pt(); !partner_it.cycled_list();
1083 partner_it.forward()) {
1089 if (!partner_it.cycled_list())
continue;
1091 for (partner_it.mark_cycle_pt(); !partner_it.cycled_list();
1092 partner_it.forward()) {
1097 tprintf(
"Finding figure captions for image part:");
1099 tprintf(
"Considering partner:");
1100 partner_box.
print();
1102 if (partner_box.
left() >= part_box.
left() &&
1104 int dist = partner_box.
y_gap(part_box);
1105 if (best_caption == NULL || dist < best_dist) {
1107 best_caption = partner;
1113 if (best_caption != NULL) {
1115 tprintf(
"Best caption candidate:");
1116 best_caption->bounding_box().print();
1122 int biggest_gap = 0;
1124 int total_height = 0;
1125 int mean_height = 0;
1128 for (
ColPartition* partner = best_caption; partner != NULL &&
1130 partner = next_partner) {
1131 if (!partner->IsTextType()) {
1132 end_partner = partner;
1138 if (next_partner != NULL) {
1141 if (gap > biggest_gap) {
1143 end_partner = next_partner;
1144 mean_height = total_height / line_count;
1145 }
else if (gap < smallest_gap) {
1150 if (biggest_gap > mean_height * kMinCaptionGapHeightRatio &&
1151 biggest_gap > smallest_gap * kMinCaptionGapRatio)
1156 tprintf(
"Line count=%d, biggest gap %d, smallest%d, mean height %d\n",
1157 line_count, biggest_gap, smallest_gap, mean_height);
1158 if (end_partner != NULL) {
1163 if (next_partner == NULL && line_count <= kMaxCaptionLines)
1165 if (line_count <= kMaxCaptionLines) {
1167 for (
ColPartition* partner = best_caption; partner != NULL &&
1168 partner != end_partner;
1169 partner = next_partner) {
1171 partner->SetBlobTypes();
1173 tprintf(
"Set caption type for partition:");
1174 partner->bounding_box().print();
1211 int height = top - bottom;
1212 int mid_y = (bottom + top) / 2;
1220 if (neighbour == part || neighbour->
type() ==
PT_NOISE)
1224 int neighbour_y = (neighbour_bottom + neighbour_top) / 2;
1225 if (upper != (neighbour_y > mid_y))
1230 if (best_neighbour == NULL)
1231 best_neighbour = neighbour;
1234 int dist = upper ? neighbour_bottom - top : bottom - neighbour_top;
1235 if (dist <= kMaxPartitionSpacing * height) {
1236 if (dist < best_dist) {
1238 best_neighbour = neighbour;
1244 if (best_neighbour != NULL)
1257 int width = right - left;
1258 int mid_x = (left + right) / 2;
1265 while ((neighbour = hsearch.
NextSideSearch(to_the_left)) != NULL) {
1266 if (neighbour == part || neighbour->
type() ==
PT_NOISE)
1270 int neighbour_x = (neighbour_left + neighbour_right) / 2;
1271 if (to_the_left != (neighbour_x < mid_x))
1277 int dist = to_the_left ? left - neighbour_right : neighbour_left - right;
1278 if (dist <= kMaxPartitionSpacing * width) {
1279 if (dist < best_dist || best_neighbour == NULL) {
1281 best_neighbour = neighbour;
1289 if (best_neighbour != NULL)
1290 part->
AddPartner(to_the_left, best_neighbour);
1306 get_desperate,
this);
1319 void ColPartitionGrid::FindMergeCandidates(
const ColPartition* part,
1320 const TBOX& search_box,
bool debug,
1321 ColPartition_CLIST* candidates) {
1323 static_cast<int>(kTinyEnoughTextlineOverlapFraction *
gridsize() + 0.5);
1331 if (!OKMergeCandidate(part, candidate, debug))
1348 TBOX merged_box(part_box);
1349 merged_box += c_box;
1355 if (neighbour == part || neighbour == candidate)
1357 if (neighbour->
OKMergeOverlap(*part, *candidate, ok_overlap,
false))
1364 !OKMergeCandidate(part, neighbour,
false) &&
1365 !OKMergeCandidate(candidate, neighbour,
false))
1368 if (neighbour != NULL) {
1370 tprintf(
"Combined box overlaps another that is not OK despite" 1371 " allowance of %d:", ok_overlap);
1374 OKMergeCandidate(part, neighbour,
true);
1376 OKMergeCandidate(candidate, neighbour,
true);
1388 candidates->add_sorted(SortByBoxLeft<ColPartition>,
true, candidate);
1403 bool ColPartitionGrid::SmoothRegionType(Pix* nontext_map,
1405 const FCOORD& rerotation,
1410 tprintf(
"Smooothing part at:");
1416 max_dist =
MAX(max_dist * kMaxNeighbourDistFactor,
gridsize() * 2);
1418 bool any_image =
false;
1419 bool all_image =
true;
1423 BlobRegionType type = SmoothInOneDirection(dir, nontext_map, im_box,
1424 rerotation, debug, *part,
1427 tprintf(
"Result in dir %d = %d at dist %d\n", dir, type, dist);
1438 if (best_dist > max_dist)
1445 if (best_type ==
BRT_TEXT && !any_image) {
1455 if (new_type != part->
blob_type() || new_flow != part->
flow()) {
1473 const TBOX& part_box,
1477 *search_box = part_box;
1481 padding =
MAX(padding, min_padding);
1483 search_box->
pad(padding, padding);
1486 switch (direction) {
1489 *dist_scaling =
ICOORD(2, 1);
1493 *dist_scaling =
ICOORD(1, 2);
1497 *dist_scaling =
ICOORD(2, 1);
1501 *dist_scaling =
ICOORD(1, 2);
1529 const TBOX& im_box,
const FCOORD& rerotation,
1530 bool debug,
const ColPartition& part,
int* best_distance) {
1535 ComputeSearchBoxAndScaling(direction, part_box,
gridsize(),
1536 &search_box, &dist_scaling);
1541 AccumulatePartDistances(part, dist_scaling, search_box,
1542 nontext_map, im_box, rerotation, debug, dists);
1547 memset(counts, 0,
sizeof(counts[0]) *
NPT_COUNT);
1549 int image_bias = image_region ? kSmoothDecisionMargin / 2 : 0;
1557 if (counts[i] < dists[i].
size() && dists[i][counts[i]] < min_dist)
1558 min_dist = dists[i][counts[i]];
1562 while (counts[i] < dists[i].
size() && dists[i][counts[i]] <= min_dist)
1565 *best_distance = min_dist;
1567 tprintf(
"Totals: htext=%d+%d, vtext=%d+%d, image=%d+%d, at dist=%d\n",
1570 counts[
NPT_IMAGE], image_bias, min_dist);
1578 if (image_count > 0 &&
1579 image_bias - htext_score >= kSmoothDecisionMargin &&
1580 image_bias - vtext_score >= kSmoothDecisionMargin) {
1610 void ColPartitionGrid::AccumulatePartDistances(
const ColPartition& base_part,
1611 const ICOORD& dist_scaling,
1612 const TBOX& search_box,
1615 const FCOORD& rerotation,
1628 neighbour == &base_part)
1638 int x_gap =
MAX(part_box.
x_gap(nbox), 0);
1639 int y_gap =
MAX(part_box.
y_gap(nbox), 0);
1640 int n_dist = x_gap * dist_scaling.
x() + y_gap* dist_scaling.
y();
1642 tprintf(
"Part has x-gap=%d, y=%d, dist=%d at:",
1643 x_gap, y_gap, n_dist);
1665 if (debug)
tprintf(
"Weak %d\n", n_boxes);
1668 if (debug)
tprintf(
"Image %d\n", n_boxes);
1670 if (count_vector != NULL) {
1671 for (
int i = 0; i < n_boxes; ++i)
1690 int y = part->
MidY();
1692 int left_margin =
bleft().
x();
1693 int right_margin =
tright().
x();
1694 if (columns != NULL) {
1697 left_margin = column->
LeftAtY(y);
1700 right_margin = column->
RightAtY(y);
1705 left_margin = FindMargin(box.
left() + box.
height(),
true, left_margin,
1709 right_margin = FindMargin(box.
right() - box.
height(),
false, right_margin,
1717 int ColPartitionGrid::FindMargin(
int x,
bool right_to_left,
int x_limit,
1718 int y_bottom,
int y_top,
1720 int height = y_top - y_bottom;
1726 while ((part = side_search.
NextSideSearch(right_to_left)) != NULL) {
1728 if (part == not_this)
1733 int min_overlap =
MIN(height, box.
height());
1734 min_overlap =
static_cast<int>(min_overlap * kMarginOverlapFraction + 0.5);
1736 if (y_overlap < min_overlap)
1739 int x_edge = right_to_left ? box.
right() : box.
left();
1740 if ((x_edge < x) != right_to_left)
1743 if ((x_edge < x_limit) == right_to_left)
ColPartition * ColumnContaining(int x, int y)
void SplitOverlappingPartitions(ColPartition_LIST *big_parts)
void rotate_large(const FCOORD &vec)
bool IsVerticalType() const
TBOX intersection(const TBOX &box) const
bool overlap(const TBOX &box) const
bool MakeColPartSets(PartSetVector *part_sets)
int VCoreOverlap(const ColPartition &other) const
ColPartition_CLIST * upper_partners()
static ColPartition * MakeBigPartition(BLOBNBOX *box, ColPartition_LIST *big_part_list)
bool GridSmoothNeighbours(BlobTextFlowType source_type, Pix *nontext_map, const TBOX &im_box, const FCOORD &rerotation)
bool VSignificantCoreOverlap(const ColPartition &other) const
void HandleClick(int x, int y)
const double kTinyEnoughTextlineOverlapFraction
bool MergePart(TessResultCallback2< bool, ColPartition *, TBOX *> *box_cb, TessResultCallback2< bool, const ColPartition *, const ColPartition *> *confirm_cb, ColPartition *part)
void SetColumnGoodness(WidthCallback *cb)
const double kMinCaptionGapRatio
bool ConfirmNoTabViolation(const ColPartition &other) const
void DeleteUnknownParts(TO_BLOCK *block)
void Init(int gridsize, const ICOORD &bleft, const ICOORD &tright)
TBOX bounding_union(const TBOX &box) const
bool IsUnMergeableType() const
const double kMinCaptionGapHeightRatio
void ExtractPartitionsAsBlocks(BLOCK_LIST *blocks, TO_BLOCK_LIST *to_blocks)
TBOX BoundsWithoutBox(BLOBNBOX *box)
void set_poly_block(POLY_BLOCK *blk)
set the poly block
const ICOORD & bleft() const
void RemoveBox(BLOBNBOX *box)
inT16 x() const
access function
static int CountPixelsInRotatedBox(TBOX box, const TBOX &im_box, const FCOORD &rotation, Pix *pix)
bool ReleaseNonLeaderBoxes()
void set_flow(BlobTextFlowType f)
void RefinePartners(PolyBlockType type, bool get_desperate, ColPartitionGrid *grid)
int direction(EDGEPT *point)
const double kBigPartSizeRatio
ColPartition * SplitAtBlob(BLOBNBOX *split_blob)
void Deskew(const FCOORD &deskew)
ColPartition_CLIST * lower_partners()
#define BOOL_VAR(name, val, comment)
void ListFindMargins(ColPartitionSet **best_columns, ColPartition_LIST *parts)
int RightAtY(int y) const
void FindFigureCaptions()
BlobRegionType region_type() const
void RepositionIterator()
void set_region_type(BlobRegionType new_type)
void set_block_owned(bool owned)
void SetUniqueMode(bool mode)
bool textord_tabfind_show_color_fit
void set_owner(tesseract::ColPartition *new_owner)
void StartVerticalSearch(int xmin, int xmax, int y)
int y_gap(const TBOX &box) const
void Merges(TessResultCallback2< bool, ColPartition *, TBOX *> *box_cb, TessResultCallback2< bool, const ColPartition *, const ColPartition *> *confirm_cb)
BLOBNBOX * OverlapSplitBlob(const TBOX &box)
ColPartition * ShallowCopy() const
void set_type(PolyBlockType t)
const int kMaxCaptionLines
bool OKMergeOverlap(const ColPartition &merge1, const ColPartition &merge2, int ok_box_overlap, bool debug)
void FindOverlappingPartitions(const TBOX &box, const ColPartition *not_this, ColPartition_CLIST *parts)
void InsertBBox(bool h_spread, bool v_spread, ColPartition *bbox)
const TBOX & bounding_box() const
void DeleteNonLeaderParts()
inT16 y() const
access_function
bool WithinSameMargins(const ColPartition &other) const
const ICOORD & tright() const
int ComputeTotalOverlap(ColPartitionGrid **overlap_grid)
const double kMaxPartitionSpacing
void set_right_margin(int margin)
void DeleteUnownedNoise()
void StartSideSearch(int x, int ymin, int ymax)
void SetLeftTab(const TabVector *tab_vector)
static bool IsLineType(BlobRegionType type)
void StartRadSearch(int x, int y, int max_radius)
void pad(int xpad, int ypad)
void CopyRightTab(const ColPartition &src, bool take_box)
bool contains(const FCOORD pt) const
PolyBlockType type() const
void RefinePartitionPartners(bool get_desperate)
void set_vertical(const ICOORD &v)
void FindVPartitionPartners(bool to_the_left, ColPartition *part)
static bool WithinTestRegion(int detail_level, int x, int y)
const double kMarginOverlapFraction
bool HOverlaps(const ColPartition &other) const
int CountOverlappingBoxes(const TBOX &box)
ColPartitionSet * MakeSingleColumnSet(WidthCallback *cb)
ColPartition * BestMergeCandidate(const ColPartition *part, ColPartition_CLIST *candidates, bool debug, TessResultCallback2< bool, const ColPartition *, const ColPartition *> *confirm_cb, int *overlap_increase)
BBC * NextVerticalSearch(bool top_to_bottom)
const ICOORD & topright() const
void set_flow(BlobTextFlowType value)
virtual ~ColPartitionGrid()
void FindPartitionPartners()
const int kMaxNeighbourDistFactor
BBC * NextSideSearch(bool right_to_left)
void set_left_margin(int margin)
void AddPartner(bool upper, ColPartition *partner)
ColPartition * SingletonPartner(bool upper)
void CopyLeftTab(const ColPartition &src, bool take_box)
void RemoveBBox(ColPartition *bbox)
void Absorb(ColPartition *other, WidthCallback *cb)
void SetRightTab(const TabVector *tab_vector)
int median_bottom() const
void StartRectSearch(const TBOX &rect)
static bool IsTextType(BlobRegionType type)
const ICOORD & botleft() const
TabVector * RightTabForBox(const TBOX &box, bool crossing, bool extended)
TabVector * LeftTabForBox(const TBOX &box, bool crossing, bool extended)
void RecomputeBounds(int gridsize, const ICOORD &bleft, const ICOORD &tright, const ICOORD &vertical)
bool OKDiacriticMerge(const ColPartition &candidate, bool debug) const
static bool BlankImageInBetween(const TBOX &box1, const TBOX &box2, const TBOX &im_box, const FCOORD &rotation, Pix *pix)
WidthCallback * WidthCB()
const TBOX & bounding_box() const
void ReTypeBlobs(BLOBNBOX_LIST *im_blobs)
void SetTabStops(TabFind *tabgrid)
BlobTextFlowType flow() const
bool VOverlaps(const ColPartition &other) const
BlobTextFlowType flow() const
BlobRegionType blob_type() const
const int kColumnWidthFactor
bool TypesMatch(const ColPartition &other) const
int HCoreOverlap(const ColPartition &other) const
void GridFindMargins(ColPartitionSet **best_columns)
void GridCoords(int x, int y, int *grid_x, int *grid_y) const
int x_gap(const TBOX &box) const
void set_blob_type(BlobRegionType t)
const int kSmoothDecisionMargin