tesseract  5.0.0-alpha-619-ge9db
alignedblob.cpp
Go to the documentation of this file.
1 // File: alignedblob.cpp
3 // Description: Subclass of BBGrid to find vertically aligned blobs.
4 // Author: Ray Smith
5 //
6 // (C) Copyright 2008, Google Inc.
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
18 
19 #ifdef HAVE_CONFIG_H
20 #include "config_auto.h"
21 #endif
22 
23 #include "alignedblob.h"
24 
25 #include <algorithm>
26 
27 INT_VAR(textord_debug_tabfind, 0, "Debug tab finding");
28 INT_VAR(textord_debug_bugs, 0, "Turn on output related to bugs in tab finding");
29 static INT_VAR(textord_testregion_left, -1, "Left edge of debug reporting rectangle");
30 static INT_VAR(textord_testregion_top, -1, "Top edge of debug reporting rectangle");
31 static INT_VAR(textord_testregion_right, INT32_MAX, "Right edge of debug rectangle");
32 static INT_VAR(textord_testregion_bottom, INT32_MAX, "Bottom edge of debug rectangle");
33 BOOL_VAR(textord_debug_printable, false, "Make debug windows printable");
34 
35 namespace tesseract {
36 
37 // Fraction of resolution used as alignment tolerance for aligned tabs.
38 const double kAlignedFraction = 0.03125;
39 // Fraction of resolution used as alignment tolerance for ragged tabs.
40 const double kRaggedFraction = 2.5;
41 // Fraction of height used as a minimum gutter gap for aligned blobs.
42 const double kAlignedGapFraction = 0.75;
43 // Fraction of height used as a minimum gutter gap for ragged tabs.
44 const double kRaggedGapFraction = 1.0;
45 // Constant number of pixels used as alignment tolerance for line finding.
46 const int kVLineAlignment = 3;
47 // Constant number of pixels used as gutter gap tolerance for line finding.
48 const int kVLineGutter = 1;
49 // Constant number of pixels used as the search size for line finding.
50 const int kVLineSearchSize = 150;
51 // Min number of points to accept for a ragged tab stop.
52 const int kMinRaggedTabs = 5;
53 // Min number of points to accept for an aligned tab stop.
54 const int kMinAlignedTabs = 4;
55 // Constant number of pixels minimum height of a vertical line.
56 const int kVLineMinLength = 500;
57 // Minimum gradient for a vertical tab vector. Used to prune away junk
58 // tab vectors with what would be a ridiculously large skew angle.
59 // Value corresponds to tan(90 - max allowed skew angle)
60 const double kMinTabGradient = 4.0;
61 // Tolerance to skew on top of current estimate of skew. Divide x or y length
62 // by kMaxSkewFactor to get the y or x skew distance.
63 // If the angle is small, the angle in degrees is roughly 60/kMaxSkewFactor.
64 const int kMaxSkewFactor = 15;
65 
66 // Constructor to set the parameters for finding aligned and ragged tabs.
67 // Vertical_x and vertical_y are the current estimates of the true vertical
68 // direction (up) in the image. Height is the height of the starter blob.
69 // v_gap_multiple is the multiple of height that will be used as a limit
70 // on vertical gap before giving up and calling the line ended.
71 // resolution is the original image resolution, and align0 indicates the
72 // type of tab stop to be found.
73 AlignedBlobParams::AlignedBlobParams(int vertical_x, int vertical_y,
74  int height, int v_gap_multiple,
75  int min_gutter_width,
76  int resolution, TabAlignment align0)
77  : right_tab(align0 == TA_RIGHT_RAGGED || align0 == TA_RIGHT_ALIGNED),
78  ragged(align0 == TA_LEFT_RAGGED || align0 == TA_RIGHT_RAGGED),
79  alignment(align0),
80  confirmed_type(TT_CONFIRMED),
81  min_length(0) {
82  // Set the tolerances according to the type of line sought.
83  // For tab search, these are based on the image resolution for most, or
84  // the height of the starting blob for the maximum vertical gap.
85  max_v_gap = height * v_gap_multiple;
86  if (ragged) {
87  // In the case of a ragged edge, we are much more generous with the
88  // inside alignment fraction, but also require a much bigger gutter.
90  if (alignment == TA_RIGHT_RAGGED) {
91  l_align_tolerance = static_cast<int>(resolution * kRaggedFraction + 0.5);
92  r_align_tolerance = static_cast<int>(resolution * kAlignedFraction + 0.5);
93  } else {
94  l_align_tolerance = static_cast<int>(resolution * kAlignedFraction + 0.5);
95  r_align_tolerance = static_cast<int>(resolution * kRaggedFraction + 0.5);
96  }
98  } else {
100  l_align_tolerance = static_cast<int>(resolution * kAlignedFraction + 0.5);
101  r_align_tolerance = static_cast<int>(resolution * kAlignedFraction + 0.5);
103  }
104  min_gutter = static_cast<int>(height * gutter_fraction + 0.5);
105  if (min_gutter < min_gutter_width)
106  min_gutter = min_gutter_width;
107  // Fit the vertical vector into an ICOORD, which is 16 bit.
108  set_vertical(vertical_x, vertical_y);
109 }
110 
111 // Constructor to set the parameters for finding vertical lines.
112 // Vertical_x and vertical_y are the current estimates of the true vertical
113 // direction (up) in the image. Width is the width of the starter blob.
114 AlignedBlobParams::AlignedBlobParams(int vertical_x, int vertical_y,
115  int width)
116  : gutter_fraction(0.0),
117  right_tab(false),
118  ragged(false),
119  alignment(TA_SEPARATOR),
120  confirmed_type(TT_VLINE),
121  max_v_gap(kVLineSearchSize),
122  min_gutter(kVLineGutter),
123  min_points(1),
124  min_length(kVLineMinLength) {
125  // Compute threshold for left and right alignment.
126  l_align_tolerance = std::max(kVLineAlignment, width);
127  r_align_tolerance = std::max(kVLineAlignment, width);
128 
129  // Fit the vertical vector into an ICOORD, which is 16 bit.
130  set_vertical(vertical_x, vertical_y);
131 }
132 
133 // Fit the vertical vector into an ICOORD, which is 16 bit.
134 void AlignedBlobParams::set_vertical(int vertical_x, int vertical_y) {
135  int factor = 1;
136  if (vertical_y > INT16_MAX)
137  factor = vertical_y / INT16_MAX + 1;
138  vertical.set_x(vertical_x / factor);
139  vertical.set_y(vertical_y / factor);
140 }
141 
142 
144  const ICOORD& bleft, const ICOORD& tright)
145  : BlobGrid(gridsize, bleft, tright) {
146 }
147 
148 // Return true if the given coordinates are within the test rectangle
149 // and the debug level is at least the given detail level.
150 bool AlignedBlob::WithinTestRegion(int detail_level, int x, int y) {
151  if (textord_debug_tabfind < detail_level)
152  return false;
153  return x >= textord_testregion_left && x <= textord_testregion_right &&
154  y <= textord_testregion_top && y >= textord_testregion_bottom;
155 }
156 
157 // Display the tab codes of the BLOBNBOXes in this grid.
158 ScrollView* AlignedBlob::DisplayTabs(const char* window_name,
159  ScrollView* tab_win) {
160 #ifndef GRAPHICS_DISABLED
161  if (tab_win == nullptr)
162  tab_win = MakeWindow(0, 50, window_name);
163  // For every tab in the grid, display it.
165  gsearch.StartFullSearch();
166  BLOBNBOX* bbox;
167  while ((bbox = gsearch.NextFullSearch()) != nullptr) {
168  const TBOX& box = bbox->bounding_box();
169  int left_x = box.left();
170  int right_x = box.right();
171  int top_y = box.top();
172  int bottom_y = box.bottom();
173  TabType tabtype = bbox->left_tab_type();
174  if (tabtype != TT_NONE) {
175  if (tabtype == TT_MAYBE_ALIGNED)
176  tab_win->Pen(ScrollView::BLUE);
177  else if (tabtype == TT_MAYBE_RAGGED)
178  tab_win->Pen(ScrollView::YELLOW);
179  else if (tabtype == TT_CONFIRMED)
180  tab_win->Pen(ScrollView::GREEN);
181  else
182  tab_win->Pen(ScrollView::GREY);
183  tab_win->Line(left_x, top_y, left_x, bottom_y);
184  }
185  tabtype = bbox->right_tab_type();
186  if (tabtype != TT_NONE) {
187  if (tabtype == TT_MAYBE_ALIGNED)
188  tab_win->Pen(ScrollView::MAGENTA);
189  else if (tabtype == TT_MAYBE_RAGGED)
190  tab_win->Pen(ScrollView::ORANGE);
191  else if (tabtype == TT_CONFIRMED)
192  tab_win->Pen(ScrollView::RED);
193  else
194  tab_win->Pen(ScrollView::GREY);
195  tab_win->Line(right_x, top_y, right_x, bottom_y);
196  }
197  }
198  tab_win->Update();
199 #endif
200  return tab_win;
201 }
202 
203 // Helper returns true if the total number of line_crossings of all the blobs
204 // in the list is at least 2.
205 static bool AtLeast2LineCrossings(BLOBNBOX_CLIST* blobs) {
206  BLOBNBOX_C_IT it(blobs);
207  int total_crossings = 0;
208  for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
209  total_crossings += it.data()->line_crossings();
210  }
211  return total_crossings >= 2;
212 }
213 
214 // Destructor.
215 // It is defined here, so the compiler can create a single vtable
216 // instead of weak vtables in every compilation unit.
217 AlignedBlob::~AlignedBlob() = default;
218 
219 // Finds a vector corresponding to a set of vertically aligned blob edges
220 // running through the given box. The type of vector returned and the
221 // search parameters are determined by the AlignedBlobParams.
222 // vertical_x and y are updated with an estimate of the real
223 // vertical direction. (skew finding.)
224 // Returns nullptr if no decent vector can be found.
226  BLOBNBOX* bbox,
227  int* vertical_x,
228  int* vertical_y) {
229  int ext_start_y, ext_end_y;
230  BLOBNBOX_CLIST good_points;
231  // Search up and then down from the starting bbox.
232  TBOX box = bbox->bounding_box();
233  bool debug = WithinTestRegion(2, box.left(), box.bottom());
234  int pt_count = AlignTabs(align_params, false, bbox, &good_points, &ext_end_y);
235  pt_count += AlignTabs(align_params, true, bbox, &good_points, &ext_start_y);
236  BLOBNBOX_C_IT it(&good_points);
237  it.move_to_last();
238  box = it.data()->bounding_box();
239  int end_y = box.top();
240  int end_x = align_params.right_tab ? box.right() : box.left();
241  it.move_to_first();
242  box = it.data()->bounding_box();
243  int start_x = align_params.right_tab ? box.right() : box.left();
244  int start_y = box.bottom();
245  // Acceptable tab vectors must have a minimum number of points,
246  // have a minimum acceptable length, and have a minimum gradient.
247  // The gradient corresponds to the skew angle.
248  // Ragged tabs don't need to satisfy the gradient condition, as they
249  // will always end up parallel to the vertical direction.
250  bool at_least_2_crossings = AtLeast2LineCrossings(&good_points);
251  if ((pt_count >= align_params.min_points &&
252  end_y - start_y >= align_params.min_length &&
253  (align_params.ragged ||
254  end_y - start_y >= abs(end_x - start_x) * kMinTabGradient)) ||
255  at_least_2_crossings) {
256  int confirmed_points = 0;
257  // Count existing confirmed points to see if vector is acceptable.
258  for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
259  bbox = it.data();
260  if (align_params.right_tab) {
261  if (bbox->right_tab_type() == align_params.confirmed_type)
262  ++confirmed_points;
263  } else {
264  if (bbox->left_tab_type() == align_params.confirmed_type)
265  ++confirmed_points;
266  }
267  }
268  // Ragged vectors are not allowed to use too many already used points.
269  if (!align_params.ragged ||
270  confirmed_points + confirmed_points < pt_count) {
271  const TBOX& box = bbox->bounding_box();
272  if (debug) {
273  tprintf("Confirming tab vector of %d pts starting at %d,%d\n",
274  pt_count, box.left(), box.bottom());
275  }
276  // Flag all the aligned neighbours as confirmed .
277  for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
278  bbox = it.data();
279  if (align_params.right_tab) {
280  bbox->set_right_tab_type(align_params.confirmed_type);
281  } else {
282  bbox->set_left_tab_type(align_params.confirmed_type);
283  }
284  if (debug) {
285  bbox->bounding_box().print();
286  }
287  }
288  // Now make the vector and return it.
289  TabVector* result = TabVector::FitVector(align_params.alignment,
290  align_params.vertical,
291  ext_start_y, ext_end_y,
292  &good_points,
293  vertical_x, vertical_y);
294  result->set_intersects_other_lines(at_least_2_crossings);
295  if (debug) {
296  tprintf("Box was %d, %d\n", box.left(), box.bottom());
297  result->Print("After fitting");
298  }
299  return result;
300  } else if (debug) {
301  tprintf("Ragged tab used too many used points: %d out of %d\n",
302  confirmed_points, pt_count);
303  }
304  } else if (debug) {
305  tprintf("Tab vector failed basic tests: pt count %d vs min %d, "
306  "length %d vs min %d, min grad %g\n",
307  pt_count, align_params.min_points, end_y - start_y,
308  align_params.min_length, abs(end_x - start_x) * kMinTabGradient);
309  }
310  return nullptr;
311 }
312 
313 // Find a set of blobs that are aligned in the given vertical
314 // direction with the given blob. Returns a list of aligned
315 // blobs and the number in the list.
316 // For other parameters see FindAlignedBlob below.
317 int AlignedBlob::AlignTabs(const AlignedBlobParams& params,
318  bool top_to_bottom, BLOBNBOX* bbox,
319  BLOBNBOX_CLIST* good_points, int* end_y) {
320  int ptcount = 0;
321  BLOBNBOX_C_IT it(good_points);
322 
323  TBOX box = bbox->bounding_box();
324  bool debug = WithinTestRegion(2, box.left(), box.bottom());
325  if (debug) {
326  tprintf("Starting alignment run at blob:");
327  box.print();
328  }
329  int x_start = params.right_tab ? box.right() : box.left();
330  while (bbox != nullptr) {
331  // Add the blob to the list if the appropriate side is a tab candidate,
332  // or if we are working on a ragged tab.
333  TabType type = params.right_tab ? bbox->right_tab_type()
334  : bbox->left_tab_type();
335  if (((type != TT_NONE && type != TT_MAYBE_RAGGED) || params.ragged) &&
336  (it.empty() || it.data() != bbox)) {
337  if (top_to_bottom)
338  it.add_before_then_move(bbox);
339  else
340  it.add_after_then_move(bbox);
341  ++ptcount;
342  }
343  // Find the next blob that is aligned with the current one.
344  // FindAlignedBlob guarantees that forward progress will be made in the
345  // top_to_bottom direction, and therefore eventually it will return nullptr,
346  // making this while (bbox != nullptr) loop safe.
347  bbox = FindAlignedBlob(params, top_to_bottom, bbox, x_start, end_y);
348  if (bbox != nullptr) {
349  box = bbox->bounding_box();
350  if (!params.ragged)
351  x_start = params.right_tab ? box.right() : box.left();
352  }
353  }
354  if (debug) {
355  tprintf("Alignment run ended with %d pts at blob:", ptcount);
356  box.print();
357  }
358  return ptcount;
359 }
360 
361 // Search vertically for a blob that is aligned with the input bbox.
362 // The search parameters are determined by AlignedBlobParams.
363 // top_to_bottom tells whether to search down or up.
364 // The return value is nullptr if nothing was found in the search box
365 // or if a blob was found in the gutter. On a nullptr return, end_y
366 // is set to the edge of the search box or the leading edge of the
367 // gutter blob if one was found.
368 BLOBNBOX* AlignedBlob::FindAlignedBlob(const AlignedBlobParams& p,
369  bool top_to_bottom, BLOBNBOX* bbox,
370  int x_start, int* end_y) {
371  TBOX box = bbox->bounding_box();
372  // If there are separator lines, get the column edges.
373  int left_column_edge = bbox->left_rule();
374  int right_column_edge = bbox->right_rule();
375  // start_y is used to guarantee that forward progress is made and the
376  // search does not go into an infinite loop. New blobs must extend the
377  // line beyond start_y.
378  int start_y = top_to_bottom ? box.bottom() : box.top();
379  if (WithinTestRegion(2, x_start, start_y)) {
380  tprintf("Column edges for blob at (%d,%d)->(%d,%d) are [%d, %d]\n",
381  box.left(), box.top(), box.right(), box.bottom(),
382  left_column_edge, right_column_edge);
383  }
384  // Compute skew tolerance.
385  int skew_tolerance = p.max_v_gap / kMaxSkewFactor;
386  // Calculate xmin and xmax of the search box so that it contains
387  // all possibly relevant boxes up to p.max_v_gap above or below according
388  // to top_to_bottom.
389  // Start with a notion of vertical with the current estimate.
390  int x2 = (p.max_v_gap * p.vertical.x() + p.vertical.y()/2) / p.vertical.y();
391  if (top_to_bottom) {
392  x2 = x_start - x2;
393  *end_y = start_y - p.max_v_gap;
394  } else {
395  x2 = x_start + x2;
396  *end_y = start_y + p.max_v_gap;
397  }
398  // Expand the box by an additional skew tolerance
399  int xmin = std::min(x_start, x2) - skew_tolerance;
400  int xmax = std::max(x_start, x2) + skew_tolerance;
401  // Now add direction-specific tolerances.
402  if (p.right_tab) {
403  xmax += p.min_gutter;
404  xmin -= p.l_align_tolerance;
405  } else {
406  xmax += p.r_align_tolerance;
407  xmin -= p.min_gutter;
408  }
409  // Setup a vertical search for an aligned blob.
410  GridSearch<BLOBNBOX, BLOBNBOX_CLIST, BLOBNBOX_C_IT> vsearch(this);
411  if (WithinTestRegion(2, x_start, start_y))
412  tprintf("Starting %s %s search at %d-%d,%d, search_size=%d, gutter=%d\n",
413  p.ragged ? "Ragged" : "Aligned", p.right_tab ? "Right" : "Left",
414  xmin, xmax, start_y, p.max_v_gap, p.min_gutter);
415  vsearch.StartVerticalSearch(xmin, xmax, start_y);
416  // result stores the best real return value.
417  BLOBNBOX* result = nullptr;
418  // The backup_result is not a tab candidate and can be used if no
419  // real tab candidate result is found.
420  BLOBNBOX* backup_result = nullptr;
421  // neighbour is the blob that is currently being investigated.
422  BLOBNBOX* neighbour = nullptr;
423  while ((neighbour = vsearch.NextVerticalSearch(top_to_bottom)) != nullptr) {
424  if (neighbour == bbox)
425  continue;
426  TBOX nbox = neighbour->bounding_box();
427  int n_y = (nbox.top() + nbox.bottom()) / 2;
428  if ((!top_to_bottom && n_y > start_y + p.max_v_gap) ||
429  (top_to_bottom && n_y < start_y - p.max_v_gap)) {
430  if (WithinTestRegion(2, x_start, start_y))
431  tprintf("Neighbour too far at (%d,%d)->(%d,%d)\n",
432  nbox.left(), nbox.bottom(), nbox.right(), nbox.top());
433  break; // Gone far enough.
434  }
435  // It is CRITICAL to ensure that forward progress is made, (strictly
436  // in/decreasing n_y) or the caller could loop infinitely, while
437  // waiting for a sequence of blobs in a line to end.
438  // NextVerticalSearch alone does not guarantee this, as there may be
439  // more than one blob in a grid cell. See comment in AlignTabs.
440  if ((n_y < start_y) != top_to_bottom || nbox.y_overlap(box))
441  continue; // Only look in the required direction.
442  if (result != nullptr && result->bounding_box().y_gap(nbox) > gridsize())
443  return result; // This result is clear.
444  if (backup_result != nullptr && p.ragged && result == nullptr &&
445  backup_result->bounding_box().y_gap(nbox) > gridsize())
446  return backup_result; // This result is clear.
447 
448  // If the neighbouring blob is the wrong side of a separator line, then it
449  // "doesn't exist" as far as we are concerned.
450  int x_at_n_y = x_start + (n_y - start_y) * p.vertical.x() / p.vertical.y();
451  if (x_at_n_y < neighbour->left_crossing_rule() ||
452  x_at_n_y > neighbour->right_crossing_rule())
453  continue; // Separator line in the way.
454  int n_left = nbox.left();
455  int n_right = nbox.right();
456  int n_x = p.right_tab ? n_right : n_left;
457  if (WithinTestRegion(2, x_start, start_y))
458  tprintf("neighbour at (%d,%d)->(%d,%d), n_x=%d, n_y=%d, xatn=%d\n",
459  nbox.left(), nbox.bottom(), nbox.right(), nbox.top(),
460  n_x, n_y, x_at_n_y);
461  if (p.right_tab &&
462  n_left < x_at_n_y + p.min_gutter &&
463  n_right > x_at_n_y + p.r_align_tolerance &&
464  (p.ragged || n_left < x_at_n_y + p.gutter_fraction * nbox.height())) {
465  // In the gutter so end of line.
466  if (bbox->right_tab_type() >= TT_MAYBE_ALIGNED)
468  *end_y = top_to_bottom ? nbox.top() : nbox.bottom();
469  if (WithinTestRegion(2, x_start, start_y))
470  tprintf("gutter\n");
471  return nullptr;
472  }
473  if (!p.right_tab &&
474  n_left < x_at_n_y - p.l_align_tolerance &&
475  n_right > x_at_n_y - p.min_gutter &&
476  (p.ragged || n_right > x_at_n_y - p.gutter_fraction * nbox.height())) {
477  // In the gutter so end of line.
478  if (bbox->left_tab_type() >= TT_MAYBE_ALIGNED)
480  *end_y = top_to_bottom ? nbox.top() : nbox.bottom();
481  if (WithinTestRegion(2, x_start, start_y))
482  tprintf("gutter\n");
483  return nullptr;
484  }
485  if ((p.right_tab && neighbour->leader_on_right()) ||
486  (!p.right_tab && neighbour->leader_on_left()))
487  continue; // Neighbours of leaders are not allowed to be used.
488  if (n_x <= x_at_n_y + p.r_align_tolerance &&
489  n_x >= x_at_n_y - p.l_align_tolerance) {
490  // Aligned so keep it. If it is a marked tab save it as result,
491  // otherwise keep it as backup_result to return in case of later failure.
492  if (WithinTestRegion(2, x_start, start_y))
493  tprintf("aligned, seeking%d, l=%d, r=%d\n",
494  p.right_tab, neighbour->left_tab_type(),
495  neighbour->right_tab_type());
496  TabType n_type = p.right_tab ? neighbour->right_tab_type()
497  : neighbour->left_tab_type();
498  if (n_type != TT_NONE && (p.ragged || n_type != TT_MAYBE_RAGGED)) {
499  if (result == nullptr) {
500  result = neighbour;
501  } else {
502  // Keep the closest neighbour by Euclidean distance.
503  // This prevents it from picking a tab blob in another column.
504  const TBOX& old_box = result->bounding_box();
505  int x_diff = p.right_tab ? old_box.right() : old_box.left();
506  x_diff -= x_at_n_y;
507  int y_diff = (old_box.top() + old_box.bottom()) / 2 - start_y;
508  int old_dist = x_diff * x_diff + y_diff * y_diff;
509  x_diff = n_x - x_at_n_y;
510  y_diff = n_y - start_y;
511  int new_dist = x_diff * x_diff + y_diff * y_diff;
512  if (new_dist < old_dist)
513  result = neighbour;
514  }
515  } else if (backup_result == nullptr) {
516  if (WithinTestRegion(2, x_start, start_y))
517  tprintf("Backup\n");
518  backup_result = neighbour;
519  } else {
520  TBOX backup_box = backup_result->bounding_box();
521  if ((p.right_tab && backup_box.right() < nbox.right()) ||
522  (!p.right_tab && backup_box.left() > nbox.left())) {
523  if (WithinTestRegion(2, x_start, start_y))
524  tprintf("Better backup\n");
525  backup_result = neighbour;
526  }
527  }
528  }
529  }
530  return result != nullptr ? result : backup_result;
531 }
532 
533 } // namespace tesseract.
ScrollView::GREY
Definition: scrollview.h:133
TabType
TabType
Definition: blobbox.h:58
tesseract::TA_LEFT_RAGGED
Definition: tabvector.h:46
ScrollView
Definition: scrollview.h:97
INT_VAR
#define INT_VAR(name, val, comment)
Definition: params.h:300
BLOBNBOX::set_right_tab_type
void set_right_tab_type(TabType new_type)
Definition: blobbox.h:279
ICOORD::set_x
void set_x(int16_t xin)
rewrite function
Definition: points.h:60
tesseract::kAlignedFraction
const double kAlignedFraction
Definition: alignedblob.cpp:38
tesseract::TA_SEPARATOR
Definition: tabvector.h:50
tesseract::TabVector
Definition: tabvector.h:111
tesseract::AlignedBlob::~AlignedBlob
~AlignedBlob() override
tesseract::TabVector::FitVector
static TabVector * FitVector(TabAlignment alignment, ICOORD vertical, int extended_start_y, int extended_end_y, BLOBNBOX_CLIST *good_points, int *vertical_x, int *vertical_y)
Definition: tabvector.cpp:176
tesseract::BBGrid< BLOBNBOX, BLOBNBOX_CLIST, BLOBNBOX_C_IT >::MakeWindow
ScrollView * MakeWindow(int x, int y, const char *window_name)
Definition: bbgrid.h:589
tesseract::AlignedBlobParams::min_gutter
int min_gutter
Definition: alignedblob.h:67
TT_NONE
Definition: blobbox.h:59
tesseract::AlignedBlobParams::min_points
int min_points
Definition: alignedblob.h:72
tesseract::TabVector::Print
void Print(const char *prefix)
Definition: tabvector.cpp:517
ICOORD
integer coordinate
Definition: points.h:30
BLOBNBOX::leader_on_left
bool leader_on_left() const
Definition: blobbox.h:357
TBOX::print
void print() const
Definition: rect.h:277
tesseract::GridSearch::StartFullSearch
void StartFullSearch()
Definition: bbgrid.h:665
TBOX::top
int16_t top() const
Definition: rect.h:57
tesseract::BlobGrid
Definition: blobgrid.h:33
tesseract::kMinTabGradient
const double kMinTabGradient
Definition: alignedblob.cpp:60
BLOBNBOX::right_rule
int right_rule() const
Definition: blobbox.h:318
tesseract::TA_RIGHT_ALIGNED
Definition: tabvector.h:48
TT_CONFIRMED
Definition: blobbox.h:63
ScrollView::Pen
void Pen(Color color)
Definition: scrollview.cpp:717
tesseract::kAlignedGapFraction
const double kAlignedGapFraction
Definition: alignedblob.cpp:42
tesseract::TabVector::set_intersects_other_lines
void set_intersects_other_lines(bool value)
Definition: tabvector.h:181
TT_MAYBE_ALIGNED
Definition: blobbox.h:62
BLOBNBOX
Definition: blobbox.h:142
ScrollView::BLUE
Definition: scrollview.h:108
BLOBNBOX::set_left_tab_type
void set_left_tab_type(TabType new_type)
Definition: blobbox.h:273
ICOORD::set_y
void set_y(int16_t yin)
rewrite function
Definition: points.h:64
TBOX::height
int16_t height() const
Definition: rect.h:107
TBOX::y_overlap
bool y_overlap(const TBOX &box) const
Definition: rect.h:418
TBOX::y_gap
int y_gap(const TBOX &box) const
Definition: rect.h:232
textord_debug_bugs
int textord_debug_bugs
Definition: alignedblob.cpp:28
BLOBNBOX::left_rule
int left_rule() const
Definition: blobbox.h:312
tesseract::kRaggedGapFraction
const double kRaggedGapFraction
Definition: alignedblob.cpp:44
BLOBNBOX::leader_on_right
bool leader_on_right() const
Definition: blobbox.h:363
tesseract::AlignedBlobParams::AlignedBlobParams
AlignedBlobParams(int vertical_x, int vertical_y, int height, int v_gap_multiple, int min_gutter_width, int resolution, TabAlignment alignment0)
Definition: alignedblob.cpp:73
ScrollView::ORANGE
Definition: scrollview.h:136
textord_debug_printable
bool textord_debug_printable
Definition: alignedblob.cpp:33
tesseract::AlignedBlob::FindVerticalAlignment
TabVector * FindVerticalAlignment(AlignedBlobParams align_params, BLOBNBOX *bbox, int *vertical_x, int *vertical_y)
Definition: alignedblob.cpp:225
tesseract::AlignedBlob::WithinTestRegion
static bool WithinTestRegion(int detail_level, int x, int y)
Definition: alignedblob.cpp:150
ScrollView::MAGENTA
Definition: scrollview.h:109
tesseract::AlignedBlobParams::right_tab
bool right_tab
Definition: alignedblob.h:62
tesseract::kVLineMinLength
const int kVLineMinLength
Definition: alignedblob.cpp:56
tesseract::kVLineSearchSize
const int kVLineSearchSize
Definition: alignedblob.cpp:50
BOOL_VAR
#define BOOL_VAR(name, val, comment)
Definition: params.h:303
tesseract::AlignedBlobParams::set_vertical
void set_vertical(int vertical_x, int vertical_y)
Definition: alignedblob.cpp:134
ScrollView::YELLOW
Definition: scrollview.h:105
TBOX::bottom
int16_t bottom() const
Definition: rect.h:64
tesseract::GridSearch
Definition: bbgrid.h:48
tesseract
Definition: baseapi.h:65
tesseract::AlignedBlobParams::alignment
TabAlignment alignment
Definition: alignedblob.h:64
tesseract::kVLineGutter
const int kVLineGutter
Definition: alignedblob.cpp:48
tesseract::kRaggedFraction
const double kRaggedFraction
Definition: alignedblob.cpp:40
ScrollView::RED
Definition: scrollview.h:104
BLOBNBOX::bounding_box
const TBOX & bounding_box() const
Definition: blobbox.h:229
tesseract::kMinRaggedTabs
const int kMinRaggedTabs
Definition: alignedblob.cpp:52
tesseract::AlignedBlobParams::confirmed_type
TabType confirmed_type
Definition: alignedblob.h:65
tesseract::kVLineAlignment
const int kVLineAlignment
Definition: alignedblob.cpp:46
TT_MAYBE_RAGGED
Definition: blobbox.h:61
tesseract::AlignedBlobParams
Definition: alignedblob.h:42
tesseract::GridBase::gridsize
int gridsize() const
Definition: bbgrid.h:63
tesseract::AlignedBlobParams::gutter_fraction
double gutter_fraction
Definition: alignedblob.h:61
BLOBNBOX::right_tab_type
TabType right_tab_type() const
Definition: blobbox.h:276
alignedblob.h
tesseract::AlignedBlobParams::r_align_tolerance
int r_align_tolerance
Definition: alignedblob.h:70
TBOX::left
int16_t left() const
Definition: rect.h:71
BLOBNBOX::right_crossing_rule
int right_crossing_rule() const
Definition: blobbox.h:330
tesseract::AlignedBlob::DisplayTabs
ScrollView * DisplayTabs(const char *window_name, ScrollView *tab_win)
Definition: alignedblob.cpp:158
ScrollView::GREEN
Definition: scrollview.h:106
tesseract::kMaxSkewFactor
const int kMaxSkewFactor
Definition: alignedblob.cpp:64
tesseract::AlignedBlobParams::ragged
bool ragged
Definition: alignedblob.h:63
TBOX::right
int16_t right() const
Definition: rect.h:78
TT_VLINE
Definition: blobbox.h:64
ScrollView::Line
void Line(int x1, int y1, int x2, int y2)
Definition: scrollview.cpp:531
tprintf
DLLSYM void tprintf(const char *format,...)
Definition: tprintf.cpp:34
tesstrain_utils.type
type
Definition: tesstrain_utils.py:141
ScrollView::Update
static void Update()
Definition: scrollview.cpp:708
tesseract::AlignedBlobParams::min_length
int min_length
Definition: alignedblob.h:73
tesseract::TabAlignment
TabAlignment
Definition: tabvector.h:44
tesseract::kMinAlignedTabs
const int kMinAlignedTabs
Definition: alignedblob.cpp:54
tesseract::TA_RIGHT_RAGGED
Definition: tabvector.h:49
TT_DELETED
Definition: blobbox.h:60
tesseract::AlignedBlobParams::max_v_gap
int max_v_gap
Definition: alignedblob.h:66
BLOBNBOX::left_tab_type
TabType left_tab_type() const
Definition: blobbox.h:270
tesseract::AlignedBlobParams::vertical
ICOORD vertical
Definition: alignedblob.h:75
textord_debug_tabfind
int textord_debug_tabfind
Definition: alignedblob.cpp:27
tesseract::AlignedBlobParams::l_align_tolerance
int l_align_tolerance
Definition: alignedblob.h:69
tesseract::AlignedBlob::AlignedBlob
AlignedBlob(int gridsize, const ICOORD &bleft, const ICOORD &tright)
Definition: alignedblob.cpp:143
tesseract::GridSearch::NextFullSearch
BBC * NextFullSearch()
Definition: bbgrid.h:675
TBOX
Definition: rect.h:33