579 {
580 bool debug = false;
581 needs_evaluation_ = false;
582 int length = endpt_.
y() - startpt_.
y();
583 if (length == 0 || boxes_.empty()) {
584 percent_score_ = 0;
585 Print(
"Zero length in evaluate");
586 return;
587 }
588
589 BLOBNBOX_C_IT it(&boxes_);
590 int mean_height = 0;
591 int height_count = 0;
592 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
595 int height = box.
height();
596 mean_height += height;
597 ++height_count;
598 }
599 if (height_count > 0) mean_height /= height_count;
602
603
605 }
606
607 STATS gutters(0, max_gutter + 1);
608
609
610
611 int num_deleted_boxes = 0;
612 bool text_on_image = false;
613 int good_length = 0;
614 const TBOX* prev_good_box =
nullptr;
615 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
618 int mid_y = (box.
top() + box.
bottom()) / 2;
620 if (!debug) {
621 tprintf(
"After already deleting %d boxes, ", num_deleted_boxes);
622 Print(
"Starting evaluation");
623 }
624 debug = true;
625 }
626
627
628
630 int tab_x =
XAtY(mid_y);
631 int gutter_width;
632 int neighbour_gap;
633 finder->GutterWidthAndNeighbourGap(tab_x, mean_height, max_gutter, left,
634 bbox, &gutter_width, &neighbour_gap);
635 if (debug) {
636 tprintf(
"Box (%d,%d)->(%d,%d) has gutter %d, ndist %d\n",
638 gutter_width, neighbour_gap);
639 }
640
642
644 gutters.add(gutter_width, 1);
645
646
647
648 if (prev_good_box != nullptr) {
649 int vertical_gap = box.
bottom() - prev_good_box->
top();
650 double size1 = sqrt(
static_cast<double>(prev_good_box->
area()));
651 double size2 = sqrt(
static_cast<double>(box.
area()));
653 good_length += vertical_gap;
654 if (debug) {
655 tprintf(
"Box and prev good, gap=%d, target %g, goodlength=%d\n",
657 good_length);
658 }
659 } else {
660
662 }
663 prev_good_box = &box;
665 text_on_image = true;
666 } else {
667
668 if (debug) {
669 tprintf(
"Bad Box (%d,%d)->(%d,%d) with gutter %d, ndist %d\n",
671 gutter_width, neighbour_gap);
672 }
673 it.extract();
674 ++num_deleted_boxes;
675 }
676 }
677 if (debug) {
678 Print(
"Evaluating:");
679 }
680
681
682
683 int search_top = endpt_.
y();
684 int search_bottom = startpt_.
y();
686 if (gutters.get_total() > 0) {
687 prev_good_box = nullptr;
688 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
691 int mid_y = (box.
top() + box.
bottom()) / 2;
692
693
695 int tab_x =
XAtY(mid_y);
698
699
701 }
702 int gutter_width;
703 int neighbour_gap;
704 finder->GutterWidthAndNeighbourGap(tab_x, mean_height, max_gutter, left,
705 bbox, &gutter_width, &neighbour_gap);
706
708 if (prev_good_box == nullptr) {
709
711 search_bottom = box.
top();
712 }
713 prev_good_box = &box;
714 search_top = box.
bottom();
715 } else {
716
717 if (debug) {
718 tprintf(
"Bad Box (%d,%d)->(%d,%d) with gutter %d, mean gutter %d\n",
720 gutter_width, median_gutter);
721 }
722 it.extract();
723 ++num_deleted_boxes;
724 }
725 }
726 }
727
728 if (prev_good_box != nullptr) {
730
731 int length = endpt_.
y() - startpt_.
y();
732 percent_score_ = 100 * good_length / length;
733 if (num_deleted_boxes > 0) {
734 needs_refit_ = true;
736 if (boxes_.empty())
737 return;
738 }
739
740 int required_shift;
741 if (search_bottom > search_top) {
742 search_bottom = startpt_.
y();
743 search_top = endpt_.
y();
744 }
747 min_gutter_width *= mean_height;
749 if (median_gutter > max_gutter_width)
750 max_gutter_width = median_gutter;
751 int gutter_width = finder->GutterWidth(search_bottom, search_top, *this,
752 text_on_image, max_gutter_width,
753 &required_shift);
754 if (gutter_width < min_gutter_width) {
755 if (debug) {
756 tprintf(
"Rejecting bad tab Vector with %d gutter vs %g min\n",
757 gutter_width, min_gutter_width);
758 }
759 boxes_.shallow_clear();
760 percent_score_ = 0;
761 } else if (debug) {
762 tprintf(
"Final gutter %d, vs limit of %g, required shift = %d\n",
763 gutter_width, min_gutter_width, required_shift);
764 }
765 } else {
766
767 percent_score_ = 0;
768 }
769
770 if (debug) {
771 Print(
"Evaluation complete:");
772 }
773}
int IntCastRounded(double x)
const double kMinAlignedGutter
const int kGutterMultiple
const double kMinRaggedGutter
const double kLineCountReciprocal
const int kMaxFillinMultiple
const double kMinGutterFraction
const int kGutterToNeighbourRatio
BlobTextFlowType flow() const
static bool WithinTestRegion(int detail_level, int x, int y)
void SetYStart(int start_y)
void FitAndEvaluateIfNeeded(const ICOORD &vertical, TabFind *finder)