Evaluate the vector in terms of coverage of its length by good-looking box edges. A good looking box is one where its nearest neighbour on the inside is nearer than half the distance its nearest neighbour on the outside of the putative column. Bad boxes are removed from the line. A second pass then further filters boxes by requiring that the gutter width be a minimum fraction of the mean gutter al
| 585 | // A second pass then further filters boxes by requiring that the gutter |
| 586 | // width be a minimum fraction of the mean gutter along the line. |
| 587 | void TabVector::Evaluate(const ICOORD& vertical, TabFind* finder) { |
| 588 | bool debug = false; |
| 589 | needs_evaluation_ = false; |
| 590 | int length = endpt_.y() - startpt_.y(); |
| 591 | if (length == 0 || boxes_.empty()) { |
| 592 | percent_score_ = 0; |
| 593 | Print("Zero length in evaluate"); |
| 594 | return; |
| 595 | } |
| 596 | // Compute the mean box height. |
| 597 | BLOBNBOX_C_IT it(&boxes_); |
| 598 | int mean_height = 0; |
| 599 | int height_count = 0; |
| 600 | for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) { |
| 601 | BLOBNBOX* bbox = it.data(); |
| 602 | const TBOX& box = bbox->bounding_box(); |
| 603 | int height = box.height(); |
| 604 | mean_height += height; |
| 605 | ++height_count; |
| 606 | } |
| 607 | if (height_count > 0) mean_height /= height_count; |
| 608 | int max_gutter = kGutterMultiple * mean_height; |
| 609 | if (IsRagged()) { |
| 610 | // Ragged edges face a tougher test in that the gap must always be within |
| 611 | // the height of the blob. |
| 612 | max_gutter = kGutterToNeighbourRatio * mean_height; |
| 613 | } |
| 614 | |
| 615 | STATS gutters(0, max_gutter + 1); |
| 616 | // Evaluate the boxes for their goodness, calculating the coverage as we go. |
| 617 | // Remove boxes that are not good and shorten the list to the first and |
| 618 | // last good boxes. |
| 619 | int num_deleted_boxes = 0; |
| 620 | bool text_on_image = false; |
| 621 | int good_length = 0; |
| 622 | const TBOX* prev_good_box = NULL; |
| 623 | for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) { |
| 624 | BLOBNBOX* bbox = it.data(); |
| 625 | const TBOX& box = bbox->bounding_box(); |
| 626 | int mid_y = (box.top() + box.bottom()) / 2; |
| 627 | if (TabFind::WithinTestRegion(2, XAtY(box.bottom()), box.bottom())) { |
| 628 | if (!debug) { |
| 629 | tprintf("After already deleting %d boxes, ", num_deleted_boxes); |
| 630 | Print("Starting evaluation"); |
| 631 | } |
| 632 | debug = true; |
| 633 | } |
| 634 | // A good box is one where the nearest neighbour on the inside is closer |
| 635 | // than half the distance to the nearest neighbour on the outside |
| 636 | // (of the putative column). |
| 637 | bool left = IsLeftTab(); |
| 638 | int tab_x = XAtY(mid_y); |
| 639 | int gutter_width; |
| 640 | int neighbour_gap; |
| 641 | finder->GutterWidthAndNeighbourGap(tab_x, mean_height, max_gutter, left, |
| 642 | bbox, &gutter_width, &neighbour_gap); |
| 643 | if (debug) { |
| 644 | tprintf("Box (%d,%d)->(%d,%d) has gutter %d, ndist %d\n", |
no test coverage detected