581 {
582 bool debug = false;
583 needs_evaluation_ = false;
584 int length = endpt_.
y() - startpt_.
y();
585 if (length == 0 || boxes_.empty()) {
586 percent_score_ = 0;
587 Print(
"Zero length in evaluate");
588 return;
589 }
590
591 BLOBNBOX_C_IT it(&boxes_);
592 int mean_height = 0;
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;
599 ++height_count;
600 }
601 if (height_count > 0) {
602 mean_height /= height_count;
603 }
606
607
609 }
610
611 STATS gutters(0, max_gutter);
612
613
614
615 int num_deleted_boxes = 0;
616 bool text_on_image = false;
617 int good_length = 0;
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;
624 if (!debug) {
625 tprintf(
"After already deleting %d boxes, ", num_deleted_boxes);
626 Print(
"Starting evaluation");
627 }
628 debug = true;
629 }
630
631
632
634 int tab_x =
XAtY(mid_y);
635 int gutter_width;
636 int neighbour_gap;
637 finder->GutterWidthAndNeighbourGap(tab_x, mean_height, max_gutter, left, bbox, &gutter_width,
638 &neighbour_gap);
639 if (debug) {
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);
642 }
643
645
646 good_length += box.top() - box.bottom();
647 gutters.add(gutter_width, 1);
648
649
650
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;
657 }
658 if (debug) {
659 tprintf(
"Box and prev good, gap=%d, target %g, goodlength=%d\n", vertical_gap,
661 }
662 } else {
663
665 }
666 prev_good_box = &box;
668 text_on_image = true;
669 }
670 } else {
671
672 if (debug) {
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);
675 }
676 it.extract();
677 ++num_deleted_boxes;
678 }
679 }
680 if (debug) {
681 Print(
"Evaluating:");
682 }
683
684
685
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;
695
696
698 int tab_x =
XAtY(mid_y);
701
702
704 }
705 int gutter_width;
706 int neighbour_gap;
707 finder->GutterWidthAndNeighbourGap(tab_x, mean_height, max_gutter, left, bbox, &gutter_width,
708 &neighbour_gap);
709
711 if (prev_good_box == nullptr) {
712
714 search_bottom = box.top();
715 }
716 prev_good_box = &box;
717 search_top = box.bottom();
718 } else {
719
720 if (debug) {
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);
723 }
724 it.extract();
725 ++num_deleted_boxes;
726 }
727 }
728 }
729
730 if (prev_good_box != nullptr) {
732
733 int length = endpt_.
y() - startpt_.
y();
734 percent_score_ = 100 * good_length / length;
735 if (num_deleted_boxes > 0) {
736 needs_refit_ = true;
738 if (boxes_.empty()) {
739 return;
740 }
741 }
742
743 int required_shift;
744 if (search_bottom > search_top) {
745 search_bottom = startpt_.
y();
746 search_top = endpt_.
y();
747 }
750 min_gutter_width *= mean_height;
752 if (median_gutter > max_gutter_width) {
753 max_gutter_width = median_gutter;
754 }
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) {
758 if (debug) {
759 tprintf(
"Rejecting bad tab Vector with %d gutter vs %g min\n", gutter_width,
760 min_gutter_width);
761 }
762 boxes_.shallow_clear();
763 percent_score_ = 0;
764 } else if (debug) {
765 tprintf(
"Final gutter %d, vs limit of %g, required shift = %d\n", gutter_width,
766 min_gutter_width, required_shift);
767 }
768 } else {
769
770 percent_score_ = 0;
771 }
772
773 if (debug) {
774 Print(
"Evaluation complete:");
775 }
776}
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)