tesseract  5.0.0-alpha-619-ge9db
blobbox.cpp
Go to the documentation of this file.
1 /**********************************************************************
2  * File: blobbox.cpp (Formerly blobnbox.c)
3  * Description: Code for the textord blob class.
4  * Author: Ray Smith
5  *
6  * (C) Copyright 1992, Hewlett-Packard Ltd.
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  *
17  **********************************************************************/
18 
19 // Include automatically generated configuration file if running autoconf.
20 #ifdef HAVE_CONFIG_H
21 #include "config_auto.h"
22 #endif
23 
24 #include "blobbox.h"
25 #include <algorithm> // for max, min
26 #include <cstdint> // for INT32_MAX, INT16_MAX
27 #include "allheaders.h" // for pixGetHeight, pixGetPixel
28 #include "blobs.h" // for TPOINT
29 #include "coutln.h" // for C_OUTLINE_IT, C_OUTLINE, C_OUTLINE_LIST
30 #include "environ.h" // for l_uint32
31 #include <tesseract/helpers.h> // for UpdateRange, IntCastRounded
32 #include "host.h" // for NearlyEqual
33 #include "points.h" // for operator+=, ICOORD::rotate
34 
35 struct Pix;
36 
37 #define PROJECTION_MARGIN 10 //arbitrary
38 
42 
43 // Up to 30 degrees is allowed for rotations of diacritic blobs.
44 const double kCosSmallAngle = 0.866;
45 // Min aspect ratio for a joined word to indicate an obvious flow direction.
46 const double kDefiniteAspectRatio = 2.0;
47 // Multiple of short length in perimeter to make a joined word.
48 const double kComplexShapePerimeterRatio = 1.5;
49 // Min multiple of linesize for medium-sized blobs in ReFilterBlobs.
50 const double kMinMediumSizeRatio = 0.25;
51 // Max multiple of linesize for medium-sized blobs in ReFilterBlobs.
52 const double kMaxMediumSizeRatio = 4.0;
53 
54 // Rotates the box and the underlying blob.
55 void BLOBNBOX::rotate(FCOORD rotation) {
56  cblob_ptr->rotate(rotation);
57  rotate_box(rotation);
58  compute_bounding_box();
59 }
60 
61 // Reflect the box in the y-axis, leaving the underlying blob untouched.
63  int left = -box.right();
64  box.set_right(-box.left());
65  box.set_left(left);
66 }
67 
68 // Rotates the box by the angle given by rotation.
69 // If the blob is a diacritic, then only small rotations for skew
70 // correction can be applied.
71 void BLOBNBOX::rotate_box(FCOORD rotation) {
72  if (IsDiacritic()) {
73  ASSERT_HOST(rotation.x() >= kCosSmallAngle);
74  ICOORD top_pt((box.left() + box.right()) / 2, base_char_top_);
75  ICOORD bottom_pt(top_pt.x(), base_char_bottom_);
76  top_pt.rotate(rotation);
77  base_char_top_ = top_pt.y();
78  bottom_pt.rotate(rotation);
79  base_char_bottom_ = bottom_pt.y();
80  box.rotate(rotation);
81  } else {
82  box.rotate(rotation);
83  set_diacritic_box(box);
84  }
85 }
86 
87 /**********************************************************************
88  * BLOBNBOX::merge
89  *
90  * Merge this blob with the given blob, which should be after this.
91  **********************************************************************/
92 void BLOBNBOX::merge( //merge blobs
93  BLOBNBOX *nextblob //blob to join with
94  ) {
95  box += nextblob->box; //merge boxes
96  set_diacritic_box(box);
97  nextblob->joined = true;
98 }
99 
100 
101 // Merge this with other, taking the outlines from other.
102 // Other is not deleted, but left for the caller to handle.
103 void BLOBNBOX::really_merge(BLOBNBOX* other) {
104  if (other->cblob_ptr != nullptr) {
105  C_OUTLINE_IT ol_it(cblob_ptr->out_list());
106  ol_it.add_list_after(other->cblob_ptr->out_list());
107  }
109 }
110 
111 
112 /**********************************************************************
113  * BLOBNBOX::chop
114  *
115  * Chop this blob into equal sized pieces using the x height as a guide.
116  * The blob is not actually chopped. Instead, fake blobs are inserted
117  * with the relevant bounding boxes.
118  **********************************************************************/
119 
120 void BLOBNBOX::chop( //chop blobs
121  BLOBNBOX_IT *start_it, //location of this
122  BLOBNBOX_IT *end_it, //iterator
123  FCOORD rotation, //for landscape
124  float xheight //of line
125  ) {
126  int16_t blobcount; //no of blobs
127  BLOBNBOX *newblob; //fake blob
128  BLOBNBOX *blob; //current blob
129  int16_t blobindex; //number of chop
130  int16_t leftx; //left edge of blob
131  float blobwidth; //width of each
132  float rightx; //right edge to scan
133  float ymin, ymax; //limits of new blob
134  float test_ymin, test_ymax; //limits of part blob
135  ICOORD bl, tr; //corners of box
136  BLOBNBOX_IT blob_it; //blob iterator
137 
138  //get no of chops
139  blobcount = static_cast<int16_t>(floor (box.width () / xheight));
140  if (blobcount > 1 && cblob_ptr != nullptr) {
141  //width of each
142  blobwidth = static_cast<float>(box.width () + 1) / blobcount;
143  for (blobindex = blobcount - 1, rightx = box.right ();
144  blobindex >= 0; blobindex--, rightx -= blobwidth) {
145  ymin = static_cast<float>(INT32_MAX);
146  ymax = static_cast<float>(-INT32_MAX);
147  blob_it = *start_it;
148  do {
149  blob = blob_it.data ();
150  find_cblob_vlimits(blob->cblob_ptr, rightx - blobwidth,
151  rightx,
152  /*rotation, */ test_ymin, test_ymax);
153  blob_it.forward ();
154  UpdateRange(test_ymin, test_ymax, &ymin, &ymax);
155  }
156  while (blob != end_it->data ());
157  if (ymin < ymax) {
158  leftx = static_cast<int16_t>(floor (rightx - blobwidth));
159  if (leftx < box.left ())
160  leftx = box.left (); //clip to real box
161  bl = ICOORD (leftx, static_cast<int16_t>(floor (ymin)));
162  tr = ICOORD (static_cast<int16_t>(ceil (rightx)), static_cast<int16_t>(ceil (ymax)));
163  if (blobindex == 0)
164  box = TBOX (bl, tr); //change box
165  else {
166  newblob = new BLOBNBOX;
167  //box is all it has
168  newblob->box = TBOX (bl, tr);
169  //stay on current
170  newblob->base_char_top_ = tr.y();
171  newblob->base_char_bottom_ = bl.y();
172  end_it->add_after_stay_put (newblob);
173  }
174  }
175  }
176  }
177 }
178 
179 // Returns the box gaps between this and its neighbours_ in an array
180 // indexed by BlobNeighbourDir.
181 void BLOBNBOX::NeighbourGaps(int gaps[BND_COUNT]) const {
182  for (int dir = 0; dir < BND_COUNT; ++dir) {
183  gaps[dir] = INT16_MAX;
184  BLOBNBOX* neighbour = neighbours_[dir];
185  if (neighbour != nullptr) {
186  const TBOX& n_box = neighbour->bounding_box();
187  if (dir == BND_LEFT || dir == BND_RIGHT) {
188  gaps[dir] = box.x_gap(n_box);
189  } else {
190  gaps[dir] = box.y_gap(n_box);
191  }
192  }
193  }
194 }
195 // Returns the min and max horizontal and vertical gaps (from NeighbourGaps)
196 // modified so that if the max exceeds the max dimension of the blob, and
197 // the min is less, the max is replaced with the min.
198 // The objective is to catch cases where there is only a single neighbour
199 // and avoid reporting the other gap as a ridiculously large number
200 void BLOBNBOX::MinMaxGapsClipped(int* h_min, int* h_max,
201  int* v_min, int* v_max) const {
202  int max_dimension = std::max(box.width(), box.height());
203  int gaps[BND_COUNT];
204  NeighbourGaps(gaps);
205  *h_min = std::min(gaps[BND_LEFT], gaps[BND_RIGHT]);
206  *h_max = std::max(gaps[BND_LEFT], gaps[BND_RIGHT]);
207  if (*h_max > max_dimension && *h_min < max_dimension) *h_max = *h_min;
208  *v_min = std::min(gaps[BND_ABOVE], gaps[BND_BELOW]);
209  *v_max = std::max(gaps[BND_ABOVE], gaps[BND_BELOW]);
210  if (*v_max > max_dimension && *v_min < max_dimension) *v_max = *v_min;
211 }
212 
213 // Nulls out any neighbours that are DeletableNoise to remove references.
215  for (int dir = 0; dir < BND_COUNT; ++dir) {
216  BLOBNBOX* neighbour = neighbours_[dir];
217  if (neighbour != nullptr && neighbour->DeletableNoise()) {
218  neighbours_[dir] = nullptr;
219  good_stroke_neighbours_[dir] = false;
220  }
221  }
222 }
223 
224 // Returns positive if there is at least one side neighbour that has a similar
225 // stroke width and is not on the other side of a rule line.
226 int BLOBNBOX::GoodTextBlob() const {
227  int score = 0;
228  for (int dir = 0; dir < BND_COUNT; ++dir) {
229  auto bnd = static_cast<BlobNeighbourDir>(dir);
230  if (good_stroke_neighbour(bnd))
231  ++score;
232  }
233  return score;
234 }
235 
236 // Returns the number of side neighbours that are of type BRT_NOISE.
237 int BLOBNBOX::NoisyNeighbours() const {
238  int count = 0;
239  for (int dir = 0; dir < BND_COUNT; ++dir) {
240  auto bnd = static_cast<BlobNeighbourDir>(dir);
241  BLOBNBOX* blob = neighbour(bnd);
242  if (blob != nullptr && blob->region_type() == BRT_NOISE)
243  ++count;
244  }
245  return count;
246 }
247 
248 // Returns true, and sets vert_possible/horz_possible if the blob has some
249 // feature that makes it individually appear to flow one way.
250 // eg if it has a high aspect ratio, yet has a complex shape, such as a
251 // joined word in Latin, Arabic, or Hindi, rather than being a -, I, l, 1 etc.
253  if (cblob() == nullptr) return false;
254  int box_perimeter = 2 * (box.height() + box.width());
255  if (box.width() > box.height() * kDefiniteAspectRatio) {
256  // Attempt to distinguish a wide joined word from a dash.
257  // If it is a dash, then its perimeter is approximately
258  // 2 * (box width + stroke width), but more if the outline is noisy,
259  // so perimeter - 2*(box width + stroke width) should be close to zero.
260  // A complex shape such as a joined word should have a much larger value.
261  int perimeter = cblob()->perimeter();
262  if (vert_stroke_width() > 0 || perimeter <= 0)
263  perimeter -= 2 * vert_stroke_width();
264  else
265  perimeter -= 4 * cblob()->area() / perimeter;
266  perimeter -= 2 * box.width();
267  // Use a multiple of the box perimeter as a threshold.
268  if (perimeter > kComplexShapePerimeterRatio * box_perimeter) {
269  set_vert_possible(false);
270  set_horz_possible(true);
271  return true;
272  }
273  }
274  if (box.height() > box.width() * kDefiniteAspectRatio) {
275  // As above, but for a putative vertical word vs a I/1/l.
276  int perimeter = cblob()->perimeter();
277  if (horz_stroke_width() > 0 || perimeter <= 0)
278  perimeter -= 2 * horz_stroke_width();
279  else
280  perimeter -= 4 * cblob()->area() / perimeter;
281  perimeter -= 2 * box.height();
282  if (perimeter > kComplexShapePerimeterRatio * box_perimeter) {
283  set_vert_possible(true);
284  set_horz_possible(false);
285  return true;
286  }
287  }
288  return false;
289 }
290 
291 // Returns true if there is no tabstop violation in merging this and other.
292 bool BLOBNBOX::ConfirmNoTabViolation(const BLOBNBOX& other) const {
293  if (box.left() < other.box.left() && box.left() < other.left_rule_)
294  return false;
295  if (other.box.left() < box.left() && other.box.left() < left_rule_)
296  return false;
297  if (box.right() > other.box.right() && box.right() > other.right_rule_)
298  return false;
299  if (other.box.right() > box.right() && other.box.right() > right_rule_)
300  return false;
301  return true;
302 }
303 
304 // Returns true if other has a similar stroke width to this.
305 bool BLOBNBOX::MatchingStrokeWidth(const BLOBNBOX& other,
306  double fractional_tolerance,
307  double constant_tolerance) const {
308  // The perimeter-based width is used as a backup in case there is
309  // no information in the blob.
310  double p_width = area_stroke_width();
311  double n_p_width = other.area_stroke_width();
312  float h_tolerance = horz_stroke_width_ * fractional_tolerance
313  + constant_tolerance;
314  float v_tolerance = vert_stroke_width_ * fractional_tolerance
315  + constant_tolerance;
316  double p_tolerance = p_width * fractional_tolerance
317  + constant_tolerance;
318  bool h_zero = horz_stroke_width_ == 0.0f || other.horz_stroke_width_ == 0.0f;
319  bool v_zero = vert_stroke_width_ == 0.0f || other.vert_stroke_width_ == 0.0f;
320  bool h_ok = !h_zero && NearlyEqual(horz_stroke_width_,
321  other.horz_stroke_width_, h_tolerance);
322  bool v_ok = !v_zero && NearlyEqual(vert_stroke_width_,
323  other.vert_stroke_width_, v_tolerance);
324  bool p_ok = h_zero && v_zero && NearlyEqual(p_width, n_p_width, p_tolerance);
325  // For a match, at least one of the horizontal and vertical widths
326  // must match, and the other one must either match or be zero.
327  // Only if both are zero will we look at the perimeter metric.
328  return p_ok || ((v_ok || h_ok) && (h_ok || h_zero) && (v_ok || v_zero));
329 }
330 
331 // Returns a bounding box of the outline contained within the
332 // given horizontal range.
333 TBOX BLOBNBOX::BoundsWithinLimits(int left, int right) {
334  FCOORD no_rotation(1.0f, 0.0f);
335  float top = box.top();
336  float bottom = box.bottom();
337  if (cblob_ptr != nullptr) {
338  find_cblob_limits(cblob_ptr, static_cast<float>(left),
339  static_cast<float>(right), no_rotation,
340  bottom, top);
341  }
342 
343  if (top < bottom) {
344  top = box.top();
345  bottom = box.bottom();
346  }
347  FCOORD bot_left(left, bottom);
348  FCOORD top_right(right, top);
349  TBOX shrunken_box(bot_left);
350  TBOX shrunken_box2(top_right);
351  shrunken_box += shrunken_box2;
352  return shrunken_box;
353 }
354 
355 // Estimates and stores the baseline position based on the shape of the
356 // outline.
358  baseline_y_ = box.bottom(); // The default.
359  if (cblob_ptr == nullptr) return;
360  baseline_y_ = cblob_ptr->EstimateBaselinePosition();
361 }
362 
363 // Helper to call CleanNeighbours on all blobs on the list.
364 void BLOBNBOX::CleanNeighbours(BLOBNBOX_LIST* blobs) {
365  BLOBNBOX_IT blob_it(blobs);
366  for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
367  blob_it.data()->CleanNeighbours();
368  }
369 }
370 
371 // Helper to delete all the deletable blobs on the list.
372 void BLOBNBOX::DeleteNoiseBlobs(BLOBNBOX_LIST* blobs) {
373  BLOBNBOX_IT blob_it(blobs);
374  for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
375  BLOBNBOX* blob = blob_it.data();
376  if (blob->DeletableNoise()) {
377  delete blob->cblob();
378  delete blob_it.extract();
379  }
380  }
381 }
382 
383 // Helper to compute edge offsets for all the blobs on the list.
384 // See coutln.h for an explanation of edge offsets.
385 void BLOBNBOX::ComputeEdgeOffsets(Pix* thresholds, Pix* grey,
386  BLOBNBOX_LIST* blobs) {
387  int grey_height = 0;
388  int thr_height = 0;
389  int scale_factor = 1;
390  if (thresholds != nullptr && grey != nullptr) {
391  grey_height = pixGetHeight(grey);
392  thr_height = pixGetHeight(thresholds);
393  scale_factor =
394  IntCastRounded(static_cast<double>(grey_height) / thr_height);
395  }
396  BLOBNBOX_IT blob_it(blobs);
397  for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
398  BLOBNBOX* blob = blob_it.data();
399  if (blob->cblob() != nullptr) {
400  // Get the threshold that applies to this blob.
401  l_uint32 threshold = 128;
402  if (thresholds != nullptr && grey != nullptr) {
403  const TBOX& box = blob->cblob()->bounding_box();
404  // Transform the coordinates if required.
405  TPOINT pt((box.left() + box.right()) / 2,
406  (box.top() + box.bottom()) / 2);
407  pixGetPixel(thresholds, pt.x / scale_factor,
408  thr_height - 1 - pt.y / scale_factor, &threshold);
409  }
410  blob->cblob()->ComputeEdgeOffsets(threshold, grey);
411  }
412  }
413 }
414 
415 
416 #ifndef GRAPHICS_DISABLED
417 // Helper to draw all the blobs on the list in the given body_colour,
418 // with child outlines in the child_colour.
419 void BLOBNBOX::PlotBlobs(BLOBNBOX_LIST* list,
420  ScrollView::Color body_colour,
421  ScrollView::Color child_colour,
422  ScrollView* win) {
423  BLOBNBOX_IT it(list);
424  for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
425  it.data()->plot(win, body_colour, child_colour);
426  }
427 }
428 
429 // Helper to draw only DeletableNoise blobs (unowned, BRT_NOISE) on the
430 // given list in the given body_colour, with child outlines in the
431 // child_colour.
432 void BLOBNBOX::PlotNoiseBlobs(BLOBNBOX_LIST* list,
433  ScrollView::Color body_colour,
434  ScrollView::Color child_colour,
435  ScrollView* win) {
436  BLOBNBOX_IT it(list);
437  for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
438  BLOBNBOX* blob = it.data();
439  if (blob->DeletableNoise())
440  blob->plot(win, body_colour, child_colour);
441  }
442 }
443 
445  BlobTextFlowType flow_type) {
446  switch (region_type) {
447  case BRT_HLINE:
448  return ScrollView::BROWN;
449  case BRT_VLINE:
450  return ScrollView::DARK_GREEN;
451  case BRT_RECTIMAGE:
452  return ScrollView::RED;
453  case BRT_POLYIMAGE:
454  return ScrollView::ORANGE;
455  case BRT_UNKNOWN:
456  return flow_type == BTFT_NONTEXT ? ScrollView::CYAN : ScrollView::WHITE;
457  case BRT_VERT_TEXT:
458  if (flow_type == BTFT_STRONG_CHAIN || flow_type == BTFT_TEXT_ON_IMAGE)
459  return ScrollView::GREEN;
460  if (flow_type == BTFT_CHAIN)
461  return ScrollView::LIME_GREEN;
462  return ScrollView::YELLOW;
463  case BRT_TEXT:
464  if (flow_type == BTFT_STRONG_CHAIN)
465  return ScrollView::BLUE;
466  if (flow_type == BTFT_TEXT_ON_IMAGE)
467  return ScrollView::LIGHT_BLUE;
468  if (flow_type == BTFT_CHAIN)
470  if (flow_type == BTFT_LEADER)
471  return ScrollView::WHEAT;
472  if (flow_type == BTFT_NONTEXT)
473  return ScrollView::PINK;
474  return ScrollView::MAGENTA;
475  default:
476  return ScrollView::GREY;
477  }
478 }
479 
480 // Keep in sync with BlobRegionType.
482  return TextlineColor(region_type_, flow_);
483 }
484 
485 void BLOBNBOX::plot(ScrollView* window, // window to draw in
486  ScrollView::Color blob_colour, // for outer bits
487  ScrollView::Color child_colour) { // for holes
488  if (cblob_ptr != nullptr)
489  cblob_ptr->plot(window, blob_colour, child_colour);
490 }
491 #endif
492 /**********************************************************************
493  * find_cblob_limits
494  *
495  * Scan the outlines of the cblob to locate the y min and max
496  * between the given x limits.
497  **********************************************************************/
498 
499 void find_cblob_limits( //get y limits
500  C_BLOB *blob, //blob to search
501  float leftx, //x limits
502  float rightx,
503  FCOORD rotation, //for landscape
504  float &ymin, //output y limits
505  float &ymax) {
506  int16_t stepindex; //current point
507  ICOORD pos; //current coords
508  ICOORD vec; //rotated step
509  C_OUTLINE *outline; //current outline
510  //outlines
511  C_OUTLINE_IT out_it = blob->out_list ();
512 
513  ymin = static_cast<float>(INT32_MAX);
514  ymax = static_cast<float>(-INT32_MAX);
515  for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
516  outline = out_it.data ();
517  pos = outline->start_pos (); //get coords
518  pos.rotate (rotation);
519  for (stepindex = 0; stepindex < outline->pathlength (); stepindex++) {
520  //inside
521  if (pos.x () >= leftx && pos.x () <= rightx) {
522  UpdateRange(pos.y(), &ymin, &ymax);
523  }
524  vec = outline->step (stepindex);
525  vec.rotate (rotation);
526  pos += vec; //move to next
527  }
528  }
529 }
530 
531 
532 /**********************************************************************
533  * find_cblob_vlimits
534  *
535  * Scan the outlines of the cblob to locate the y min and max
536  * between the given x limits.
537  **********************************************************************/
538 
539 void find_cblob_vlimits( //get y limits
540  C_BLOB *blob, //blob to search
541  float leftx, //x limits
542  float rightx,
543  float &ymin, //output y limits
544  float &ymax) {
545  int16_t stepindex; //current point
546  ICOORD pos; //current coords
547  ICOORD vec; //rotated step
548  C_OUTLINE *outline; //current outline
549  //outlines
550  C_OUTLINE_IT out_it = blob->out_list ();
551 
552  ymin = static_cast<float>(INT32_MAX);
553  ymax = static_cast<float>(-INT32_MAX);
554  for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
555  outline = out_it.data ();
556  pos = outline->start_pos (); //get coords
557  for (stepindex = 0; stepindex < outline->pathlength (); stepindex++) {
558  //inside
559  if (pos.x () >= leftx && pos.x () <= rightx) {
560  UpdateRange(pos.y(), &ymin, &ymax);
561  }
562  vec = outline->step (stepindex);
563  pos += vec; //move to next
564  }
565  }
566 }
567 
568 
569 /**********************************************************************
570  * find_cblob_hlimits
571  *
572  * Scan the outlines of the cblob to locate the x min and max
573  * between the given y limits.
574  **********************************************************************/
575 
576 void find_cblob_hlimits( //get x limits
577  C_BLOB *blob, //blob to search
578  float bottomy, //y limits
579  float topy,
580  float &xmin, //output x limits
581  float &xmax) {
582  int16_t stepindex; //current point
583  ICOORD pos; //current coords
584  ICOORD vec; //rotated step
585  C_OUTLINE *outline; //current outline
586  //outlines
587  C_OUTLINE_IT out_it = blob->out_list ();
588 
589  xmin = static_cast<float>(INT32_MAX);
590  xmax = static_cast<float>(-INT32_MAX);
591  for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
592  outline = out_it.data ();
593  pos = outline->start_pos (); //get coords
594  for (stepindex = 0; stepindex < outline->pathlength (); stepindex++) {
595  //inside
596  if (pos.y () >= bottomy && pos.y () <= topy) {
597  UpdateRange(pos.x(), &xmin, &xmax);
598  }
599  vec = outline->step (stepindex);
600  pos += vec; //move to next
601  }
602  }
603 }
604 
605 /**********************************************************************
606  * crotate_cblob
607  *
608  * Rotate the copy by the given vector and return a C_BLOB.
609  **********************************************************************/
610 
611 C_BLOB *crotate_cblob( //rotate it
612  C_BLOB *blob, //blob to search
613  FCOORD rotation //for landscape
614  ) {
615  C_OUTLINE_LIST out_list; //output outlines
616  //input outlines
617  C_OUTLINE_IT in_it = blob->out_list ();
618  //output outlines
619  C_OUTLINE_IT out_it = &out_list;
620 
621  for (in_it.mark_cycle_pt (); !in_it.cycled_list (); in_it.forward ()) {
622  out_it.add_after_then_move (new C_OUTLINE (in_it.data (), rotation));
623  }
624  return new C_BLOB (&out_list);
625 }
626 
627 
628 /**********************************************************************
629  * box_next
630  *
631  * Compute the bounding box of this blob with merging of x overlaps
632  * but no pre-chopping.
633  * Then move the iterator on to the start of the next blob.
634  **********************************************************************/
635 
636 TBOX box_next( //get bounding box
637  BLOBNBOX_IT *it //iterator to blobds
638  ) {
639  BLOBNBOX *blob; //current blob
640  TBOX result; //total box
641 
642  blob = it->data ();
643  result = blob->bounding_box ();
644  do {
645  it->forward ();
646  blob = it->data ();
647  if (blob->cblob() == nullptr)
648  //was pre-chopped
649  result += blob->bounding_box ();
650  }
651  //until next real blob
652  while ((blob->cblob() == nullptr) || blob->joined_to_prev());
653  return result;
654 }
655 
656 
657 /**********************************************************************
658  * box_next_pre_chopped
659  *
660  * Compute the bounding box of this blob with merging of x overlaps
661  * but WITH pre-chopping.
662  * Then move the iterator on to the start of the next pre-chopped blob.
663  **********************************************************************/
664 
665 TBOX box_next_pre_chopped( //get bounding box
666  BLOBNBOX_IT *it //iterator to blobds
667  ) {
668  BLOBNBOX *blob; //current blob
669  TBOX result; //total box
670 
671  blob = it->data ();
672  result = blob->bounding_box ();
673  do {
674  it->forward ();
675  blob = it->data ();
676  }
677  //until next real blob
678  while (blob->joined_to_prev ());
679  return result;
680 }
681 
682 
683 /**********************************************************************
684  * TO_ROW::TO_ROW
685  *
686  * Constructor to make a row from a blob.
687  **********************************************************************/
688 
689 TO_ROW::TO_ROW ( //constructor
690 BLOBNBOX * blob, //first blob
691 float top, //corrected top
692 float bottom, //of row
693 float row_size //ideal
694 ) {
695  clear();
696  y_min = bottom;
697  y_max = top;
698  initial_y_min = bottom;
699 
700  float diff; //in size
701  BLOBNBOX_IT it = &blobs; //list of blobs
702 
703  it.add_to_end (blob);
704  diff = top - bottom - row_size;
705  if (diff > 0) {
706  y_max -= diff / 2;
707  y_min += diff / 2;
708  }
709  //very small object
710  else if ((top - bottom) * 3 < row_size) {
711  diff = row_size / 3 + bottom - top;
712  y_max += diff / 2;
713  y_min -= diff / 2;
714  }
715 }
716 
717 void TO_ROW::print() const {
718  tprintf("pitch=%d, fp=%g, fps=%g, fpns=%g, prs=%g, prns=%g,"
719  " spacing=%g xh=%g y_origin=%g xev=%d, asc=%g, desc=%g,"
720  " body=%g, minsp=%d maxnsp=%d, thr=%d kern=%g sp=%g\n",
724  space_size);
725 }
726 
727 /**********************************************************************
728  * TO_ROW:add_blob
729  *
730  * Add the blob to the end of the row.
731  **********************************************************************/
732 
733 void TO_ROW::add_blob( //constructor
734  BLOBNBOX *blob, //first blob
735  float top, //corrected top
736  float bottom, //of row
737  float row_size //ideal
738  ) {
739  float allowed; //allowed expansion
740  float available; //expansion
741  BLOBNBOX_IT it = &blobs; //list of blobs
742 
743  it.add_to_end (blob);
744  allowed = row_size + y_min - y_max;
745  if (allowed > 0) {
746  available = top > y_max ? top - y_max : 0;
747  if (bottom < y_min)
748  //total available
749  available += y_min - bottom;
750  if (available > 0) {
751  available += available; //do it gradually
752  if (available < allowed)
753  available = allowed;
754  if (bottom < y_min)
755  y_min -= (y_min - bottom) * allowed / available;
756  if (top > y_max)
757  y_max += (top - y_max) * allowed / available;
758  }
759  }
760 }
761 
762 
763 /**********************************************************************
764  * TO_ROW:insert_blob
765  *
766  * Add the blob to the row in the correct position.
767  **********************************************************************/
768 
769 void TO_ROW::insert_blob( //constructor
770  BLOBNBOX *blob //first blob
771  ) {
772  BLOBNBOX_IT it = &blobs; //list of blobs
773 
774  if (it.empty ())
775  it.add_before_then_move (blob);
776  else {
777  it.mark_cycle_pt ();
778  while (!it.cycled_list ()
779  && it.data ()->bounding_box ().left () <=
780  blob->bounding_box ().left ())
781  it.forward ();
782  if (it.cycled_list ())
783  it.add_to_end (blob);
784  else
785  it.add_before_stay_put (blob);
786  }
787 }
788 
789 
790 /**********************************************************************
791  * TO_ROW::compute_vertical_projection
792  *
793  * Compute the vertical projection of a TO_ROW from its blobs.
794  **********************************************************************/
795 
796 void TO_ROW::compute_vertical_projection() { //project whole row
797  TBOX row_box; //bound of row
798  BLOBNBOX *blob; //current blob
799  TBOX blob_box; //bounding box
800  BLOBNBOX_IT blob_it = blob_list ();
801 
802  if (blob_it.empty ())
803  return;
804  row_box = blob_it.data ()->bounding_box ();
805  for (blob_it.mark_cycle_pt (); !blob_it.cycled_list (); blob_it.forward ())
806  row_box += blob_it.data ()->bounding_box ();
807 
809  row_box.right () + PROJECTION_MARGIN);
810  projection_left = row_box.left () - PROJECTION_MARGIN;
812  for (blob_it.mark_cycle_pt (); !blob_it.cycled_list (); blob_it.forward ()) {
813  blob = blob_it.data();
814  if (blob->cblob() != nullptr)
816  }
817 }
818 
819 
820 /**********************************************************************
821  * TO_ROW::clear
822  *
823  * Zero out all scalar members.
824  **********************************************************************/
825 void TO_ROW::clear() {
826  all_caps = false;
827  used_dm_model = false;
828  projection_left = 0;
829  projection_right = 0;
831  fixed_pitch = 0.0;
832  fp_space = 0.0;
833  fp_nonsp = 0.0;
834  pr_space = 0.0;
835  pr_nonsp = 0.0;
836  spacing = 0.0;
837  xheight = 0.0;
838  xheight_evidence = 0;
839  body_size = 0.0;
840  ascrise = 0.0;
841  descdrop = 0.0;
842  min_space = 0;
843  max_nonspace = 0;
844  space_threshold = 0;
845  kern_size = 0.0;
846  space_size = 0.0;
847  y_min = 0.0;
848  y_max = 0.0;
849  initial_y_min = 0.0;
850  m = 0.0;
851  c = 0.0;
852  error = 0.0;
853  para_c = 0.0;
854  para_error = 0.0;
855  y_origin = 0.0;
856  credibility = 0.0;
857  num_repeated_sets_ = -1;
858 }
859 
860 
861 /**********************************************************************
862  * vertical_cblob_projection
863  *
864  * Compute the vertical projection of a cblob from its outlines
865  * and add to the given STATS.
866  **********************************************************************/
867 
868 void vertical_cblob_projection( //project outlines
869  C_BLOB *blob, //blob to project
870  STATS *stats //output
871  ) {
872  //outlines of blob
873  C_OUTLINE_IT out_it = blob->out_list ();
874 
875  for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
876  vertical_coutline_projection (out_it.data (), stats);
877  }
878 }
879 
880 
881 /**********************************************************************
882  * vertical_coutline_projection
883  *
884  * Compute the vertical projection of a outline from its outlines
885  * and add to the given STATS.
886  **********************************************************************/
887 
888 void vertical_coutline_projection( //project outlines
889  C_OUTLINE *outline, //outline to project
890  STATS *stats //output
891  ) {
892  ICOORD pos; //current point
893  ICOORD step; //edge step
894  int32_t length; //of outline
895  int16_t stepindex; //current step
896  C_OUTLINE_IT out_it = outline->child ();
897 
898  pos = outline->start_pos ();
899  length = outline->pathlength ();
900  for (stepindex = 0; stepindex < length; stepindex++) {
901  step = outline->step (stepindex);
902  if (step.x () > 0) {
903  stats->add (pos.x (), -pos.y ());
904  } else if (step.x () < 0) {
905  stats->add (pos.x () - 1, pos.y ());
906  }
907  pos += step;
908  }
909 
910  for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
911  vertical_coutline_projection (out_it.data (), stats);
912  }
913 }
914 
915 
916 /**********************************************************************
917  * TO_BLOCK::TO_BLOCK
918  *
919  * Constructor to make a TO_BLOCK from a real block.
920  **********************************************************************/
921 
922 TO_BLOCK::TO_BLOCK( //make a block
923  BLOCK *src_block //real block
924  ) {
925  clear();
926  block = src_block;
927 }
928 
929 static void clear_blobnboxes(BLOBNBOX_LIST* boxes) {
930  BLOBNBOX_IT it = boxes;
931  // A BLOBNBOX generally doesn't own its blobs, so if they do, you
932  // have to delete them explicitly.
933  for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
934  BLOBNBOX* box = it.data();
935  delete box->cblob();
936  }
937 }
938 
939 /**********************************************************************
940  * TO_BLOCK::clear
941  *
942  * Zero out all scalar members.
943  **********************************************************************/
944 void TO_BLOCK::clear() {
945  block = nullptr;
947  line_spacing = 0.0;
948  line_size = 0.0;
949  max_blob_size = 0.0;
950  baseline_offset = 0.0;
951  xheight = 0.0;
952  fixed_pitch = 0.0;
953  kern_size = 0.0;
954  space_size = 0.0;
955  min_space = 0;
956  max_nonspace = 0;
957  fp_space = 0.0;
958  fp_nonsp = 0.0;
959  pr_space = 0.0;
960  pr_nonsp = 0.0;
961  key_row = nullptr;
962 }
963 
964 
966  // Any residual BLOBNBOXes at this stage own their blobs, so delete them.
967  clear_blobnboxes(&blobs);
968  clear_blobnboxes(&underlines);
969  clear_blobnboxes(&noise_blobs);
970  clear_blobnboxes(&small_blobs);
971  clear_blobnboxes(&large_blobs);
972 }
973 
974 // Helper function to divide the input blobs over noise, small, medium
975 // and large lists. Blobs small in height and (small in width or large in width)
976 // go in the noise list. Dash (-) candidates go in the small list, and
977 // medium and large are by height.
978 // SIDE-EFFECT: reset all blobs to initial state by calling Init().
979 static void SizeFilterBlobs(int min_height, int max_height,
980  BLOBNBOX_LIST* src_list,
981  BLOBNBOX_LIST* noise_list,
982  BLOBNBOX_LIST* small_list,
983  BLOBNBOX_LIST* medium_list,
984  BLOBNBOX_LIST* large_list) {
985  BLOBNBOX_IT noise_it(noise_list);
986  BLOBNBOX_IT small_it(small_list);
987  BLOBNBOX_IT medium_it(medium_list);
988  BLOBNBOX_IT large_it(large_list);
989  for (BLOBNBOX_IT src_it(src_list); !src_it.empty(); src_it.forward()) {
990  BLOBNBOX* blob = src_it.extract();
991  blob->ReInit();
992  int width = blob->bounding_box().width();
993  int height = blob->bounding_box().height();
994  if (height < min_height &&
995  (width < min_height || width > max_height))
996  noise_it.add_after_then_move(blob);
997  else if (height > max_height)
998  large_it.add_after_then_move(blob);
999  else if (height < min_height)
1000  small_it.add_after_then_move(blob);
1001  else
1002  medium_it.add_after_then_move(blob);
1003  }
1004 }
1005 
1006 // Reorganize the blob lists with a different definition of small, medium
1007 // and large, compared to the original definition.
1008 // Height is still the primary filter key, but medium width blobs of small
1009 // height become small, and very wide blobs of small height stay noise, along
1010 // with small dot-shaped blobs.
1012  int min_height = IntCastRounded(kMinMediumSizeRatio * line_size);
1013  int max_height = IntCastRounded(kMaxMediumSizeRatio * line_size);
1014  BLOBNBOX_LIST noise_list;
1015  BLOBNBOX_LIST small_list;
1016  BLOBNBOX_LIST medium_list;
1017  BLOBNBOX_LIST large_list;
1018  SizeFilterBlobs(min_height, max_height, &blobs,
1019  &noise_list, &small_list, &medium_list, &large_list);
1020  SizeFilterBlobs(min_height, max_height, &large_blobs,
1021  &noise_list, &small_list, &medium_list, &large_list);
1022  SizeFilterBlobs(min_height, max_height, &small_blobs,
1023  &noise_list, &small_list, &medium_list, &large_list);
1024  SizeFilterBlobs(min_height, max_height, &noise_blobs,
1025  &noise_list, &small_list, &medium_list, &large_list);
1026  BLOBNBOX_IT blob_it(&blobs);
1027  blob_it.add_list_after(&medium_list);
1028  blob_it.set_to_list(&large_blobs);
1029  blob_it.add_list_after(&large_list);
1030  blob_it.set_to_list(&small_blobs);
1031  blob_it.add_list_after(&small_list);
1032  blob_it.set_to_list(&noise_blobs);
1033  blob_it.add_list_after(&noise_list);
1034 }
1035 
1036 // Deletes noise blobs from all lists where not owned by a ColPartition.
1047 
1048 // Computes and stores the edge offsets on each blob for use in feature
1049 // extraction, using greyscale if the supplied grey and thresholds pixes
1050 // are 8-bit or otherwise (if nullptr or not 8 bit) the original binary
1051 // edge step outlines.
1052 // Thresholds must either be the same size as grey or an integer down-scale
1053 // of grey.
1054 // See coutln.h for an explanation of edge offsets.
1055 void TO_BLOCK::ComputeEdgeOffsets(Pix* thresholds, Pix* grey) {
1056  BLOBNBOX::ComputeEdgeOffsets(thresholds, grey, &blobs);
1057  BLOBNBOX::ComputeEdgeOffsets(thresholds, grey, &small_blobs);
1058  BLOBNBOX::ComputeEdgeOffsets(thresholds, grey, &noise_blobs);
1059 }
1060 
1061 #ifndef GRAPHICS_DISABLED
1062 // Draw the noise blobs from all lists in red.
1069 
1070 // Draw the blobs on the various lists in the block in different colors.
1074  win);
1076  win);
1078 }
1079 
1080 /**********************************************************************
1081  * plot_blob_list
1082  *
1083  * Draw a list of blobs.
1084  **********************************************************************/
1085 
1086 void plot_blob_list(ScrollView* win, // window to draw in
1087  BLOBNBOX_LIST *list, // blob list
1088  ScrollView::Color body_colour, // colour to draw
1089  ScrollView::Color child_colour) { // colour of child
1090  BLOBNBOX_IT it = list;
1091  for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
1092  it.data()->plot(win, body_colour, child_colour);
1093  }
1094 }
1095 #endif // GRAPHICS_DISABLED
ScrollView::GREY
Definition: scrollview.h:133
TO_BLOCK::ComputeEdgeOffsets
void ComputeEdgeOffsets(Pix *thresholds, Pix *grey)
Definition: blobbox.cpp:1038
crotate_cblob
C_BLOB * crotate_cblob(C_BLOB *blob, FCOORD rotation)
Definition: blobbox.cpp:605
ELIST2IZE
#define ELIST2IZE(CLASSNAME)
Definition: elst2.h:928
TBOX
Definition: cleanapi_test.cc:19
TO_ROW::min_space
int32_t min_space
Definition: blobbox.h:662
TO_BLOCK::small_blobs
BLOBNBOX_LIST small_blobs
Definition: blobbox.h:774
ScrollView
Definition: scrollview.h:97
BlobTextFlowType
BlobTextFlowType
Definition: blobbox.h:113
TO_BLOCK::plot_graded_blobs
void plot_graded_blobs(ScrollView *to_win)
Definition: blobbox.cpp:1054
BLOBNBOX::ComputeEdgeOffsets
static void ComputeEdgeOffsets(Pix *thresholds, Pix *grey, BLOBNBOX_LIST *blobs)
Definition: blobbox.cpp:383
TO_BLOCK::max_nonspace
int32_t max_nonspace
Definition: blobbox.h:792
TO_ROW::body_size
float body_size
Definition: blobbox.h:660
C_BLOB::bounding_box
TBOX bounding_box() const
Definition: stepblob.cpp:247
kMinMediumSizeRatio
const double kMinMediumSizeRatio
Definition: blobbox.cpp:50
C_BLOB::perimeter
int32_t perimeter()
Definition: stepblob.cpp:284
BND_RIGHT
Definition: blobbox.h:89
BLOBNBOX::rotate_box
void rotate_box(FCOORD rotation)
Definition: blobbox.cpp:71
PROJECTION_MARGIN
#define PROJECTION_MARGIN
Definition: blobbox.cpp:37
BLOBNBOX::NoisyNeighbours
int NoisyNeighbours() const
Definition: blobbox.cpp:235
kDefiniteAspectRatio
const double kDefiniteAspectRatio
Definition: blobbox.cpp:46
TO_BLOCK::plot_noise_blobs
void plot_noise_blobs(ScrollView *to_win)
Definition: blobbox.cpp:1046
ScrollView::DARK_GREEN
Definition: scrollview.h:124
TO_BLOCK::baseline_offset
float baseline_offset
Definition: blobbox.h:786
TO_ROW::space_size
float space_size
Definition: blobbox.h:666
C_BLOB::out_list
C_OUTLINE_LIST * out_list()
Definition: stepblob.h:69
BTFT_STRONG_CHAIN
Definition: blobbox.h:118
BLOBNBOX::set_diacritic_box
void set_diacritic_box(const TBOX &diacritic_box)
Definition: blobbox.h:397
host.h
TPOINT
Definition: blobs.h:49
TO_ROW::pr_nonsp
float pr_nonsp
Definition: blobbox.h:654
TO_BLOCK::kern_size
float kern_size
Definition: blobbox.h:789
BRT_NOISE
Definition: blobbox.h:72
kCosSmallAngle
const double kCosSmallAngle
Definition: blobbox.cpp:44
TO_BLOCK::noise_blobs
BLOBNBOX_LIST noise_blobs
Definition: blobbox.h:773
BLOBNBOX::plot
void plot(ScrollView *window, ScrollView::Color blob_colour, ScrollView::Color child_colour)
Definition: blobbox.cpp:483
TO_ROW::pr_space
float pr_space
Definition: blobbox.h:653
TO_BLOCK::key_row
TO_ROW * key_row
Definition: blobbox.h:797
BLOBNBOX::PlotBlobs
static void PlotBlobs(BLOBNBOX_LIST *list, ScrollView::Color body_colour, ScrollView::Color child_colour, ScrollView *win)
Definition: blobbox.cpp:417
ASSERT_HOST
#define ASSERT_HOST(x)
Definition: errcode.h:87
BND_BELOW
Definition: blobbox.h:88
BLOBNBOX::BoundsWithinLimits
TBOX BoundsWithinLimits(int left, int right)
Definition: blobbox.cpp:331
NearlyEqual
bool NearlyEqual(T x, T y, T tolerance)
Definition: host.h:36
TO_ROW::spacing
float spacing
Definition: blobbox.h:655
blobbox.h
BRT_UNKNOWN
Definition: blobbox.h:77
ICOORD
integer coordinate
Definition: points.h:30
ICOORD::rotate
void rotate(const FCOORD &vec)
Definition: points.h:522
BLOBNBOX::compute_bounding_box
void compute_bounding_box()
Definition: blobbox.h:239
vertical_coutline_projection
void vertical_coutline_projection(C_OUTLINE *outline, STATS *stats)
Definition: blobbox.cpp:873
TO_BLOCK::DeleteUnownedNoise
void DeleteUnownedNoise()
Definition: blobbox.cpp:1020
FCOORD::x
float x() const
Definition: points.h:206
TO_ROW::projection_left
int16_t projection_left
Definition: blobbox.h:647
TBOX::top
int16_t top() const
Definition: rect.h:57
TO_BLOCK::fp_space
float fp_space
Definition: blobbox.h:793
TO_BLOCK::blobs
BLOBNBOX_LIST blobs
Definition: blobbox.h:771
TO_ROW::projection_right
int16_t projection_right
Definition: blobbox.h:648
TO_BLOCK
Definition: blobbox.h:691
BRT_VERT_TEXT
Definition: blobbox.h:78
ScrollView::BROWN
Definition: scrollview.h:120
BLOBNBOX::NeighbourGaps
void NeighbourGaps(int gaps[BND_COUNT]) const
Definition: blobbox.cpp:179
find_cblob_vlimits
void find_cblob_vlimits(C_BLOB *blob, float leftx, float rightx, float &ymin, float &ymax)
Definition: blobbox.cpp:535
ScrollView::CYAN
Definition: scrollview.h:107
TO_BLOCK::clear
void clear()
Definition: blobbox.cpp:927
BLOBNBOX::good_stroke_neighbour
bool good_stroke_neighbour(BlobNeighbourDir n) const
Definition: blobbox.h:372
IntCastRounded
int IntCastRounded(double x)
Definition: helpers.h:173
ScrollView::MEDIUM_BLUE
Definition: scrollview.h:113
BRT_RECTIMAGE
Definition: blobbox.h:75
TO_ROW::pitch_decision
PITCH_TYPE pitch_decision
Definition: blobbox.h:649
ICOORD::x
int16_t x() const
access function
Definition: points.h:51
FCOORD
Definition: points.h:187
blobs.h
BLOBNBOX
Definition: blobbox.h:142
BND_ABOVE
Definition: blobbox.h:90
BTFT_CHAIN
Definition: blobbox.h:117
ScrollView::BLUE
Definition: scrollview.h:108
BRT_HLINE
Definition: blobbox.h:73
BTFT_LEADER
Definition: blobbox.h:120
BLOBNBOX::reflect_box_in_y_axis
void reflect_box_in_y_axis()
Definition: blobbox.cpp:62
TO_BLOCK::underlines
BLOBNBOX_LIST underlines
Definition: blobbox.h:772
BRT_POLYIMAGE
Definition: blobbox.h:76
BLOBNBOX::BoxColor
ScrollView::Color BoxColor() const
Definition: blobbox.cpp:479
C_BLOB
Definition: stepblob.h:36
C_BLOB::area
int32_t area()
Definition: stepblob.cpp:266
TBOX::rotate
void rotate(const FCOORD &vec)
Definition: rect.h:196
kComplexShapePerimeterRatio
const double kComplexShapePerimeterRatio
Definition: blobbox.cpp:48
TO_ROW::fp_nonsp
float fp_nonsp
Definition: blobbox.h:652
C_OUTLINE
Definition: coutln.h:71
BLOBNBOX::horz_stroke_width
float horz_stroke_width() const
Definition: blobbox.h:336
TBOX::height
int16_t height() const
Definition: rect.h:107
BLOBNBOX::TextlineColor
static ScrollView::Color TextlineColor(BlobRegionType region_type, BlobTextFlowType flow_type)
Definition: blobbox.cpp:442
TBOX::y_gap
int y_gap(const TBOX &box) const
Definition: rect.h:232
BTFT_NONTEXT
Definition: blobbox.h:115
vertical_cblob_projection
void vertical_cblob_projection(C_BLOB *blob, STATS *stats)
Definition: blobbox.cpp:854
BLOBNBOX::GoodTextBlob
int GoodTextBlob() const
Definition: blobbox.cpp:224
BLOBNBOX::neighbour
BLOBNBOX * neighbour(BlobNeighbourDir n) const
Definition: blobbox.h:369
TBOX::set_right
void set_right(int x)
Definition: rect.h:81
BLOCK
Definition: ocrblock.h:28
TO_ROW::used_dm_model
bool used_dm_model
Definition: blobbox.h:646
TO_BLOCK::ReSetAndReFilterBlobs
void ReSetAndReFilterBlobs()
Definition: blobbox.cpp:994
TO_BLOCK::large_blobs
BLOBNBOX_LIST large_blobs
Definition: blobbox.h:775
ScrollView::ORANGE
Definition: scrollview.h:136
BTFT_TEXT_ON_IMAGE
Definition: blobbox.h:119
TPOINT::x
int16_t x
Definition: blobs.h:91
BlobRegionType
BlobRegionType
Definition: blobbox.h:71
PITCH_DUNNO
Definition: blobbox.h:45
TO_ROW::insert_blob
void insert_blob(BLOBNBOX *blob)
Definition: blobbox.cpp:758
BLOBNBOX::PlotNoiseBlobs
static void PlotNoiseBlobs(BLOBNBOX_LIST *list, ScrollView::Color body_colour, ScrollView::Color child_colour, ScrollView *win)
Definition: blobbox.cpp:430
BLOBNBOX::MatchingStrokeWidth
bool MatchingStrokeWidth(const BLOBNBOX &other, double fractional_tolerance, double constant_tolerance) const
Definition: blobbox.cpp:303
TO_BLOCK::block
BLOCK * block
Definition: blobbox.h:776
ScrollView::LIGHT_BLUE
Definition: scrollview.h:112
TO_ROW::projection
STATS projection
Definition: blobbox.h:670
ScrollView::MAGENTA
Definition: scrollview.h:109
TO_BLOCK::fixed_pitch
float fixed_pitch
Definition: blobbox.h:788
BRT_TEXT
Definition: blobbox.h:79
TO_BLOCK::fp_nonsp
float fp_nonsp
Definition: blobbox.h:794
TO_ROW::fp_space
float fp_space
Definition: blobbox.h:651
TO_BLOCK::xheight
float xheight
Definition: blobbox.h:787
BLOBNBOX::joined_to_prev
bool joined_to_prev() const
Definition: blobbox.h:255
find_cblob_limits
void find_cblob_limits(C_BLOB *blob, float leftx, float rightx, FCOORD rotation, float &ymin, float &ymax)
Definition: blobbox.cpp:496
TPOINT::y
int16_t y
Definition: blobs.h:92
C_BLOB::EstimateBaselinePosition
int16_t EstimateBaselinePosition()
Definition: stepblob.cpp:419
BLOBNBOX::CleanNeighbours
void CleanNeighbours()
Definition: blobbox.cpp:212
TBOX::width
int16_t width() const
Definition: rect.h:114
ScrollView::YELLOW
Definition: scrollview.h:105
TBOX::bottom
int16_t bottom() const
Definition: rect.h:64
BLOBNBOX::IsDiacritic
bool IsDiacritic() const
Definition: blobbox.h:379
ScrollView::WHITE
Definition: scrollview.h:103
BLOBNBOX::DefiniteIndividualFlow
bool DefiniteIndividualFlow()
Definition: blobbox.cpp:250
coutln.h
BLOBNBOX::rotate
void rotate(FCOORD rotation)
Definition: blobbox.cpp:55
TO_ROW::fixed_pitch
float fixed_pitch
Definition: blobbox.h:650
TO_ROW::xheight
float xheight
Definition: blobbox.h:656
helpers.h
TO_BLOCK::TO_BLOCK
TO_BLOCK()
Definition: blobbox.h:694
BND_LEFT
Definition: blobbox.h:87
ScrollView::WHEAT
Definition: scrollview.h:148
TO_BLOCK::space_size
float space_size
Definition: blobbox.h:790
TO_BLOCK::line_spacing
float line_spacing
Definition: blobbox.h:778
TO_BLOCK::pitch_decision
PITCH_TYPE pitch_decision
Definition: blobbox.h:777
ScrollView::RED
Definition: scrollview.h:104
TO_ROW::add_blob
void add_blob(BLOBNBOX *blob, float top, float bottom, float row_size)
Definition: blobbox.cpp:723
STATS
Definition: statistc.h:30
BLOBNBOX::bounding_box
const TBOX & bounding_box() const
Definition: blobbox.h:229
TO_BLOCK::pr_space
float pr_space
Definition: blobbox.h:795
kMaxMediumSizeRatio
const double kMaxMediumSizeRatio
Definition: blobbox.cpp:52
BLOBNBOX::DeletableNoise
bool DeletableNoise() const
Definition: blobbox.h:202
TO_BLOCK::pr_nonsp
float pr_nonsp
Definition: blobbox.h:796
ScrollView::PINK
Definition: scrollview.h:138
BLOBNBOX::area_stroke_width
float area_stroke_width() const
Definition: blobbox.h:348
TO_ROW::xheight_evidence
int xheight_evidence
Definition: blobbox.h:657
TO_ROW::TO_ROW
TO_ROW()
Definition: blobbox.h:548
TO_BLOCK::min_space
int32_t min_space
Definition: blobbox.h:791
TO_ROW::print
void print() const
Definition: blobbox.cpp:708
box_next_pre_chopped
TBOX box_next_pre_chopped(BLOBNBOX_IT *it)
Definition: blobbox.cpp:657
TO_ROW::space_threshold
int32_t space_threshold
Definition: blobbox.h:664
ScrollView::LIME_GREEN
Definition: scrollview.h:127
TO_ROW::max_nonspace
int32_t max_nonspace
Definition: blobbox.h:663
BLOBNBOX::BLOBNBOX
BLOBNBOX()
Definition: blobbox.h:145
box_next
TBOX box_next(BLOBNBOX_IT *it)
Definition: blobbox.cpp:629
ScrollView::GOLDENROD
Definition: scrollview.h:123
BLOBNBOX::merge
void merge(BLOBNBOX *nextblob)
Definition: blobbox.cpp:91
count
int count(LIST var_list)
Definition: oldlist.cpp:79
BLOBNBOX::really_merge
void really_merge(BLOBNBOX *other)
Definition: blobbox.cpp:102
BLOBNBOX::EstimateBaselinePosition
void EstimateBaselinePosition()
Definition: blobbox.cpp:355
BRT_VLINE
Definition: blobbox.h:74
TBOX::left
int16_t left() const
Definition: rect.h:71
STATS::add
void add(int32_t value, int32_t count)
Definition: statistc.cpp:87
ScrollView::GREEN
Definition: scrollview.h:106
BND_COUNT
Definition: blobbox.h:91
BLOBNBOX::ConfirmNoTabViolation
bool ConfirmNoTabViolation(const BLOBNBOX &other) const
Definition: blobbox.cpp:290
BLOBNBOX::region_type
BlobRegionType region_type() const
Definition: blobbox.h:282
BLOBNBOX::set_horz_possible
void set_horz_possible(bool value)
Definition: blobbox.h:309
TBOX::right
int16_t right() const
Definition: rect.h:78
BLOBNBOX::MinMaxGapsClipped
void MinMaxGapsClipped(int *h_min, int *h_max, int *v_min, int *v_max) const
Definition: blobbox.cpp:198
tprintf
DLLSYM void tprintf(const char *format,...)
Definition: tprintf.cpp:34
TO_ROW
Definition: blobbox.h:543
C_OUTLINE::pathlength
int32_t pathlength() const
Definition: coutln.h:134
TO_ROW::ascrise
float ascrise
Definition: blobbox.h:658
TO_ROW::kern_size
float kern_size
Definition: blobbox.h:665
TO_ROW::all_caps
bool all_caps
Definition: blobbox.h:645
ScrollView::CORAL
Definition: scrollview.h:119
C_OUTLINE::step
ICOORD step(int index) const
Definition: coutln.h:143
ScrollView::Color
Color
Definition: scrollview.h:100
UpdateRange
void UpdateRange(const T1 &x, T2 *lower_bound, T2 *upper_bound)
Definition: helpers.h:118
BLOBNBOX::cblob
C_BLOB * cblob() const
Definition: blobbox.h:267
BLOBNBOX::ReInit
void ReInit()
Definition: blobbox.h:469
TO_ROW::descdrop
float descdrop
Definition: blobbox.h:659
C_OUTLINE::child
C_OUTLINE_LIST * child()
Definition: coutln.h:107
TO_BLOCK::max_blob_size
float max_blob_size
Definition: blobbox.h:785
STATS::set_range
bool set_range(int32_t min_bucket_value, int32_t max_bucket_value_plus_1)
Definition: statistc.cpp:53
find_cblob_hlimits
void find_cblob_hlimits(C_BLOB *blob, float bottomy, float topy, float &xmin, float &xmax)
Definition: blobbox.cpp:571
BLOBNBOX::vert_stroke_width
float vert_stroke_width() const
Definition: blobbox.h:342
BLOBNBOX::chop
void chop(BLOBNBOX_IT *start_it, BLOBNBOX_IT *blob_it, FCOORD rotation, float xheight)
Definition: blobbox.cpp:118
ELISTIZE
#define ELISTIZE(CLASSNAME)
Definition: elst.h:919
C_OUTLINE::start_pos
const ICOORD & start_pos() const
Definition: coutln.h:147
TBOX::set_left
void set_left(int x)
Definition: rect.h:74
C_BLOB::plot
void plot(ScrollView *window, ScrollView::Color blob_colour, ScrollView::Color child_colour)
Definition: stepblob.cpp:523
plot_blob_list
void plot_blob_list(ScrollView *win, BLOBNBOX_LIST *list, ScrollView::Color body_colour, ScrollView::Color child_colour)
Definition: blobbox.cpp:1068
TBOX::x_gap
int x_gap(const TBOX &box) const
Definition: rect.h:224
BLOBNBOX::DeleteNoiseBlobs
static void DeleteNoiseBlobs(BLOBNBOX_LIST *blobs)
Definition: blobbox.cpp:370
TO_ROW::compute_vertical_projection
void compute_vertical_projection()
Definition: blobbox.cpp:784
TO_ROW::blob_list
BLOBNBOX_LIST * blob_list()
Definition: blobbox.h:599
ICOORD::y
int16_t y() const
access_function
Definition: points.h:55
BLOBNBOX::set_vert_possible
void set_vert_possible(bool value)
Definition: blobbox.h:303
C_BLOB::ComputeEdgeOffsets
void ComputeEdgeOffsets(int threshold, Pix *pix)
Definition: stepblob.cpp:401
points.h
TBOX
Definition: rect.h:33
TO_BLOCK::line_size
float line_size
Definition: blobbox.h:784
TO_BLOCK::~TO_BLOCK
~TO_BLOCK()
Definition: blobbox.cpp:948