tesseract  3.03
tesseract::TableRecognizer Class Reference

#include <tablerecog.h>

List of all members.

Public Member Functions

 TableRecognizer ()
 ~TableRecognizer ()
void Init ()
void set_text_grid (ColPartitionGrid *text)
void set_line_grid (ColPartitionGrid *lines)
void set_min_height (int height)
void set_min_width (int width)
void set_max_text_height (int height)
StructuredTableRecognizeTable (const TBOX &guess_box)

Protected Member Functions

bool RecognizeLinedTable (const TBOX &guess_box, StructuredTable *table)
bool HasSignificantLines (const TBOX &guess)
bool FindLinesBoundingBox (TBOX *bounding_box)
bool FindLinesBoundingBoxIteration (TBOX *bounding_box)
bool RecognizeWhitespacedTable (const TBOX &guess_box, StructuredTable *table)
int NextHorizontalSplit (int left, int right, int y, bool top_to_bottom)

Static Protected Member Functions

static bool IsWeakTableRow (StructuredTable *table, int row)

Protected Attributes

ColPartitionGridtext_grid_
ColPartitionGridline_grid_
int min_height_
int min_width_
int max_text_height_

Detailed Description

Definition at line 257 of file tablerecog.h.


Constructor & Destructor Documentation


Member Function Documentation

bool tesseract::TableRecognizer::FindLinesBoundingBox ( TBOX bounding_box) [protected]

Definition at line 811 of file tablerecog.cpp.

                                                             {
  // The first iteration will tell us if there are lines
  // present and shrink the box to a minimal iterative size.
  if (!FindLinesBoundingBoxIteration(bounding_box))
    return false;

  // Keep growing until the area of the table stabilizes.
  // The box can only get bigger, increasing area.
  bool changed = true;
  while (changed) {
    changed = false;
    int old_area = bounding_box->area();
    bool check = FindLinesBoundingBoxIteration(bounding_box);
    // At this point, the function will return true.
    ASSERT_HOST(check);
    ASSERT_HOST(bounding_box->area() >= old_area);
    changed = (bounding_box->area() > old_area);
  }

  return true;
}

Definition at line 833 of file tablerecog.cpp.

                                                                      {
  // Search for all of the lines in the current box, keeping track of extents.
  ColPartitionGridSearch box_search(line_grid_);
  box_search.SetUniqueMode(true);
  box_search.StartRectSearch(*bounding_box);
  ColPartition* line = NULL;
  bool first_line = true;

  while ((line = box_search.NextRectSearch()) != NULL) {
    if (line->IsLineType()) {
      if (first_line) {
        // The first iteration can shrink the box.
        *bounding_box = line->bounding_box();
        first_line = false;
      } else {
        *bounding_box += line->bounding_box();
      }
    }
  }
  return !first_line;
}
bool tesseract::TableRecognizer::HasSignificantLines ( const TBOX guess) [protected]

Definition at line 772 of file tablerecog.cpp.

                                                           {
  ColPartitionGridSearch box_search(line_grid_);
  box_search.SetUniqueMode(true);
  box_search.StartRectSearch(guess);
  ColPartition* line = NULL;
  int vertical_count = 0;
  int horizontal_count = 0;

  while ((line = box_search.NextRectSearch()) != NULL) {
    if (line->IsHorizontalLine())
      ++horizontal_count;
    if (line->IsVerticalLine())
      ++vertical_count;
  }

  return vertical_count >= kLinedTableMinVerticalLines &&
         horizontal_count >= kLinedTableMinHorizontalLines;
}

Definition at line 713 of file tablerecog.cpp.

                           {
}
bool tesseract::TableRecognizer::IsWeakTableRow ( StructuredTable table,
int  row 
) [static, protected]

Definition at line 1049 of file tablerecog.cpp.

                                                                    {
  if (!table->VerifyRowFilled(row))
    return false;

  double threshold = 0.0;
  if (table->column_count() > kGoodRowNumberOfColumnsSmallSize)
    threshold = table->column_count() * kGoodRowNumberOfColumnsLarge;
  else
    threshold = kGoodRowNumberOfColumnsSmall[table->column_count()];

  return table->CountFilledCellsInRow(row) < threshold;
}
int tesseract::TableRecognizer::NextHorizontalSplit ( int  left,
int  right,
int  y,
bool  top_to_bottom 
) [protected]

Definition at line 1015 of file tablerecog.cpp.

                                                             {
  ColPartitionGridSearch gsearch(text_grid_);
  gsearch.SetUniqueMode(true);
  gsearch.StartVerticalSearch(left, right, y);
  ColPartition* text = NULL;
  int last_y = y;
  while ((text = gsearch.NextVerticalSearch(top_to_bottom)) != NULL) {
    if (!text->IsTextType() || !text->IsHorizontalType())
      continue;
    if (text->bounding_box().height() > max_text_height_)
      continue;

    const TBOX& text_box = text->bounding_box();
    if (top_to_bottom && (last_y >= y || last_y <= text_box.top())) {
      last_y = MIN(last_y, text_box.bottom());
      continue;
    }
    if (!top_to_bottom && (last_y <= y || last_y >= text_box.bottom())) {
      last_y = MAX(last_y, text_box.top());
      continue;
    }

    return last_y;
  }
  // If none is found, we at least want to preserve the min/max,
  // which defines the overlap of y with the last partition in the grid.
  return last_y;
}
bool tesseract::TableRecognizer::RecognizeLinedTable ( const TBOX guess_box,
StructuredTable table 
) [protected]

Definition at line 755 of file tablerecog.cpp.

                                                                  {
  if (!HasSignificantLines(guess_box))
    return false;
  TBOX line_bound = guess_box;
  if (!FindLinesBoundingBox(&line_bound))
    return false;
  table->set_bounding_box(line_bound);
  return table->FindLinedStructure();
}

Definition at line 732 of file tablerecog.cpp.

                                                                  {
  StructuredTable* table = new StructuredTable();
  table->Init();
  table->set_text_grid(text_grid_);
  table->set_line_grid(line_grid_);
  table->set_max_text_height(max_text_height_);

  // Try to solve ths simple case, a table with *both*
  // vertical and horizontal lines.
  if (RecognizeLinedTable(guess, table))
    return table;

  // Fallback to whitespace if that failed.
  // TODO(nbeato): Break this apart to take advantage of horizontal
  // lines or vertical lines when present.
  if (RecognizeWhitespacedTable(guess, table))
    return table;

  // No table found...
  delete table;
  return NULL;
}
bool tesseract::TableRecognizer::RecognizeWhitespacedTable ( const TBOX guess_box,
StructuredTable table 
) [protected]

Definition at line 871 of file tablerecog.cpp.

                                                                        {
  TBOX best_box = guess_box;  // Best borders known.
  int best_below = 0;         // Margin size above best table.
  int best_above = 0;         // Margin size below best table.
  TBOX adjusted = guess_box;  // The search box.

  // We assume that the guess box is somewhat accurate, so we don't allow
  // the adjusted border to pass half of the guessed area. This prevents
  // "negative" tables from forming.
  const int kMidGuessY = (guess_box.bottom() + guess_box.top()) / 2;
  // Keeps track of the most columns in an accepted table. The resulting table
  // may be less than the max, but we don't want to stray too far.
  int best_cols = 0;
  // Make sure we find a good border.
  bool found_good_border = false;

  // Find the bottom of the table by trying a few different locations. For
  // each location, the top, left, and right are fixed. We start the search
  // in a smaller table to favor best_cols getting a good estimate sooner.
  int last_bottom = MAX_INT32;
  int bottom = NextHorizontalSplit(guess_box.left(), guess_box.right(),
                                   kMidGuessY - min_height_ / 2, true);
  int top = NextHorizontalSplit(guess_box.left(), guess_box.right(),
                                kMidGuessY + min_height_ / 2, false);
  adjusted.set_top(top);

  // Headers/footers can be spaced far from everything.
  // Make sure that the space below is greater than the space above
  // the lowest row.
  int previous_below = 0;
  const int kMaxChances = 10;
  int chances = kMaxChances;
  while (bottom != last_bottom) {
    adjusted.set_bottom(bottom);

    if (adjusted.height() >= min_height_) {
      // Try to fit the grid on the current box. We give it a chance
      // if the number of columns didn't significantly drop.
      table->set_bounding_box(adjusted);
      if (table->FindWhitespacedStructure() &&
          table->column_count() >= best_cols * kRequiredColumns) {
        if (false && IsWeakTableRow(table, 0)) {
          // Currently buggy, but was looking promising so disabled.
          --chances;
        } else {
          // We favor 2 things,
          //   1- Adding rows that have partitioned data.
          //   2- Better margins (to find header/footer).
          // For better tables, we just look for multiple cells in the
          // bottom row with data in them.
          // For margins, the space below the last row should
          // be better than a table with the last row removed.
          chances = kMaxChances;
          double max_row_height = kMaxRowSize * table->median_cell_height();
          if ((table->space_below() * kMarginFactor >= best_below &&
               table->space_below() >= previous_below) ||
              (table->CountFilledCellsInRow(0) > 1 &&
               table->row_height(0) < max_row_height)) {
            best_box.set_bottom(bottom);
            best_below = table->space_below();
            best_cols = MAX(table->column_count(), best_cols);
            found_good_border = true;
          }
        }
        previous_below = table->space_below();
      } else {
       --chances;
      }
    }
    if (chances <= 0)
      break;

    last_bottom = bottom;
    bottom = NextHorizontalSplit(guess_box.left(), guess_box.right(),
                                 last_bottom, true);
  }
  if (!found_good_border)
    return false;

  // TODO(nbeato) comments: follow modified code above... put it in a function!
  found_good_border = false;
  int last_top = MIN_INT32;
  top = NextHorizontalSplit(guess_box.left(), guess_box.right(),
                            kMidGuessY + min_height_ / 2, false);
  int previous_above = 0;
  chances = kMaxChances;

  adjusted.set_bottom(best_box.bottom());
  while (last_top != top) {
    adjusted.set_top(top);
    if (adjusted.height() >= min_height_) {
      table->set_bounding_box(adjusted);
      if (table->FindWhitespacedStructure() &&
          table->column_count() >= best_cols * kRequiredColumns) {
        int last_row = table->row_count() - 1;
        if (false && IsWeakTableRow(table, last_row)) {
          // Currently buggy, but was looking promising so disabled.
          --chances;
        } else {
          chances = kMaxChances;
          double max_row_height = kMaxRowSize * table->median_cell_height();
          if ((table->space_above() * kMarginFactor >= best_above &&
               table->space_above() >= previous_above) ||
              (table->CountFilledCellsInRow(last_row) > 1 &&
               table->row_height(last_row) < max_row_height)) {
            best_box.set_top(top);
            best_above = table->space_above();
            best_cols = MAX(table->column_count(), best_cols);
            found_good_border = true;
          }
        }
        previous_above = table->space_above();
      } else {
       --chances;
      }
    }
    if (chances <= 0)
      break;

    last_top = top;
    top = NextHorizontalSplit(guess_box.left(), guess_box.right(),
                              last_top, false);
  }

  if (!found_good_border)
    return false;

  // If we get here, this shouldn't happen. It can be an assert, but
  // I haven't tested it enough to make it crash things.
  if (best_box.null_box())
    return false;

  // Given the best locations, fit the box to those locations.
  table->set_bounding_box(best_box);
  return table->FindWhitespacedStructure();
}

Definition at line 719 of file tablerecog.cpp.

                                                               {
  line_grid_ = line_grid;
}

Definition at line 728 of file tablerecog.cpp.

                                                    {
  max_text_height_ = height;
}

Definition at line 722 of file tablerecog.cpp.

                                               {
  min_height_ = height;
}

Definition at line 725 of file tablerecog.cpp.

                                             {
  min_width_ = width;
}

Definition at line 716 of file tablerecog.cpp.

                                                               {
  text_grid_ = text_grid;
}

Member Data Documentation

Definition at line 368 of file tablerecog.h.

Definition at line 373 of file tablerecog.h.

Definition at line 370 of file tablerecog.h.

Definition at line 371 of file tablerecog.h.

Definition at line 367 of file tablerecog.h.


The documentation for this class was generated from the following files:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines