583 needs_evaluation_ =
false;
584 int length = endpt_.
y() - startpt_.
y();
585 if (length == 0 || boxes_.empty()) {
587 Print(
"Zero length in evaluate");
591 BLOBNBOX_C_IT it(&boxes_);
593 int height_count = 0;
594 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
595 BLOBNBOX *bbox = it.data();
596 const TBOX &box = bbox->bounding_box();
597 int height = box.height();
598 mean_height += height;
601 if (height_count > 0) {
602 mean_height /= height_count;
611 STATS gutters(0, max_gutter + 1);
615 int num_deleted_boxes = 0;
616 bool text_on_image =
false;
618 const TBOX *prev_good_box =
nullptr;
619 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
620 BLOBNBOX *bbox = it.data();
621 const TBOX &box = bbox->bounding_box();
622 int mid_y = (box.top() + box.bottom()) / 2;
625 tprintf(
"After already deleting %d boxes, ", num_deleted_boxes);
626 Print(
"Starting evaluation");
634 int tab_x =
XAtY(mid_y);
637 finder->GutterWidthAndNeighbourGap(tab_x, mean_height, max_gutter, left, bbox, &gutter_width,
640 tprintf(
"Box (%d,%d)->(%d,%d) has gutter %d, ndist %d\n", box.left(), box.bottom(),
641 box.right(), box.top(), gutter_width, neighbour_gap);
646 good_length += box.top() - box.bottom();
647 gutters.add(gutter_width, 1);
651 if (prev_good_box !=
nullptr) {
652 int vertical_gap = box.bottom() - prev_good_box->top();
653 double size1 = sqrt(
static_cast<double>(prev_good_box->area()));
654 double size2 = sqrt(
static_cast<double>(box.area()));
656 good_length += vertical_gap;
659 tprintf(
"Box and prev good, gap=%d, target %g, goodlength=%d\n", vertical_gap,
666 prev_good_box = &box;
668 text_on_image =
true;
673 tprintf(
"Bad Box (%d,%d)->(%d,%d) with gutter %d, ndist %d\n", box.left(), box.bottom(),
674 box.right(), box.top(), gutter_width, neighbour_gap);
681 Print(
"Evaluating:");
686 int search_top = endpt_.
y();
687 int search_bottom = startpt_.
y();
689 if (gutters.get_total() > 0) {
690 prev_good_box =
nullptr;
691 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
692 BLOBNBOX *bbox = it.data();
693 const TBOX &box = bbox->bounding_box();
694 int mid_y = (box.top() + box.bottom()) / 2;
698 int tab_x =
XAtY(mid_y);
707 finder->GutterWidthAndNeighbourGap(tab_x, mean_height, max_gutter, left, bbox, &gutter_width,
711 if (prev_good_box ==
nullptr) {
714 search_bottom = box.top();
716 prev_good_box = &box;
717 search_top = box.bottom();
721 tprintf(
"Bad Box (%d,%d)->(%d,%d) with gutter %d, mean gutter %d\n", box.left(),
722 box.bottom(), box.right(), box.top(), gutter_width, median_gutter);
730 if (prev_good_box !=
nullptr) {
733 int length = endpt_.
y() - startpt_.
y();
734 percent_score_ = 100 * good_length / length;
735 if (num_deleted_boxes > 0) {
738 if (boxes_.empty()) {
744 if (search_bottom > search_top) {
745 search_bottom = startpt_.
y();
746 search_top = endpt_.
y();
750 min_gutter_width *= mean_height;
752 if (median_gutter > max_gutter_width) {
753 max_gutter_width = median_gutter;
755 int gutter_width = finder->GutterWidth(search_bottom, search_top, *
this, text_on_image,
756 max_gutter_width, &required_shift);
757 if (gutter_width < min_gutter_width) {
759 tprintf(
"Rejecting bad tab Vector with %d gutter vs %g min\n", gutter_width,
762 boxes_.shallow_clear();
765 tprintf(
"Final gutter %d, vs limit of %g, required shift = %d\n", gutter_width,
766 min_gutter_width, required_shift);
774 Print(
"Evaluation complete:");
const double kMinAlignedGutter
int IntCastRounded(double x)
const int kGutterMultiple
const double kMinRaggedGutter
const double kLineCountReciprocal
const int kMaxFillinMultiple
const double kMinGutterFraction
const int kGutterToNeighbourRatio
static bool WithinTestRegion(int detail_level, int x, int y)
void SetYStart(int start_y)
void FitAndEvaluateIfNeeded(const ICOORD &vertical, TabFind *finder)