tesseract  4.00.00dev
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

◆ TableRecognizer()

tesseract::TableRecognizer::TableRecognizer ( )

Definition at line 706 of file tablerecog.cpp.

707  : text_grid_(NULL),
708  line_grid_(NULL),
709  min_height_(0),
710  min_width_(0),
712 }
#define MAX_INT32
Definition: host.h:62
ColPartitionGrid * line_grid_
Definition: tablerecog.h:368
ColPartitionGrid * text_grid_
Definition: tablerecog.h:367

◆ ~TableRecognizer()

tesseract::TableRecognizer::~TableRecognizer ( )

Definition at line 714 of file tablerecog.cpp.

714  {
715 }

Member Function Documentation

◆ FindLinesBoundingBox()

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

Definition at line 815 of file tablerecog.cpp.

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

◆ FindLinesBoundingBoxIteration()

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

Definition at line 837 of file tablerecog.cpp.

837  {
838  // Search for all of the lines in the current box, keeping track of extents.
840  box_search.SetUniqueMode(true);
841  box_search.StartRectSearch(*bounding_box);
842  ColPartition* line = NULL;
843  bool first_line = true;
844 
845  while ((line = box_search.NextRectSearch()) != NULL) {
846  if (line->IsLineType()) {
847  if (first_line) {
848  // The first iteration can shrink the box.
849  *bounding_box = line->bounding_box();
850  first_line = false;
851  } else {
852  *bounding_box += line->bounding_box();
853  }
854  }
855  }
856  return !first_line;
857 }
GridSearch< ColPartition, ColPartition_CLIST, ColPartition_C_IT > ColPartitionGridSearch
Definition: colpartition.h:932
ColPartitionGrid * line_grid_
Definition: tablerecog.h:368

◆ HasSignificantLines()

bool tesseract::TableRecognizer::HasSignificantLines ( const TBOX guess)
protected

Definition at line 776 of file tablerecog.cpp.

776  {
778  box_search.SetUniqueMode(true);
779  box_search.StartRectSearch(guess);
780  ColPartition* line = NULL;
781  int vertical_count = 0;
782  int horizontal_count = 0;
783 
784  while ((line = box_search.NextRectSearch()) != NULL) {
785  if (line->IsHorizontalLine())
786  ++horizontal_count;
787  if (line->IsVerticalLine())
788  ++vertical_count;
789  }
790 
791  return vertical_count >= kLinedTableMinVerticalLines &&
792  horizontal_count >= kLinedTableMinHorizontalLines;
793 }
GridSearch< ColPartition, ColPartition_CLIST, ColPartition_C_IT > ColPartitionGridSearch
Definition: colpartition.h:932
const int kLinedTableMinHorizontalLines
Definition: tablerecog.cpp:43
const int kLinedTableMinVerticalLines
Definition: tablerecog.cpp:42
ColPartitionGrid * line_grid_
Definition: tablerecog.h:368

◆ Init()

void tesseract::TableRecognizer::Init ( )

Definition at line 717 of file tablerecog.cpp.

717  {
718 }

◆ IsWeakTableRow()

bool tesseract::TableRecognizer::IsWeakTableRow ( StructuredTable table,
int  row 
)
staticprotected

Definition at line 1053 of file tablerecog.cpp.

1053  {
1054  if (!table->VerifyRowFilled(row))
1055  return false;
1056 
1057  double threshold = 0.0;
1058  if (table->column_count() > kGoodRowNumberOfColumnsSmallSize)
1059  threshold = table->column_count() * kGoodRowNumberOfColumnsLarge;
1060  else
1061  threshold = kGoodRowNumberOfColumnsSmall[table->column_count()];
1062 
1063  return table->CountFilledCellsInRow(row) < threshold;
1064 }
const double kGoodRowNumberOfColumnsSmall[]
Definition: tablerecog.cpp:54
const double kGoodRowNumberOfColumnsLarge
Definition: tablerecog.cpp:58
const int kGoodRowNumberOfColumnsSmallSize
Definition: tablerecog.cpp:55

◆ NextHorizontalSplit()

int tesseract::TableRecognizer::NextHorizontalSplit ( int  left,
int  right,
int  y,
bool  top_to_bottom 
)
protected

Definition at line 1019 of file tablerecog.cpp.

1020  {
1022  gsearch.SetUniqueMode(true);
1023  gsearch.StartVerticalSearch(left, right, y);
1024  ColPartition* text = NULL;
1025  int last_y = y;
1026  while ((text = gsearch.NextVerticalSearch(top_to_bottom)) != NULL) {
1027  if (!text->IsTextType() || !text->IsHorizontalType())
1028  continue;
1029  if (text->bounding_box().height() > max_text_height_)
1030  continue;
1031 
1032  const TBOX& text_box = text->bounding_box();
1033  if (top_to_bottom && (last_y >= y || last_y <= text_box.top())) {
1034  last_y = MIN(last_y, text_box.bottom());
1035  continue;
1036  }
1037  if (!top_to_bottom && (last_y <= y || last_y >= text_box.bottom())) {
1038  last_y = MAX(last_y, text_box.top());
1039  continue;
1040  }
1041 
1042  return last_y;
1043  }
1044  // If none is found, we at least want to preserve the min/max,
1045  // which defines the overlap of y with the last partition in the grid.
1046  return last_y;
1047 }
GridSearch< ColPartition, ColPartition_CLIST, ColPartition_C_IT > ColPartitionGridSearch
Definition: colpartition.h:932
inT16 top() const
Definition: rect.h:54
#define MAX(x, y)
Definition: ndminx.h:24
Definition: rect.h:30
#define MIN(x, y)
Definition: ndminx.h:28
inT16 bottom() const
Definition: rect.h:61
ColPartitionGrid * text_grid_
Definition: tablerecog.h:367

◆ RecognizeLinedTable()

bool tesseract::TableRecognizer::RecognizeLinedTable ( const TBOX guess_box,
StructuredTable table 
)
protected

Definition at line 759 of file tablerecog.cpp.

760  {
761  if (!HasSignificantLines(guess_box))
762  return false;
763  TBOX line_bound = guess_box;
764  if (!FindLinesBoundingBox(&line_bound))
765  return false;
766  table->set_bounding_box(line_bound);
767  return table->FindLinedStructure();
768 }
bool FindLinesBoundingBox(TBOX *bounding_box)
Definition: tablerecog.cpp:815
Definition: rect.h:30
bool HasSignificantLines(const TBOX &guess)
Definition: tablerecog.cpp:776

◆ RecognizeTable()

StructuredTable * tesseract::TableRecognizer::RecognizeTable ( const TBOX guess_box)

Definition at line 736 of file tablerecog.cpp.

736  {
737  StructuredTable* table = new StructuredTable();
738  table->Init();
739  table->set_text_grid(text_grid_);
740  table->set_line_grid(line_grid_);
741  table->set_max_text_height(max_text_height_);
742 
743  // Try to solve this simple case, a table with *both*
744  // vertical and horizontal lines.
745  if (RecognizeLinedTable(guess, table))
746  return table;
747 
748  // Fallback to whitespace if that failed.
749  // TODO(nbeato): Break this apart to take advantage of horizontal
750  // lines or vertical lines when present.
751  if (RecognizeWhitespacedTable(guess, table))
752  return table;
753 
754  // No table found...
755  delete table;
756  return NULL;
757 }
bool RecognizeLinedTable(const TBOX &guess_box, StructuredTable *table)
Definition: tablerecog.cpp:759
bool RecognizeWhitespacedTable(const TBOX &guess_box, StructuredTable *table)
Definition: tablerecog.cpp:875
ColPartitionGrid * line_grid_
Definition: tablerecog.h:368
ColPartitionGrid * text_grid_
Definition: tablerecog.h:367

◆ RecognizeWhitespacedTable()

bool tesseract::TableRecognizer::RecognizeWhitespacedTable ( const TBOX guess_box,
StructuredTable table 
)
protected

Definition at line 875 of file tablerecog.cpp.

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

◆ set_line_grid()

void tesseract::TableRecognizer::set_line_grid ( ColPartitionGrid lines)

Definition at line 723 of file tablerecog.cpp.

723  {
724  line_grid_ = line_grid;
725 }
ColPartitionGrid * line_grid_
Definition: tablerecog.h:368

◆ set_max_text_height()

void tesseract::TableRecognizer::set_max_text_height ( int  height)

Definition at line 732 of file tablerecog.cpp.

732  {
733  max_text_height_ = height;
734 }

◆ set_min_height()

void tesseract::TableRecognizer::set_min_height ( int  height)

Definition at line 726 of file tablerecog.cpp.

726  {
727  min_height_ = height;
728 }

◆ set_min_width()

void tesseract::TableRecognizer::set_min_width ( int  width)

Definition at line 729 of file tablerecog.cpp.

729  {
730  min_width_ = width;
731 }

◆ set_text_grid()

void tesseract::TableRecognizer::set_text_grid ( ColPartitionGrid text)

Definition at line 720 of file tablerecog.cpp.

720  {
721  text_grid_ = text_grid;
722 }
ColPartitionGrid * text_grid_
Definition: tablerecog.h:367

Member Data Documentation

◆ line_grid_

ColPartitionGrid* tesseract::TableRecognizer::line_grid_
protected

Definition at line 368 of file tablerecog.h.

◆ max_text_height_

int tesseract::TableRecognizer::max_text_height_
protected

Definition at line 373 of file tablerecog.h.

◆ min_height_

int tesseract::TableRecognizer::min_height_
protected

Definition at line 370 of file tablerecog.h.

◆ min_width_

int tesseract::TableRecognizer::min_width_
protected

Definition at line 371 of file tablerecog.h.

◆ text_grid_

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: