Tesseract  3.02
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
tesseract::TableRecognizer Class Reference

#include <tablerecog.h>

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

tesseract::TableRecognizer::TableRecognizer ( )

Definition at line 698 of file tablerecog.cpp.

699  : text_grid_(NULL),
700  line_grid_(NULL),
701  min_height_(0),
702  min_width_(0),
704 }
ColPartitionGrid * line_grid_
Definition: tablerecog.h:368
ColPartitionGrid * text_grid_
Definition: tablerecog.h:367
#define NULL
Definition: host.h:144
#define MAX_INT32
Definition: host.h:120
tesseract::TableRecognizer::~TableRecognizer ( )

Definition at line 706 of file tablerecog.cpp.

706  {
707 }

Member Function Documentation

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

Definition at line 807 of file tablerecog.cpp.

807  {
808  // The first iteration will tell us if there are lines
809  // present and shrink the box to a minimal iterative size.
810  if (!FindLinesBoundingBoxIteration(bounding_box))
811  return false;
812 
813  // Keep growing until the area of the table stabilizes.
814  // The box can only get bigger, increasing area.
815  bool changed = true;
816  while (changed) {
817  changed = false;
818  int old_area = bounding_box->area();
819  bool check = FindLinesBoundingBoxIteration(bounding_box);
820  // At this point, the function will return true.
821  ASSERT_HOST(check);
822  ASSERT_HOST(bounding_box->area() >= old_area);
823  changed = (bounding_box->area() > old_area);
824  }
825 
826  return true;
827 }
inT32 area() const
Definition: rect.h:111
bool FindLinesBoundingBoxIteration(TBOX *bounding_box)
Definition: tablerecog.cpp:829
#define ASSERT_HOST(x)
Definition: errcode.h:84
bool tesseract::TableRecognizer::FindLinesBoundingBoxIteration ( TBOX bounding_box)
protected

Definition at line 829 of file tablerecog.cpp.

829  {
830  // Search for all of the lines in the current box, keeping track of extents.
832  box_search.SetUniqueMode(true);
833  box_search.StartRectSearch(*bounding_box);
834  ColPartition* line = NULL;
835  bool first_line = true;
836 
837  while ((line = box_search.NextRectSearch()) != NULL) {
838  if (line->IsLineType()) {
839  if (first_line) {
840  // The first iteration can shrink the box.
841  *bounding_box = line->bounding_box();
842  first_line = false;
843  } else {
844  *bounding_box += line->bounding_box();
845  }
846  }
847  }
848  return !first_line;
849 }
ColPartitionGrid * line_grid_
Definition: tablerecog.h:368
#define NULL
Definition: host.h:144
GridSearch< ColPartition, ColPartition_CLIST, ColPartition_C_IT > ColPartitionGridSearch
Definition: colpartition.h:895
bool tesseract::TableRecognizer::HasSignificantLines ( const TBOX guess)
protected

Definition at line 768 of file tablerecog.cpp.

768  {
770  box_search.SetUniqueMode(true);
771  box_search.StartRectSearch(guess);
772  ColPartition* line = NULL;
773  int vertical_count = 0;
774  int horizontal_count = 0;
775 
776  while ((line = box_search.NextRectSearch()) != NULL) {
777  if (line->IsHorizontalLine())
778  ++horizontal_count;
779  if (line->IsVerticalLine())
780  ++vertical_count;
781  }
782 
783  return vertical_count >= kLinedTableMinVerticalLines &&
784  horizontal_count >= kLinedTableMinHorizontalLines;
785 }
const int kLinedTableMinVerticalLines
Definition: tablerecog.cpp:38
ColPartitionGrid * line_grid_
Definition: tablerecog.h:368
const int kLinedTableMinHorizontalLines
Definition: tablerecog.cpp:39
#define NULL
Definition: host.h:144
GridSearch< ColPartition, ColPartition_CLIST, ColPartition_C_IT > ColPartitionGridSearch
Definition: colpartition.h:895
void tesseract::TableRecognizer::Init ( )

Definition at line 709 of file tablerecog.cpp.

709  {
710 }
bool tesseract::TableRecognizer::IsWeakTableRow ( StructuredTable table,
int  row 
)
staticprotected

Definition at line 1045 of file tablerecog.cpp.

1045  {
1046  if (!table->VerifyRowFilled(row))
1047  return false;
1048 
1049  double threshold = 0.0;
1050  if (table->column_count() > kGoodRowNumberOfColumnsSmallSize)
1051  threshold = table->column_count() * kGoodRowNumberOfColumnsLarge;
1052  else
1053  threshold = kGoodRowNumberOfColumnsSmall[table->column_count()];
1054 
1055  return table->CountFilledCellsInRow(row) < threshold;
1056 }
const int kGoodRowNumberOfColumnsSmallSize
Definition: tablerecog.cpp:51
const double kGoodRowNumberOfColumnsSmall[]
Definition: tablerecog.cpp:50
const double kGoodRowNumberOfColumnsLarge
Definition: tablerecog.cpp:54
int tesseract::TableRecognizer::NextHorizontalSplit ( int  left,
int  right,
int  y,
bool  top_to_bottom 
)
protected

Definition at line 1011 of file tablerecog.cpp.

1012  {
1014  gsearch.SetUniqueMode(true);
1015  gsearch.StartVerticalSearch(left, right, y);
1016  ColPartition* text = NULL;
1017  int last_y = y;
1018  while ((text = gsearch.NextVerticalSearch(top_to_bottom)) != NULL) {
1019  if (!text->IsTextType() || !text->IsHorizontalType())
1020  continue;
1021  if (text->bounding_box().height() > max_text_height_)
1022  continue;
1023 
1024  const TBOX& text_box = text->bounding_box();
1025  if (top_to_bottom && (last_y >= y || last_y <= text_box.top())) {
1026  last_y = MIN(last_y, text_box.bottom());
1027  continue;
1028  }
1029  if (!top_to_bottom && (last_y <= y || last_y >= text_box.bottom())) {
1030  last_y = MAX(last_y, text_box.top());
1031  continue;
1032  }
1033 
1034  return last_y;
1035  }
1036  // If none is found, we at least want to preserve the min/max,
1037  // which defines the overlap of y with the last partition in the grid.
1038  return last_y;
1039 }
ColPartitionGrid * text_grid_
Definition: tablerecog.h:367
#define NULL
Definition: host.h:144
Definition: rect.h:29
GridSearch< ColPartition, ColPartition_CLIST, ColPartition_C_IT > ColPartitionGridSearch
Definition: colpartition.h:895
inT16 top() const
Definition: rect.h:53
#define MIN(x, y)
Definition: ndminx.h:28
#define MAX(x, y)
Definition: ndminx.h:24
inT16 bottom() const
Definition: rect.h:60
bool tesseract::TableRecognizer::RecognizeLinedTable ( const TBOX guess_box,
StructuredTable table 
)
protected

Definition at line 751 of file tablerecog.cpp.

752  {
753  if (!HasSignificantLines(guess_box))
754  return false;
755  TBOX line_bound = guess_box;
756  if (!FindLinesBoundingBox(&line_bound))
757  return false;
758  table->set_bounding_box(line_bound);
759  return table->FindLinedStructure();
760 }
Definition: rect.h:29
bool HasSignificantLines(const TBOX &guess)
Definition: tablerecog.cpp:768
bool FindLinesBoundingBox(TBOX *bounding_box)
Definition: tablerecog.cpp:807
StructuredTable * tesseract::TableRecognizer::RecognizeTable ( const TBOX guess_box)

Definition at line 728 of file tablerecog.cpp.

728  {
729  StructuredTable* table = new StructuredTable();
730  table->Init();
731  table->set_text_grid(text_grid_);
732  table->set_line_grid(line_grid_);
733  table->set_max_text_height(max_text_height_);
734 
735  // Try to solve ths simple case, a table with *both*
736  // vertical and horizontal lines.
737  if (RecognizeLinedTable(guess, table))
738  return table;
739 
740  // Fallback to whitespace if that failed.
741  // TODO(nbeato): Break this apart to take advantage of horizontal
742  // lines or vertical lines when present.
743  if (RecognizeWhitespacedTable(guess, table))
744  return table;
745 
746  // No table found...
747  delete table;
748  return NULL;
749 }
ColPartitionGrid * line_grid_
Definition: tablerecog.h:368
bool RecognizeLinedTable(const TBOX &guess_box, StructuredTable *table)
Definition: tablerecog.cpp:751
ColPartitionGrid * text_grid_
Definition: tablerecog.h:367
#define NULL
Definition: host.h:144
bool RecognizeWhitespacedTable(const TBOX &guess_box, StructuredTable *table)
Definition: tablerecog.cpp:867
bool tesseract::TableRecognizer::RecognizeWhitespacedTable ( const TBOX guess_box,
StructuredTable table 
)
protected

Definition at line 867 of file tablerecog.cpp.

868  {
869  TBOX best_box = guess_box; // Best borders known.
870  int best_below = 0; // Margin size above best table.
871  int best_above = 0; // Margin size below best table.
872  TBOX adjusted = guess_box; // The search box.
873 
874  // We assume that the guess box is somewhat accurate, so we don't allow
875  // the adjusted border to pass half of the guessed area. This prevents
876  // "negative" tables from forming.
877  const int kMidGuessY = (guess_box.bottom() + guess_box.top()) / 2;
878  // Keeps track of the most columns in an accepted table. The resulting table
879  // may be less than the max, but we don't want to stray too far.
880  int best_cols = 0;
881  // Make sure we find a good border.
882  bool found_good_border = false;
883 
884  // Find the bottom of the table by trying a few different locations. For
885  // each location, the top, left, and right are fixed. We start the search
886  // in a smaller table to favor best_cols getting a good estimate sooner.
887  int last_bottom = MAX_INT32;
888  int bottom = NextHorizontalSplit(guess_box.left(), guess_box.right(),
889  kMidGuessY - min_height_ / 2, true);
890  int top = NextHorizontalSplit(guess_box.left(), guess_box.right(),
891  kMidGuessY + min_height_ / 2, false);
892  adjusted.set_top(top);
893 
894  // Headers/footers can be spaced far from everything.
895  // Make sure that the space below is greater than the space above
896  // the lowest row.
897  int previous_below = 0;
898  const int kMaxChances = 10;
899  int chances = kMaxChances;
900  while (bottom != last_bottom) {
901  adjusted.set_bottom(bottom);
902 
903  if (adjusted.height() >= min_height_) {
904  // Try to fit the grid on the current box. We give it a chance
905  // if the number of columns didn't significantly drop.
906  table->set_bounding_box(adjusted);
907  if (table->FindWhitespacedStructure() &&
908  table->column_count() >= best_cols * kRequiredColumns) {
909  if (false && IsWeakTableRow(table, 0)) {
910  // Currently buggy, but was looking promising so disabled.
911  --chances;
912  } else {
913  // We favor 2 things,
914  // 1- Adding rows that have partitioned data.
915  // 2- Better margins (to find header/footer).
916  // For better tables, we just look for multiple cells in the
917  // bottom row with data in them.
918  // For margins, the space below the last row should
919  // be better than a table with the last row removed.
920  chances = kMaxChances;
921  double max_row_height = kMaxRowSize * table->median_cell_height();
922  if ((table->space_below() * kMarginFactor >= best_below &&
923  table->space_below() >= previous_below) ||
924  (table->CountFilledCellsInRow(0) > 1 &&
925  table->row_height(0) < max_row_height)) {
926  best_box.set_bottom(bottom);
927  best_below = table->space_below();
928  best_cols = MAX(table->column_count(), best_cols);
929  found_good_border = true;
930  }
931  }
932  previous_below = table->space_below();
933  } else {
934  --chances;
935  }
936  }
937  if (chances <= 0)
938  break;
939 
940  last_bottom = bottom;
941  bottom = NextHorizontalSplit(guess_box.left(), guess_box.right(),
942  last_bottom, true);
943  }
944  if (!found_good_border)
945  return false;
946 
947  // TODO(nbeato) comments: follow modified code above... put it in a function!
948  found_good_border = false;
949  int last_top = MIN_INT32;
950  top = NextHorizontalSplit(guess_box.left(), guess_box.right(),
951  kMidGuessY + min_height_ / 2, false);
952  int previous_above = 0;
953  chances = kMaxChances;
954 
955  adjusted.set_bottom(best_box.bottom());
956  while (last_top != top) {
957  adjusted.set_top(top);
958  if (adjusted.height() >= min_height_) {
959  table->set_bounding_box(adjusted);
960  if (table->FindWhitespacedStructure() &&
961  table->column_count() >= best_cols * kRequiredColumns) {
962  int last_row = table->row_count() - 1;
963  if (false && IsWeakTableRow(table, last_row)) {
964  // Currently buggy, but was looking promising so disabled.
965  --chances;
966  } else {
967  chances = kMaxChances;
968  double max_row_height = kMaxRowSize * table->median_cell_height();
969  if ((table->space_above() * kMarginFactor >= best_above &&
970  table->space_above() >= previous_above) ||
971  (table->CountFilledCellsInRow(last_row) > 1 &&
972  table->row_height(last_row) < max_row_height)) {
973  best_box.set_top(top);
974  best_above = table->space_above();
975  best_cols = MAX(table->column_count(), best_cols);
976  found_good_border = true;
977  }
978  }
979  previous_above = table->space_above();
980  } else {
981  --chances;
982  }
983  }
984  if (chances <= 0)
985  break;
986 
987  last_top = top;
988  top = NextHorizontalSplit(guess_box.left(), guess_box.right(),
989  last_top, false);
990  }
991 
992  if (!found_good_border)
993  return false;
994 
995  // If we get here, this shouldn't happen. It can be an assert, but
996  // I haven't tested it enough to make it crash things.
997  if (best_box.null_box())
998  return false;
999 
1000  // Given the best locations, fit the box to those locations.
1001  table->set_bounding_box(best_box);
1002  return table->FindWhitespacedStructure();
1003 }
bool null_box() const
Definition: rect.h:45
inT16 left() const
Definition: rect.h:67
Definition: rect.h:29
int NextHorizontalSplit(int left, int right, int y, bool top_to_bottom)
inT16 right() const
Definition: rect.h:74
#define MAX_INT32
Definition: host.h:120
const double kMarginFactor
Definition: tablerecog.cpp:44
const double kRequiredColumns
Definition: tablerecog.cpp:42
inT16 top() const
Definition: rect.h:53
static bool IsWeakTableRow(StructuredTable *table, int row)
#define MAX(x, y)
Definition: ndminx.h:24
void set_bottom(int y)
Definition: rect.h:63
const double kMaxRowSize
Definition: tablerecog.cpp:47
void set_top(int y)
Definition: rect.h:56
inT16 height() const
Definition: rect.h:97
#define MIN_INT32
Definition: host.h:128
inT16 bottom() const
Definition: rect.h:60
void tesseract::TableRecognizer::set_line_grid ( ColPartitionGrid lines)

Definition at line 715 of file tablerecog.cpp.

715  {
716  line_grid_ = line_grid;
717 }
ColPartitionGrid * line_grid_
Definition: tablerecog.h:368
void tesseract::TableRecognizer::set_max_text_height ( int  height)

Definition at line 724 of file tablerecog.cpp.

724  {
725  max_text_height_ = height;
726 }
void tesseract::TableRecognizer::set_min_height ( int  height)

Definition at line 718 of file tablerecog.cpp.

718  {
719  min_height_ = height;
720 }
void tesseract::TableRecognizer::set_min_width ( int  width)

Definition at line 721 of file tablerecog.cpp.

721  {
722  min_width_ = width;
723 }
void tesseract::TableRecognizer::set_text_grid ( ColPartitionGrid text)

Definition at line 712 of file tablerecog.cpp.

712  {
713  text_grid_ = text_grid;
714 }
ColPartitionGrid * text_grid_
Definition: tablerecog.h:367

Member Data Documentation

ColPartitionGrid* tesseract::TableRecognizer::line_grid_
protected

Definition at line 368 of file tablerecog.h.

int tesseract::TableRecognizer::max_text_height_
protected

Definition at line 373 of file tablerecog.h.

int tesseract::TableRecognizer::min_height_
protected

Definition at line 370 of file tablerecog.h.

int tesseract::TableRecognizer::min_width_
protected

Definition at line 371 of file tablerecog.h.

ColPartitionGrid* tesseract::TableRecognizer::text_grid_
protected

Definition at line 367 of file tablerecog.h.


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