tesseract  4.00.00dev
normalis.cpp
Go to the documentation of this file.
1 /**********************************************************************
2  * File: normalis.cpp (Formerly denorm.c)
3  * Description: Code for the DENORM class.
4  * Author: Ray Smith
5  * Created: Thu Apr 23 09:22:43 BST 1992
6  *
7  * (C) Copyright 1992, Hewlett-Packard Ltd.
8  ** Licensed under the Apache License, Version 2.0 (the "License");
9  ** you may not use this file except in compliance with the License.
10  ** You may obtain a copy of the License at
11  ** http://www.apache.org/licenses/LICENSE-2.0
12  ** Unless required by applicable law or agreed to in writing, software
13  ** distributed under the License is distributed on an "AS IS" BASIS,
14  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  ** See the License for the specific language governing permissions and
16  ** limitations under the License.
17  *
18  **********************************************************************/
19 
20 #include "normalis.h"
21 
22 #include <stdlib.h>
23 
24 #include "allheaders.h"
25 #include "blobs.h"
26 #include "helpers.h"
27 #include "matrix.h"
28 #include "ocrblock.h"
29 #include "unicharset.h"
30 #include "werd.h"
31 
32 // Tolerance in pixels used for baseline and xheight on non-upper/lower scripts.
33 const int kSloppyTolerance = 4;
34 // Final tolerance in pixels added to the computed xheight range.
35 const float kFinalPixelTolerance = 0.125f;
36 
38  Init();
39 }
40 
41 DENORM::DENORM(const DENORM &src) {
42  rotation_ = NULL;
43  *this = src;
44 }
45 
46 
48  Clear();
49  inverse_ = src.inverse_;
50  predecessor_ = src.predecessor_;
51  pix_ = src.pix_;
52  block_ = src.block_;
53  if (src.rotation_ == NULL)
54  rotation_ = NULL;
55  else
56  rotation_ = new FCOORD(*src.rotation_);
57  x_origin_ = src.x_origin_;
58  y_origin_ = src.y_origin_;
59  x_scale_ = src.x_scale_;
60  y_scale_ = src.y_scale_;
61  final_xshift_ = src.final_xshift_;
62  final_yshift_ = src.final_yshift_;
63  return *this;
64 }
65 
67  Clear();
68 }
69 
70 // Initializes the denorm for a transformation. For details see the large
71 // comment in normalis.h.
72 // Arguments:
73 // block: if not NULL, then this is the first transformation, and
74 // block->re_rotation() needs to be used after the Denorm
75 // transformation to get back to the image coords.
76 // rotation: if not NULL, apply this rotation after translation to the
77 // origin and scaling. (Usually a classify rotation.)
78 // predecessor: if not NULL, then predecessor has been applied to the
79 // input space and needs to be undone to complete the inverse.
80 // The above pointers are not owned by this DENORM and are assumed to live
81 // longer than this denorm, except rotation, which is deep copied on input.
82 //
83 // x_origin: The x origin which will be mapped to final_xshift in the result.
84 // y_origin: The y origin which will be mapped to final_yshift in the result.
85 // Added to result of row->baseline(x) if not NULL.
86 //
87 // x_scale: scale factor for the x-coordinate.
88 // y_scale: scale factor for the y-coordinate. Ignored if segs is given.
89 // Note that these scale factors apply to the same x and y system as the
90 // x-origin and y-origin apply, ie after any block rotation, but before
91 // the rotation argument is applied.
92 //
93 // final_xshift: The x component of the final translation.
94 // final_yshift: The y component of the final translation.
96  const FCOORD* rotation,
97  const DENORM* predecessor,
98  float x_origin, float y_origin,
99  float x_scale, float y_scale,
100  float final_xshift, float final_yshift) {
101  Clear();
102  block_ = block;
103  if (rotation == NULL)
104  rotation_ = NULL;
105  else
106  rotation_ = new FCOORD(*rotation);
107  predecessor_ = predecessor;
108  x_origin_ = x_origin;
109  y_origin_ = y_origin;
110  x_scale_ = x_scale;
111  y_scale_ = y_scale;
112  final_xshift_ = final_xshift;
113  final_yshift_ = final_yshift;
114 }
115 
116 // Helper for SetupNonLinear computes an image of shortest run-lengths from
117 // the x/y edges provided.
118 // Based on "A nonlinear normalization method for handprinted Kanji character
119 // recognition -- line density equalization" by Hiromitsu Yamada et al.
120 // Eg below is an O in a 1-pixel margin-ed bounding box and the corresponding
121 // ______________ input x_coords and y_coords.
122 // | _________ | <empty>
123 // | | _ | | 1, 6
124 // | | | | | | 1, 3, 4, 6
125 // | | | | | | 1, 3, 4, 6
126 // | | | | | | 1, 3, 4, 6
127 // | | |_| | | 1, 3, 4, 6
128 // | |_________| | 1, 6
129 // |_____________| <empty>
130 // E 1 1 1 1 1 E
131 // m 7 7 2 7 7 m
132 // p 6 p
133 // t 7 t
134 // y y
135 // The output image contains the min of the x and y run-length (distance
136 // between edges) at each coordinate in the image thus:
137 // ______________
138 // |7 1_1_1_1_1 7|
139 // |1|5 5 1 5 5|1|
140 // |1|2 2|1|2 2|1|
141 // |1|2 2|1|2 2|1|
142 // |1|2 2|1|2 2|1|
143 // |1|2 2|1|2 2|1|
144 // |1|5_5_1_5_5|1|
145 // |7_1_1_1_1_1_7|
146 // Note that the input coords are all integer, so all partial pixels are dealt
147 // with elsewhere. Although it is nice for outlines to be properly connected
148 // and continuous, there is no requirement that they be as such, so they could
149 // have been derived from a flaky source, such as greyscale.
150 // This function works only within the provided box, and it is assumed that the
151 // input x_coords and y_coords have already been translated to have the bottom-
152 // left of box as the origin. Although an output, the minruns should have been
153 // pre-initialized to be the same size as box. Each element will contain the
154 // minimum of x and y run-length as shown above.
155 static void ComputeRunlengthImage(
156  const TBOX& box,
157  const GenericVector<GenericVector<int> >& x_coords,
158  const GenericVector<GenericVector<int> >& y_coords,
159  GENERIC_2D_ARRAY<int>* minruns) {
160  int width = box.width();
161  int height = box.height();
162  ASSERT_HOST(minruns->dim1() == width);
163  ASSERT_HOST(minruns->dim2() == height);
164  // Set a 2-d image array to the run lengths at each pixel.
165  for (int ix = 0; ix < width; ++ix) {
166  int y = 0;
167  for (int i = 0; i < y_coords[ix].size(); ++i) {
168  int y_edge = ClipToRange(y_coords[ix][i], 0, height);
169  int gap = y_edge - y;
170  // Every pixel between the last and current edge get set to the gap.
171  while (y < y_edge) {
172  (*minruns)(ix, y) = gap;
173  ++y;
174  }
175  }
176  // Pretend there is a bounding box of edges all around the image.
177  int gap = height - y;
178  while (y < height) {
179  (*minruns)(ix, y) = gap;
180  ++y;
181  }
182  }
183  // Now set the image pixels the the MIN of the x and y runlengths.
184  for (int iy = 0; iy < height; ++iy) {
185  int x = 0;
186  for (int i = 0; i < x_coords[iy].size(); ++i) {
187  int x_edge = ClipToRange(x_coords[iy][i], 0, width);
188  int gap = x_edge - x;
189  while (x < x_edge) {
190  if (gap < (*minruns)(x, iy))
191  (*minruns)(x, iy) = gap;
192  ++x;
193  }
194  }
195  int gap = width - x;
196  while (x < width) {
197  if (gap < (*minruns)(x, iy))
198  (*minruns)(x, iy) = gap;
199  ++x;
200  }
201  }
202 }
203 // Converts the run-length image (see above to the edge density profiles used
204 // for scaling, thus:
205 // ______________
206 // |7 1_1_1_1_1 7| = 5.28
207 // |1|5 5 1 5 5|1| = 3.8
208 // |1|2 2|1|2 2|1| = 5
209 // |1|2 2|1|2 2|1| = 5
210 // |1|2 2|1|2 2|1| = 5
211 // |1|2 2|1|2 2|1| = 5
212 // |1|5_5_1_5_5|1| = 3.8
213 // |7_1_1_1_1_1_7| = 5.28
214 // 6 4 4 8 4 4 6
215 // . . . . . . .
216 // 2 4 4 0 4 4 2
217 // 8 8
218 // Each profile is the sum of the reciprocals of the pixels in the image in
219 // the appropriate row or column, and these are then normalized to sum to 1.
220 // On output hx, hy contain an extra element, which will eventually be used
221 // to guarantee that the top/right edge of the box (and anything beyond) always
222 // gets mapped to the maximum target coordinate.
223 static void ComputeEdgeDensityProfiles(const TBOX& box,
224  const GENERIC_2D_ARRAY<int>& minruns,
226  GenericVector<float>* hy) {
227  int width = box.width();
228  int height = box.height();
229  hx->init_to_size(width + 1, 0.0);
230  hy->init_to_size(height + 1, 0.0);
231  double total = 0.0;
232  for (int iy = 0; iy < height; ++iy) {
233  for (int ix = 0; ix < width; ++ix) {
234  int run = minruns(ix, iy);
235  if (run == 0) run = 1;
236  float density = 1.0f / run;
237  (*hx)[ix] += density;
238  (*hy)[iy] += density;
239  }
240  total += (*hy)[iy];
241  }
242  // Normalize each profile to sum to 1.
243  if (total > 0.0) {
244  for (int ix = 0; ix < width; ++ix) {
245  (*hx)[ix] /= total;
246  }
247  for (int iy = 0; iy < height; ++iy) {
248  (*hy)[iy] /= total;
249  }
250  }
251  // There is an extra element in each array, so initialize to 1.
252  (*hx)[width] = 1.0f;
253  (*hy)[height] = 1.0f;
254 }
255 
256 // Sets up the DENORM to execute a non-linear transformation based on
257 // preserving an even distribution of stroke edges. The transformation
258 // operates only within the given box.
259 // x_coords is a collection of the x-coords of vertical edges for each
260 // y-coord starting at box.bottom().
261 // y_coords is a collection of the y-coords of horizontal edges for each
262 // x-coord starting at box.left().
263 // Eg x_coords[0] is a collection of the x-coords of edges at y=bottom.
264 // Eg x_coords[1] is a collection of the x-coords of edges at y=bottom + 1.
265 // The second-level vectors must all be sorted in ascending order.
266 // See comments on the helper functions above for more details.
268  const DENORM* predecessor, const TBOX& box, float target_width,
269  float target_height, float final_xshift, float final_yshift,
270  const GenericVector<GenericVector<int> >& x_coords,
271  const GenericVector<GenericVector<int> >& y_coords) {
272  Clear();
273  predecessor_ = predecessor;
274  // x_map_ and y_map_ store a mapping from input x and y coordinate to output
275  // x and y coordinate, based on scaling to the supplied target_width and
276  // target_height.
277  x_map_ = new GenericVector<float>;
278  y_map_ = new GenericVector<float>;
279  // Set a 2-d image array to the run lengths at each pixel.
280  int width = box.width();
281  int height = box.height();
282  GENERIC_2D_ARRAY<int> minruns(width, height, 0);
283  ComputeRunlengthImage(box, x_coords, y_coords, &minruns);
284  // Edge density is the sum of the inverses of the run lengths. Compute
285  // edge density projection profiles.
286  ComputeEdgeDensityProfiles(box, minruns, x_map_, y_map_);
287  // Convert the edge density profiles to the coordinates by multiplying by
288  // the desired size and accumulating.
289  (*x_map_)[width] = target_width;
290  for (int x = width - 1; x >= 0; --x) {
291  (*x_map_)[x] = (*x_map_)[x + 1] - (*x_map_)[x] * target_width;
292  }
293  (*y_map_)[height] = target_height;
294  for (int y = height - 1; y >= 0; --y) {
295  (*y_map_)[y] = (*y_map_)[y + 1] - (*y_map_)[y] * target_height;
296  }
297  x_origin_ = box.left();
298  y_origin_ = box.bottom();
299  final_xshift_ = final_xshift;
300  final_yshift_ = final_yshift;
301 }
302 
303 // Transforms the given coords one step forward to normalized space, without
304 // using any block rotation or predecessor.
305 void DENORM::LocalNormTransform(const TPOINT& pt, TPOINT* transformed) const {
306  FCOORD src_pt(pt.x, pt.y);
307  FCOORD float_result;
308  LocalNormTransform(src_pt, &float_result);
309  transformed->x = IntCastRounded(float_result.x());
310  transformed->y = IntCastRounded(float_result.y());
311 }
312 void DENORM::LocalNormTransform(const FCOORD& pt, FCOORD* transformed) const {
313  FCOORD translated(pt.x() - x_origin_, pt.y() - y_origin_);
314  if (x_map_ != NULL && y_map_ != NULL) {
315  int x = ClipToRange(IntCastRounded(translated.x()), 0, x_map_->size()-1);
316  translated.set_x((*x_map_)[x]);
317  int y = ClipToRange(IntCastRounded(translated.y()), 0, y_map_->size()-1);
318  translated.set_y((*y_map_)[y]);
319  } else {
320  translated.set_x(translated.x() * x_scale_);
321  translated.set_y(translated.y() * y_scale_);
322  if (rotation_ != NULL)
323  translated.rotate(*rotation_);
324  }
325  transformed->set_x(translated.x() + final_xshift_);
326  transformed->set_y(translated.y() + final_yshift_);
327 }
328 
329 // Transforms the given coords forward to normalized space using the
330 // full transformation sequence defined by the block rotation, the
331 // predecessors, deepest first, and finally this. If first_norm is not NULL,
332 // then the first and deepest transformation used is first_norm, ending
333 // with this, and the block rotation will not be applied.
334 void DENORM::NormTransform(const DENORM* first_norm, const TPOINT& pt,
335  TPOINT* transformed) const {
336  FCOORD src_pt(pt.x, pt.y);
337  FCOORD float_result;
338  NormTransform(first_norm, src_pt, &float_result);
339  transformed->x = IntCastRounded(float_result.x());
340  transformed->y = IntCastRounded(float_result.y());
341 }
342 void DENORM::NormTransform(const DENORM* first_norm, const FCOORD& pt,
343  FCOORD* transformed) const {
344  FCOORD src_pt(pt);
345  if (first_norm != this) {
346  if (predecessor_ != NULL) {
347  predecessor_->NormTransform(first_norm, pt, &src_pt);
348  } else if (block_ != NULL) {
349  FCOORD fwd_rotation(block_->re_rotation().x(),
350  -block_->re_rotation().y());
351  src_pt.rotate(fwd_rotation);
352  }
353  }
354  LocalNormTransform(src_pt, transformed);
355 }
356 
357 // Transforms the given coords one step back to source space, without
358 // using to any block rotation or predecessor.
359 void DENORM::LocalDenormTransform(const TPOINT& pt, TPOINT* original) const {
360  FCOORD src_pt(pt.x, pt.y);
361  FCOORD float_result;
362  LocalDenormTransform(src_pt, &float_result);
363  original->x = IntCastRounded(float_result.x());
364  original->y = IntCastRounded(float_result.y());
365 }
366 void DENORM::LocalDenormTransform(const FCOORD& pt, FCOORD* original) const {
367  FCOORD rotated(pt.x() - final_xshift_, pt.y() - final_yshift_);
368  if (x_map_ != NULL && y_map_ != NULL) {
369  int x = x_map_->binary_search(rotated.x());
370  original->set_x(x + x_origin_);
371  int y = y_map_->binary_search(rotated.y());
372  original->set_y(y + y_origin_);
373  } else {
374  if (rotation_ != NULL) {
375  FCOORD inverse_rotation(rotation_->x(), -rotation_->y());
376  rotated.rotate(inverse_rotation);
377  }
378  original->set_x(rotated.x() / x_scale_ + x_origin_);
379  float y_scale = y_scale_;
380  original->set_y(rotated.y() / y_scale + y_origin_);
381  }
382 }
383 
384 // Transforms the given coords all the way back to source image space using
385 // the full transformation sequence defined by this and its predecessors
386 // recursively, shallowest first, and finally any block re_rotation.
387 // If last_denorm is not NULL, then the last transformation used will
388 // be last_denorm, and the block re_rotation will never be executed.
389 void DENORM::DenormTransform(const DENORM* last_denorm, const TPOINT& pt,
390  TPOINT* original) const {
391  FCOORD src_pt(pt.x, pt.y);
392  FCOORD float_result;
393  DenormTransform(last_denorm, src_pt, &float_result);
394  original->x = IntCastRounded(float_result.x());
395  original->y = IntCastRounded(float_result.y());
396 }
397 void DENORM::DenormTransform(const DENORM* last_denorm, const FCOORD& pt,
398  FCOORD* original) const {
399  LocalDenormTransform(pt, original);
400  if (last_denorm != this) {
401  if (predecessor_ != NULL) {
402  predecessor_->DenormTransform(last_denorm, *original, original);
403  } else if (block_ != NULL) {
404  original->rotate(block_->re_rotation());
405  }
406  }
407 }
408 
409 // Normalize a blob using blob transformations. Less accurate, but
410 // more accurately copies the old way.
411 void DENORM::LocalNormBlob(TBLOB* blob) const {
412  TBOX blob_box = blob->bounding_box();
413  ICOORD translation(-IntCastRounded(x_origin_), -IntCastRounded(y_origin_));
414  blob->Move(translation);
415  if (y_scale_ != 1.0f)
416  blob->Scale(y_scale_);
417  if (rotation_ != NULL)
418  blob->Rotate(*rotation_);
419  translation.set_x(IntCastRounded(final_xshift_));
420  translation.set_y(IntCastRounded(final_yshift_));
421  blob->Move(translation);
422 }
423 
424 // Fills in the x-height range accepted by the given unichar_id, given its
425 // bounding box in the usual baseline-normalized coordinates, with some
426 // initial crude x-height estimate (such as word size) and this denoting the
427 // transformation that was used.
428 void DENORM::XHeightRange(int unichar_id, const UNICHARSET& unicharset,
429  const TBOX& bbox,
430  float* min_xht, float* max_xht, float* yshift) const {
431  // Default return -- accept anything.
432  *yshift = 0.0f;
433  *min_xht = 0.0f;
434  *max_xht = MAX_FLOAT32;
435 
436  if (!unicharset.top_bottom_useful())
437  return;
438 
439  // Clip the top and bottom to the limit of normalized feature space.
440  int top = ClipToRange<int>(bbox.top(), 0, kBlnCellHeight - 1);
441  int bottom = ClipToRange<int>(bbox.bottom(), 0, kBlnCellHeight - 1);
442  // A tolerance of yscale corresponds to 1 pixel in the image.
443  double tolerance = y_scale();
444  // If the script doesn't have upper and lower-case characters, widen the
445  // tolerance to allow sloppy baseline/x-height estimates.
446  if (!unicharset.script_has_upper_lower())
447  tolerance = y_scale() * kSloppyTolerance;
448 
449  int min_bottom, max_bottom, min_top, max_top;
450  unicharset.get_top_bottom(unichar_id, &min_bottom, &max_bottom,
451  &min_top, &max_top);
452 
453  // Calculate the scale factor we'll use to get to image y-pixels
454  double midx = (bbox.left() + bbox.right()) / 2.0;
455  double ydiff = (bbox.top() - bbox.bottom()) + 2.0;
456  FCOORD mid_bot(midx, bbox.bottom()), tmid_bot;
457  FCOORD mid_high(midx, bbox.bottom() + ydiff), tmid_high;
458  DenormTransform(NULL, mid_bot, &tmid_bot);
459  DenormTransform(NULL, mid_high, &tmid_high);
460 
461  // bln_y_measure * yscale = image_y_measure
462  double yscale = tmid_high.pt_to_pt_dist(tmid_bot) / ydiff;
463 
464  // Calculate y-shift
465  int bln_yshift = 0, bottom_shift = 0, top_shift = 0;
466  if (bottom < min_bottom - tolerance) {
467  bottom_shift = bottom - min_bottom;
468  } else if (bottom > max_bottom + tolerance) {
469  bottom_shift = bottom - max_bottom;
470  }
471  if (top < min_top - tolerance) {
472  top_shift = top - min_top;
473  } else if (top > max_top + tolerance) {
474  top_shift = top - max_top;
475  }
476  if ((top_shift >= 0 && bottom_shift > 0) ||
477  (top_shift < 0 && bottom_shift < 0)) {
478  bln_yshift = (top_shift + bottom_shift) / 2;
479  }
480  *yshift = bln_yshift * yscale;
481 
482  // To help very high cap/xheight ratio fonts accept the correct x-height,
483  // and to allow the large caps in small caps to accept the xheight of the
484  // small caps, add kBlnBaselineOffset to chars with a maximum max, and have
485  // a top already at a significantly high position.
486  if (max_top == kBlnCellHeight - 1 &&
488  max_top += kBlnBaselineOffset;
489  top -= bln_yshift;
490  int height = top - kBlnBaselineOffset;
491  double min_height = min_top - kBlnBaselineOffset - tolerance;
492  double max_height = max_top - kBlnBaselineOffset + tolerance;
493 
494  // We shouldn't try calculations if the characters are very short (for example
495  // for punctuation).
496  if (min_height > kBlnXHeight / 8 && height > 0) {
497  float result = height * kBlnXHeight * yscale / min_height;
498  *max_xht = result + kFinalPixelTolerance;
499  result = height * kBlnXHeight * yscale / max_height;
500  *min_xht = result - kFinalPixelTolerance;
501  }
502 }
503 
504 // Prints the content of the DENORM for debug purposes.
505 void DENORM::Print() const {
506  if (pix_ != NULL) {
507  tprintf("Pix dimensions %d x %d x %d\n",
508  pixGetWidth(pix_), pixGetHeight(pix_), pixGetDepth(pix_));
509  }
510  if (inverse_)
511  tprintf("Inverse\n");
512  if (block_ && block_->re_rotation().x() != 1.0f) {
513  tprintf("Block rotation %g, %g\n",
514  block_->re_rotation().x(), block_->re_rotation().y());
515  }
516  tprintf("Input Origin = (%g, %g)\n", x_origin_, y_origin_);
517  if (x_map_ != NULL && y_map_ != NULL) {
518  tprintf("x map:\n");
519  for (int x = 0; x < x_map_->size(); ++x) {
520  tprintf("%g ", (*x_map_)[x]);
521  }
522  tprintf("\ny map:\n");
523  for (int y = 0; y < y_map_->size(); ++y) {
524  tprintf("%g ", (*y_map_)[y]);
525  }
526  tprintf("\n");
527  } else {
528  tprintf("Scale = (%g, %g)\n", x_scale_, y_scale_);
529  if (rotation_ != NULL)
530  tprintf("Rotation = (%g, %g)\n", rotation_->x(), rotation_->y());
531  }
532  tprintf("Final Origin = (%g, %g)\n", final_xshift_, final_xshift_);
533  if (predecessor_ != NULL) {
534  tprintf("Predecessor:\n");
535  predecessor_->Print();
536  }
537 }
538 
539 
540 // ============== Private Code ======================
541 
542 // Free allocated memory and clear pointers.
543 void DENORM::Clear() {
544  if (x_map_ != NULL) {
545  delete x_map_;
546  x_map_ = NULL;
547  }
548  if (y_map_ != NULL) {
549  delete y_map_;
550  y_map_ = NULL;
551  }
552  if (rotation_ != NULL) {
553  delete rotation_;
554  rotation_ = NULL;
555  }
556 }
557 
558 // Setup default values.
559 void DENORM::Init() {
560  inverse_ = false;
561  pix_ = NULL;
562  block_ = NULL;
563  rotation_ = NULL;
564  predecessor_ = NULL;
565  x_map_ = NULL;
566  y_map_ = NULL;
567  x_origin_ = 0.0f;
568  y_origin_ = 0.0f;
569  x_scale_ = 1.0f;
570  y_scale_ = 1.0f;
571  final_xshift_ = 0.0f;
572  final_yshift_ = static_cast<float>(kBlnBaselineOffset);
573 }
Definition: points.h:189
void NormTransform(const DENORM *first_norm, const TPOINT &pt, TPOINT *transformed) const
Definition: normalis.cpp:334
const DENORM * predecessor() const
Definition: normalis.h:265
void init_to_size(int size, T t)
void rotate(const FCOORD vec)
Definition: ipoints.h:471
void set_x(inT16 xin)
rewrite function
Definition: points.h:61
DENORM & operator=(const DENORM &)
Definition: normalis.cpp:47
void Rotate(const FCOORD rotation)
Definition: blobs.cpp:441
const int kBlnXHeight
Definition: normalis.h:28
void XHeightRange(int unichar_id, const UNICHARSET &unicharset, const TBOX &bbox, float *min_xht, float *max_xht, float *yshift) const
Definition: normalis.cpp:428
#define tprintf(...)
Definition: tprintf.h:31
void Scale(float factor)
Definition: blobs.cpp:455
const int kBlnBaselineOffset
Definition: normalis.h:29
void SetupNormalization(const BLOCK *block, const FCOORD *rotation, const DENORM *predecessor, float x_origin, float y_origin, float x_scale, float y_scale, float final_xshift, float final_yshift)
Definition: normalis.cpp:95
void set_x(float xin)
rewrite function
Definition: points.h:216
float y_scale() const
Definition: normalis.h:272
int IntCastRounded(double x)
Definition: helpers.h:179
void Print() const
Definition: normalis.cpp:505
int size() const
Definition: genericvector.h:72
void LocalNormTransform(const TPOINT &pt, TPOINT *transformed) const
Definition: normalis.cpp:305
void set_y(float yin)
rewrite function
Definition: points.h:220
const int kBlnCellHeight
Definition: normalis.h:27
#define ASSERT_HOST(x)
Definition: errcode.h:84
void Move(const ICOORD vec)
Definition: blobs.cpp:448
inT16 left() const
Definition: rect.h:68
int dim1() const
Definition: matrix.h:201
~DENORM()
Definition: normalis.cpp:66
int dim2() const
Definition: matrix.h:202
void DenormTransform(const DENORM *last_denorm, const TPOINT &pt, TPOINT *original) const
Definition: normalis.cpp:389
void LocalNormBlob(TBLOB *blob) const
Definition: normalis.cpp:411
void get_top_bottom(UNICHAR_ID unichar_id, int *min_bottom, int *max_bottom, int *min_top, int *max_top) const
Definition: unicharset.h:528
const BLOCK * block() const
Definition: normalis.h:275
inT16 x
Definition: blobs.h:71
T ClipToRange(const T &x, const T &lower_bound, const T &upper_bound)
Definition: helpers.h:122
DENORM()
Definition: normalis.cpp:37
#define MAX_FLOAT32
Definition: host.h:66
int binary_search(const T &target) const
inT16 top() const
Definition: rect.h:54
float x_scale() const
Definition: normalis.h:269
inT16 y
Definition: blobs.h:72
Definition: rect.h:30
Definition: blobs.h:261
Definition: blobs.h:50
inT16 height() const
Definition: rect.h:104
const float kFinalPixelTolerance
Definition: normalis.cpp:35
float y() const
Definition: points.h:212
inT16 right() const
Definition: rect.h:75
inT16 width() const
Definition: rect.h:111
void SetupNonLinear(const DENORM *predecessor, const TBOX &box, float target_width, float target_height, float final_xshift, float final_yshift, const GenericVector< GenericVector< int > > &x_coords, const GenericVector< GenericVector< int > > &y_coords)
Definition: normalis.cpp:267
FCOORD re_rotation() const
Definition: ocrblock.h:138
inT16 bottom() const
Definition: rect.h:61
const int kSloppyTolerance
Definition: normalis.cpp:33
void LocalDenormTransform(const TPOINT &pt, TPOINT *original) const
Definition: normalis.cpp:359
TBOX bounding_box() const
Definition: blobs.cpp:482
bool top_bottom_useful() const
Definition: unicharset.h:497
bool script_has_upper_lower() const
Definition: unicharset.h:856
float x() const
Definition: points.h:209
Definition: ocrblock.h:30
void set_y(inT16 yin)
rewrite function
Definition: points.h:65
integer coordinate
Definition: points.h:30