Tesseract 3.02

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- Class List
- Class Hierarchy
- Class Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Public Member Functions | Static Public Member Functions | Protected Member Functions | Static Protected Member Functions | Protected Attributes
tesseract::TabFind Class Reference

`#include <tabfind.h>`

Inheritance diagram for tesseract::TabFind:

List of all members.

## Public Member Functions
| TabFind (int gridsize, const ICOORD &bleft, const ICOORD &tright, TabVector_LIST *vlines, int vertical_x, int vertical_y, int resolution)
virtual | ~TabFind ()
void | InsertBlobsToGrid (bool h_spread, bool v_spread, BLOBNBOX_LIST *blobs, BBGrid< BLOBNBOX, BLOBNBOX_CLIST, BLOBNBOX_C_IT > *grid)
bool | InsertBlob (bool h_spread, bool v_spread, BLOBNBOX *blob, BBGrid< BLOBNBOX, BLOBNBOX_CLIST, BLOBNBOX_C_IT > *grid)
void | SetBlockRuleEdges (TO_BLOCK *block)
void | SetBlobRuleEdges (BLOBNBOX_LIST *blobs)
int | GutterWidth (int bottom_y, int top_y, const TabVector &v, bool ignore_unmergeables, int max_gutter_width, int *required_shift)
void | GutterWidthAndNeighbourGap (int tab_x, int mean_height, int max_gutter, bool left, BLOBNBOX *bbox, int *gutter_width, int *neighbour_gap)
int | RightEdgeForBox (const TBOX &box, bool crossing, bool extended)
int | LeftEdgeForBox (const TBOX &box, bool crossing, bool extended)
TabVector * | RightTabForBox (const TBOX &box, bool crossing, bool extended)
TabVector * | LeftTabForBox (const TBOX &box, bool crossing, bool extended)
bool | CommonWidth (int width)
WidthCallback * | WidthCB ()
const ICOORD & | image_origin () const
Public Member Functions inherited from tesseract::AlignedBlob
| AlignedBlob (int gridsize, const ICOORD &bleft, const ICOORD &tright)
virtual | ~AlignedBlob ()
ScrollView * | DisplayTabs (const char *window_name, ScrollView *tab_win)
TabVector * | FindVerticalAlignment (AlignedBlobParams align_params, BLOBNBOX *bbox, int *vertical_x, int *vertical_y)
Public Member Functions inherited from tesseract::BlobGrid
| BlobGrid (int gridsize, const ICOORD &bleft, const ICOORD &tright)
virtual | ~BlobGrid ()
void | InsertBlobList (BLOBNBOX_LIST *blobs)
Public Member Functions inherited from tesseract::BBGrid< BLOBNBOX, BLOBNBOX_CLIST, BLOBNBOX_C_IT >
| BBGrid ()
| BBGrid (int gridsize, const ICOORD &bleft, const ICOORD &tright)
virtual | ~BBGrid ()
void | Init (int gridsize, const ICOORD &bleft, const ICOORD &tright)
void | Clear ()
void | ClearGridData (void(*free_method)(BLOBNBOX *))
void | InsertBBox (bool h_spread, bool v_spread, BLOBNBOX *bbox)
void | InsertPixPtBBox (int left, int bottom, Pix *pix, BLOBNBOX *bbox)
void | RemoveBBox (BLOBNBOX *bbox)
bool | RectangleEmpty (const TBOX &rect)
IntGrid * | CountCellElements ()
ScrollView * | MakeWindow (int x, int y, const char *window_name)
void | DisplayBoxes (ScrollView *window)
void | AssertNoDuplicates ()
virtual void | HandleClick (int x, int y)
Public Member Functions inherited from tesseract::GridBase
| GridBase ()
| GridBase (int gridsize, const ICOORD &bleft, const ICOORD &tright)
virtual | ~GridBase ()
int | gridsize () const
int | gridwidth () const
int | gridheight () const
const ICOORD & | bleft () const
const ICOORD & | tright () const
void | GridCoords (int x, int y, int *grid_x, int *grid_y) const
void | ClipGridCoords (int *x, int *y) const

## Static Public Member Functions
static bool | DifferentSizes (int size1, int size2)
static bool | VeryDifferentSizes (int size1, int size2)
Static Public Member Functions inherited from tesseract::AlignedBlob
static bool | WithinTestRegion (int detail_level, int x, int y)
static void | IncrementDebugPix ()
static const STRING & | textord_debug_pix ()

## Protected Member Functions
TabVector_LIST * | vectors ()
TabVector_LIST * | dead_vectors ()
bool | FindTabVectors (TabVector_LIST *hlines, BLOBNBOX_LIST *image_blobs, TO_BLOCK *block, int min_gutter_width, ColPartitionGrid *part_grid, FCOORD *deskew, FCOORD *reskew)
void | DontFindTabVectors (BLOBNBOX_LIST *image_blobs, TO_BLOCK *block, FCOORD *deskew, FCOORD *reskew)
void | TidyBlobs (TO_BLOCK *block)
void | SetupTabSearch (int x, int y, int *min_key, int *max_key)
ScrollView * | DisplayTabVectors (ScrollView *tab_win)
ScrollView * | FindInitialTabVectors (BLOBNBOX_LIST *image_blobs, int min_gutter_width, TO_BLOCK *block)
void | ResetForVerticalText (const FCOORD &rotate, const FCOORD &rerotate, TabVector_LIST *horizontal_lines, int *min_gutter_width)
void | Reset ()
void | ReflectInYAxis ()

## Static Protected Member Functions
static void | RotateBlobList (const FCOORD &rotation, BLOBNBOX_LIST *blobs)

## Protected Attributes
ICOORD | vertical_skew_
int | resolution_

## Detailed Description

The TabFind class contains code to find tab-stops and maintain the vectors_ list of tab vectors. Also provides an interface to find neighbouring blobs in the grid of BLOBNBOXes that is used by multiple subclasses. Searching is a complex operation because of the need to enforce rule/separator lines, and tabstop boundaries, (when available), so as the holder of the list of TabVectors this class provides the functions.

Definition at line 62 of file tabfind.h.

## Constructor & Destructor Documentation

tesseract::TabFind::TabFind | ( | int | gridsize,
|  | const ICOORD & | bleft,
|  | const ICOORD & | tright,
|  | TabVector_LIST * | vlines,
|  | int | vertical_x,
|  | int | vertical_y,
|  | int | resolution
| ) |  |

Definition at line 89 of file tabfind.cpp.

: AlignedBlob(gridsize, bleft, tright),
resolution_(resolution),
image_origin_(0, tright.y() - 1) {
width_cb_ = NULL;
v_it_.set_to_list(&vectors_);
v_it_.add_list_after(vlines);
SetVerticalSkewAndParellelize(vertical_x, vertical_y);
width_cb_ = NewPermanentTessCallback(this, &TabFind::CommonWidth);
}

tesseract::TabFind::~TabFind | ( |  | ) |
| virtual

Definition at line 102 of file tabfind.cpp.

{
if (width_cb_ != NULL)
delete width_cb_;
}

## Member Function Documentation

bool tesseract::TabFind::CommonWidth | ( | int | width | ) |

Return true if the given width is close to one of the common widths in column_widths_.

Definition at line 419 of file tabfind.cpp.

{
width /= kColumnWidthFactor;
ICOORDELT_IT it(&column_widths_);
for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
ICOORDELT* w = it.data();
if (NearlyEqual<int>(width, w->x(), 1))
return true;
}
return false;
}

TabVector_LIST* tesseract::TabFind::dead_vectors | ( |  | ) |
| inline protected

Definition at line 185 of file tabfind.h.

{
return &dead_vectors_;
}

bool tesseract::TabFind::DifferentSizes | ( | int | size1,
|  | int | size2
| ) |  |
| static

Return true if the sizes are more than a factor of 2 different.

Definition at line 432 of file tabfind.cpp.

{
return size1 > size2 * 2 || size2 > size1 * 2;
}

ScrollView * tesseract::TabFind::DisplayTabVectors | ( | ScrollView * | tab_win | ) |
| protected

Display the tab vectors found in this grid.

Definition at line 525 of file tabfind.cpp.

{
#ifndef GRAPHICS_DISABLED
// For every vector, display it.
TabVector_IT it(&vectors_);
for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
TabVector* vector = it.data();
vector->Display(tab_win);
}
tab_win->Update();
#endif
return tab_win;
}

void tesseract::TabFind::DontFindTabVectors | ( | BLOBNBOX_LIST * | image_blobs,
|  | TO_BLOCK * | block,
|  | FCOORD * | deskew,
|  | FCOORD * | reskew
| ) |  |
| protected

Definition at line 480 of file tabfind.cpp.

{
InsertBlobsToGrid(false, false, image_blobs, this);
InsertBlobsToGrid(true, false, &block->blobs, this);
deskew->set_x(1.0f);
deskew->set_y(0.0f);
reskew->set_x(1.0f);
reskew->set_y(0.0f);
}

ScrollView * tesseract::TabFind::FindInitialTabVectors | ( | BLOBNBOX_LIST * | image_blobs,
|  | int | min_gutter_width,
|  | TO_BLOCK * | block
| ) |  |
| protected

Definition at line 542 of file tabfind.cpp.

{
if (textord_tabfind_show_initialtabs) {
ScrollView* line_win = MakeWindow(0, 0, "VerticalLines");
line_win = DisplayTabVectors(line_win);
}
// Prepare the grid.
if (image_blobs != NULL)
InsertBlobsToGrid(true, false, image_blobs, this);
InsertBlobsToGrid(true, false, &block->blobs, this);
ScrollView* initial_win = FindTabBoxes(min_gutter_width);
FindAllTabVectors(min_gutter_width);
TabVector::MergeSimilarTabVectors(vertical_skew_, &vectors_, this);
SortVectors();
EvaluateTabs();
if (textord_tabfind_show_initialtabs && initial_win != NULL)
initial_win = DisplayTabVectors(initial_win);
MarkVerticalText();
return initial_win;
}

bool tesseract::TabFind::FindTabVectors | ( | TabVector_LIST * | hlines,
|  | BLOBNBOX_LIST * | image_blobs,
|  | TO_BLOCK * | block,
|  | int | min_gutter_width,
|  | ColPartitionGrid * | part_grid,
|  | FCOORD * | deskew,
|  | FCOORD * | reskew
| ) |  |
| protected

Top-level function to find TabVectors in an input page block. Returns false if the detected skew angle is impossible. Applies the detected skew angle to deskew the tabs, blobs and part_grid.

Definition at line 447 of file tabfind.cpp.

{
ScrollView* tab_win = FindInitialTabVectors(image_blobs, min_gutter_width,
block);
ComputeColumnWidths(tab_win, part_grid);
TabVector::MergeSimilarTabVectors(vertical_skew_, &vectors_, this);
SortVectors();
CleanupTabs();
if (!Deskew(hlines, image_blobs, block, deskew, reskew))
return false; // Skew angle is too large.
part_grid->Deskew(*deskew);
ApplyTabConstraints();
#ifndef GRAPHICS_DISABLED
if (textord_tabfind_show_finaltabs) {
tab_win = MakeWindow(640, 50, "FinalTabs");
if (textord_debug_images) {
tab_win->Image(AlignedBlob::textord_debug_pix().string(),
image_origin_.x(), image_origin_.y());
} else {
DisplayBoxes(tab_win);
DisplayTabs("FinalTabs", tab_win);
}
tab_win = DisplayTabVectors(tab_win);
}
#endif // GRAPHICS_DISABLED
return true;
}

int tesseract::TabFind::GutterWidth | ( | int | bottom_y,
|  | int | top_y,
|  | const TabVector & | v,
|  | bool | ignore_unmergeables,
|  | int | max_gutter_width,
|  | int * | required_shift
| ) |  |

Definition at line 186 of file tabfind.cpp.

{
bool right_to_left = v.IsLeftTab();
int bottom_x = v.XAtY(bottom_y);
int top_x = v.XAtY(top_y);
int start_x = right_to_left ? MAX(top_x, bottom_x) : MIN(top_x, bottom_x);
BlobGridSearch sidesearch(this);
sidesearch.StartSideSearch(start_x, bottom_y, top_y);
int min_gap = max_gutter_width;
*required_shift = 0;
BLOBNBOX* blob = NULL;
while ((blob = sidesearch.NextSideSearch(right_to_left)) != NULL) {
const TBOX& box = blob->bounding_box();
if (box.bottom() >= top_y || box.top() <= bottom_y)
continue; // Doesn't overlap enough.
if (box.height() >= gridsize() * 2 &&
box.height() > box.width() * kLineFragmentAspectRatio) {
// Skip likely separator line residue.
continue;
}
if (ignore_unmergeables && BLOBNBOX::UnMergeableType(blob->region_type()))
continue; // Skip non-text if required.
int mid_y = (box.bottom() + box.top()) / 2;
// We use the x at the mid-y so that the required_shift guarantees
// to clear all the blobs on the tab-stop. If we use the min/max
// of x at top/bottom of the blob, then exactness would be required,
// which is not a good thing.
int tab_x = v.XAtY(mid_y);
int gap;
if (right_to_left) {
gap = tab_x - box.right();
if (gap < 0 && box.left() - tab_x < *required_shift)
*required_shift = box.left() - tab_x;
} else {
gap = box.left() - tab_x;
if (gap < 0 && box.right() - tab_x > *required_shift)
*required_shift = box.right() - tab_x;
}
if (gap > 0 && gap < min_gap)
min_gap = gap;
}
// Result may be negative, in which case, this is a really bad tabstop.
return min_gap - abs(*required_shift);
}

void tesseract::TabFind::GutterWidthAndNeighbourGap | ( | int | tab_x,
|  | int | mean_height,
|  | int | max_gutter,
|  | bool | left,
|  | BLOBNBOX * | bbox,
|  | int * | gutter_width,
|  | int * | neighbour_gap
| ) |  |

Find the gutter width and distance to inner neighbour for the given blob.

Definition at line 233 of file tabfind.cpp.

{
const TBOX& box = bbox->bounding_box();
// The gutter and internal sides of the box.
int gutter_x = left ? box.left() : box.right();
int internal_x = left ? box.right() : box.left();
// On ragged edges, the gutter side of the box is away from the tabstop.
int tab_gap = left ? gutter_x - tab_x : tab_x - gutter_x;
*gutter_width = max_gutter;
// If the box is away from the tabstop, we need to increase
// the allowed gutter width.
if (tab_gap > 0)
*gutter_width += tab_gap;
bool debug = WithinTestRegion(2, box.left(), box.bottom());
if (debug)
tprintf("Looking in gutter\n");
// Find the nearest blob on the outside of the column.
BLOBNBOX* gutter_bbox = AdjacentBlob(bbox, left,
bbox->flow() == BTFT_TEXT_ON_IMAGE, 0.0,
*gutter_width, box.top(), box.bottom());
if (gutter_bbox != NULL) {
TBOX gutter_box = gutter_bbox->bounding_box();
*gutter_width = left ? tab_x - gutter_box.right()
: gutter_box.left() - tab_x;
}
if (*gutter_width >= max_gutter) {
// If there is no box because a tab was in the way, get the tab coord.
TBOX gutter_box(box);
if (left) {
gutter_box.set_left(tab_x - max_gutter - 1);
gutter_box.set_right(tab_x - max_gutter);
int tab_gutter = RightEdgeForBox(gutter_box, true, false);
if (tab_gutter < tab_x - 1)
*gutter_width = tab_x - tab_gutter;
} else {
gutter_box.set_left(tab_x + max_gutter);
gutter_box.set_right(tab_x + max_gutter + 1);
int tab_gutter = LeftEdgeForBox(gutter_box, true, false);
if (tab_gutter > tab_x + 1)
*gutter_width = tab_gutter - tab_x;
}
}
if (*gutter_width > max_gutter)
*gutter_width = max_gutter;
// Now look for a neighbour on the inside.
if (debug)
tprintf("Looking for neighbour\n");
BLOBNBOX* neighbour = AdjacentBlob(bbox, !left,
bbox->flow() == BTFT_TEXT_ON_IMAGE, 0.0,
*gutter_width, box.top(), box.bottom());
int neighbour_edge = left ? RightEdgeForBox(box, true, false)
: LeftEdgeForBox(box, true, false);
if (neighbour != NULL) {
TBOX n_box = neighbour->bounding_box();
if (debug) {
tprintf("Found neighbour:");
n_box.print();
}
if (left && n_box.left() < neighbour_edge)
neighbour_edge = n_box.left();
else if (!left && n_box.right() > neighbour_edge)
neighbour_edge = n_box.right();
}
*neighbour_gap = left ? neighbour_edge - internal_x
: internal_x - neighbour_edge;
}

const ICOORD& tesseract::TabFind::image_origin | ( |  | ) | const
| inline

Return the coords at which to draw the image backdrop.

Definition at line 174 of file tabfind.h.

{
return image_origin_;
}

bool tesseract::TabFind::InsertBlob | ( | bool | h_spread,
|  | bool | v_spread,
|  | BLOBNBOX * | blob,
|  | BBGrid< BLOBNBOX, BLOBNBOX_CLIST, BLOBNBOX_C_IT > * | grid
| ) |  |

Insert a single blob into the given grid (not necessarily this). If h_spread, then all cells covered horizontally by the box are used, otherwise, just the bottom-left. Similarly for v_spread. A side effect is that the left and right rule edges of the blob are set according to the tab vectors in this (not grid).

Definition at line 143 of file tabfind.cpp.

{
TBOX box = blob->bounding_box();
blob->set_left_rule(LeftEdgeForBox(box, false, false));
blob->set_right_rule(RightEdgeForBox(box, false, false));
blob->set_left_crossing_rule(LeftEdgeForBox(box, true, false));
blob->set_right_crossing_rule(RightEdgeForBox(box, true, false));
if (blob->joined_to_prev())
return false;
grid->InsertBBox(h_spread, v_spread, blob);
return true;
}

void tesseract::TabFind::InsertBlobsToGrid | ( | bool | h_spread,
|  | bool | v_spread,
|  | BLOBNBOX_LIST * | blobs,
|  | BBGrid< BLOBNBOX, BLOBNBOX_CLIST, BLOBNBOX_C_IT > * | grid
| ) |  |

Insert a list of blobs into the given grid (not necessarily this). See InsertBlob for the other arguments. It would seem to make more sense to swap this and grid, but this way around allows grid to not be derived from TabFind, eg a ColPartitionGrid, while the grid that provides the tab stops(this) has to be derived from TabFind.

Definition at line 116 of file tabfind.cpp.

{
BLOBNBOX_IT blob_it(blobs);
int b_count = 0;
int reject_count = 0;
for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
BLOBNBOX* blob = blob_it.data();
// if (InsertBlob(true, true, blob, grid)) {
if (InsertBlob(h_spread, v_spread, blob, grid)) {
++b_count;
} else {
++reject_count;
}
}
if (textord_debug_tabfind) {
tprintf("Inserted %d blobs into grid, %d rejected.\n",
b_count, reject_count);
}
}

int tesseract::TabFind::LeftEdgeForBox | ( | const TBOX & | box,
|  | bool | crossing,
|  | bool | extended
| ) |  |

As RightEdgeForBox, but finds the left Edge instead.

Definition at line 311 of file tabfind.cpp.

{
TabVector* v = LeftTabForBox(box, crossing, extended);
return v == NULL ? bleft_.x() : v->XAtY((box.top() + box.bottom()) / 2);
}

TabVector * tesseract::TabFind::LeftTabForBox | ( | const TBOX & | box,
|  | bool | crossing,
|  | bool | extended
| ) |  |

As RightTabForBox, but finds the left TabVector instead.

Definition at line 373 of file tabfind.cpp.

{
if (v_it_.empty())
return NULL;
int top_y = box.top();
int bottom_y = box.bottom();
int mid_y = (top_y + bottom_y) / 2;
int left = crossing ? (box.left() + box.right()) / 2 : box.left();
int min_key, max_key;
SetupTabSearch(left, mid_y, &min_key, &max_key);
// Position the iterator at the last TabVector with sort_key <= max_key.
while (!v_it_.at_last() && v_it_.data()->sort_key() <= max_key)
v_it_.forward();
while (!v_it_.at_first() && v_it_.data()->sort_key() > max_key) {
v_it_.backward();
}
// Find the rightmost tab vector that overlaps and has XAtY(mid_y) <= left.
TabVector* best_v = NULL;
int best_x = -1;
int key_limit = -1;
do {
TabVector* v = v_it_.data();
int x = v->XAtY(mid_y);
if (x <= left &&
(v->VOverlap(top_y, bottom_y) > 0 ||
(extended && v->ExtendedOverlap(top_y, bottom_y) > 0))) {
if (best_v == NULL || x > best_x) {
best_v = v;
best_x = x;
// We can guarantee that no better vector can be found if the
// sort key is less than that of the best by max_key - min_key.
key_limit = v->sort_key() - (max_key - min_key);
}
}
// Break when the search is done to avoid wrapping the iterator and
// thereby potentially slowing the next search.
if (v_it_.at_first() ||
(best_v != NULL && v->sort_key() < key_limit))
break; // Prevent restarting list for next call.
v_it_.backward();
} while (!v_it_.at_last());
return best_v;
}

void tesseract::TabFind::ReflectInYAxis | ( |  | ) |
| protected

Definition at line 1385 of file tabfind.cpp.

{
TabVector_LIST temp_list;
TabVector_IT temp_it(&temp_list);
v_it_.move_to_first();
// The TabVector list only contains vertical lines, but they need to be
// reflected and the list needs to be reversed, so they are still in
// sort_key order.
while (!v_it_.empty()) {
TabVector* v = v_it_.extract();
v_it_.forward();
v->ReflectInYAxis();
temp_it.add_before_then_move(v);
}
v_it_.add_list_after(&temp_list);
v_it_.move_to_first();
// Reset this grid with reflected bounding boxes.
TBOX grid_box(bleft(), tright());
int tmp = grid_box.left();
grid_box.set_left(-grid_box.right());
grid_box.set_right(-tmp);
Init(gridsize(), grid_box.botleft(), grid_box.topright());
}

void tesseract::TabFind::Reset | ( |  | ) |
| protected

Definition at line 1374 of file tabfind.cpp.

{
v_it_.move_to_first();
for (v_it_.mark_cycle_pt(); !v_it_.cycled_list(); v_it_.forward()) {
if (!v_it_.data()->IsSeparator())
delete v_it_.extract();
}
Clear();
}

void tesseract::TabFind::ResetForVerticalText | ( | const FCOORD & | rotate,
|  | const FCOORD & | rerotate,
|  | TabVector_LIST * | horizontal_lines,
|  | int * | min_gutter_width
| ) |  |
| protected

Definition at line 1329 of file tabfind.cpp.

{
// Rotate the horizontal and vertical vectors and swap them over.
// Only the separators are kept and rotated; other tabs are used
// to estimate the gutter width then thrown away.
TabVector_LIST ex_verticals;
TabVector_IT ex_v_it(&ex_verticals);
TabVector_LIST vlines;
TabVector_IT v_it(&vlines);
while (!v_it_.empty()) {
TabVector* v = v_it_.extract();
if (v->IsSeparator()) {
v->Rotate(rotate);
ex_v_it.add_after_then_move(v);
} else {
v_it.add_after_then_move(v);
}
v_it_.forward();
}
// Adjust the min gutter width for better tabbox selection
// in 2nd call to FindInitialTabVectors().
int median_gutter = FindMedianGutterWidth(&vlines);
if (median_gutter > *min_gutter_width)
*min_gutter_width = median_gutter;
TabVector_IT h_it(horizontal_lines);
for (h_it.mark_cycle_pt(); !h_it.cycled_list(); h_it.forward()) {
TabVector* h = h_it.data();
h->Rotate(rotate);
}
v_it_.add_list_after(horizontal_lines);
v_it_.move_to_first();
h_it.set_to_list(horizontal_lines);
h_it.add_list_after(&ex_verticals);
// Rebuild the grid to the new size.
TBOX grid_box(bleft(), tright());
grid_box.rotate_large(rotate);
Init(gridsize(), grid_box.botleft(), grid_box.topright());
}

int tesseract::TabFind::RightEdgeForBox | ( | const TBOX & | box,
|  | bool | crossing,
|  | bool | extended
| ) |  |

Return the x-coord that corresponds to the right edge for the given box. If there is a rule line to the right that vertically overlaps it, then return the x-coord of the rule line, otherwise return the right edge of the page. For details see RightTabForBox below.

Definition at line 306 of file tabfind.cpp.

{
TabVector* v = RightTabForBox(box, crossing, extended);
return v == NULL ? tright_.x() : v->XAtY((box.top() + box.bottom()) / 2);
}

TabVector * tesseract::TabFind::RightTabForBox | ( | const TBOX & | box,
|  | bool | crossing,
|  | bool | extended
| ) |  |

Return the TabVector that corresponds to the right edge for the given box. If there is a TabVector to the right that vertically overlaps it, then return it, otherwise return NULL. Note that Right and Left refer to the position of the TabVector, not its type, ie RightTabForBox returns the nearest TabVector to the right of the box, regardless of its type. If a TabVector crosses right through the box (as opposed to grazing one edge or missing entirely), then crossing false will ignore such a line. Crossing true will return the line for BOTH left and right edges. If extended is true, then TabVectors are considered to extend to their extended_start/end_y, otherwise, just the startpt_ and endpt_. These functions make use of an internal iterator to the vectors_ list for speed when used repeatedly on neighbouring boxes. The caveat is that the iterator must be updated whenever the list is modified.

Definition at line 329 of file tabfind.cpp.

{
if (v_it_.empty())
return NULL;
int top_y = box.top();
int bottom_y = box.bottom();
int mid_y = (top_y + bottom_y) / 2;
int right = crossing ? (box.left() + box.right()) / 2 : box.right();
int min_key, max_key;
SetupTabSearch(right, mid_y, &min_key, &max_key);
// Position the iterator at the first TabVector with sort_key >= min_key.
while (!v_it_.at_first() && v_it_.data()->sort_key() >= min_key)
v_it_.backward();
while (!v_it_.at_last() && v_it_.data()->sort_key() < min_key)
v_it_.forward();
// Find the leftmost tab vector that overlaps and has XAtY(mid_y) >= right.
TabVector* best_v = NULL;
int best_x = -1;
int key_limit = -1;
do {
TabVector* v = v_it_.data();
int x = v->XAtY(mid_y);
if (x >= right &&
(v->VOverlap(top_y, bottom_y) > 0 ||
(extended && v->ExtendedOverlap(top_y, bottom_y) > 0))) {
if (best_v == NULL || x < best_x) {
best_v = v;
best_x = x;
// We can guarantee that no better vector can be found if the
// sort key exceeds that of the best by max_key - min_key.
key_limit = v->sort_key() + max_key - min_key;
}
}
// Break when the search is done to avoid wrapping the iterator and
// thereby potentially slowing the next search.
if (v_it_.at_last() ||
(best_v != NULL && v->sort_key() > key_limit))
break; // Prevent restarting list for next call.
v_it_.forward();
} while (!v_it_.at_first());
return best_v;
}

void tesseract::TabFind::RotateBlobList | ( | const FCOORD & | rotation,
|  | BLOBNBOX_LIST * | blobs
| ) |  |
| static protected

Definition at line 1259 of file tabfind.cpp.

{
BLOBNBOX_IT it(blobs);
for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
it.data()->rotate_box(rotation);
}
}

void tesseract::TabFind::SetBlobRuleEdges | ( | BLOBNBOX_LIST * | blobs | ) |

Definition at line 167 of file tabfind.cpp.

{
BLOBNBOX_IT blob_it(blobs);
for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
BLOBNBOX* blob = blob_it.data();
TBOX box = blob->bounding_box();
blob->set_left_rule(LeftEdgeForBox(box, false, false));
blob->set_right_rule(RightEdgeForBox(box, false, false));
blob->set_left_crossing_rule(LeftEdgeForBox(box, true, false));
blob->set_right_crossing_rule(RightEdgeForBox(box, true, false));
}
}

void tesseract::TabFind::SetBlockRuleEdges | ( | TO_BLOCK * | block | ) |

Definition at line 158 of file tabfind.cpp.

{
SetBlobRuleEdges(&block->blobs);
SetBlobRuleEdges(&block->small_blobs);
SetBlobRuleEdges(&block->noise_blobs);
SetBlobRuleEdges(&block->large_blobs);
}

void tesseract::TabFind::SetupTabSearch | ( | int | x,
|  | int | y,
|  | int * | min_key,
|  | int * | max_key
| ) |  |
| protected

Definition at line 518 of file tabfind.cpp.

{
int key1 = TabVector::SortKey(vertical_skew_, x, (y + tright_.y()) / 2);
int key2 = TabVector::SortKey(vertical_skew_, x, (y + bleft_.y()) / 2);
*min_key = MIN(key1, key2);
*max_key = MAX(key1, key2);
}

void tesseract::TabFind::TidyBlobs | ( | TO_BLOCK * | block | ) |
| protected

Definition at line 493 of file tabfind.cpp.

{
BLOBNBOX_IT large_it = &block->large_blobs;
BLOBNBOX_IT blob_it = &block->blobs;
int b_count = 0;
for (large_it.mark_cycle_pt(); !large_it.cycled_list(); large_it.forward()) {
BLOBNBOX* large_blob = large_it.data();
if (large_blob->owner() != NULL) {
blob_it.add_to_end(large_it.extract());
++b_count;
}
}
if (textord_debug_tabfind) {
tprintf("Moved %d large blobs to normal list\n",
b_count);
#ifndef GRAPHICS_DISABLED
ScrollView* rej_win = MakeWindow(500, 300, "Image blobs");
block->plot_graded_blobs(rej_win);
block->plot_noise_blobs(rej_win);
rej_win->Update();
#endif // GRAPHICS_DISABLED
}
block->DeleteUnownedNoise();
}

TabVector_LIST* tesseract::TabFind::vectors | ( |  | ) |
| inline protected

Accessors

Definition at line 182 of file tabfind.h.

{
return &vectors_;
}

bool tesseract::TabFind::VeryDifferentSizes | ( | int | size1,
|  | int | size2
| ) |  |
| static

Return true if the sizes are more than a factor of 5 different.

Definition at line 438 of file tabfind.cpp.

{
return size1 > size2 * 5 || size2 > size1 * 5;
}

WidthCallback* tesseract::TabFind::WidthCB | ( |  | ) |
| inline

Return a callback for testing CommonWidth.

Definition at line 167 of file tabfind.h.

{
return width_cb_;
}

## Member Data Documentation

int tesseract::TabFind::resolution_
| protected

Definition at line 360 of file tabfind.h.

ICOORD tesseract::TabFind::vertical_skew_
| protected

Definition at line 359 of file tabfind.h.

The documentation for this class was generated from the following files:

- /mnt/data/src/tesseract-ocr/textord/tabfind.h
- /mnt/data/src/tesseract-ocr/textord/tabfind.cpp