tesseract 4.1.1
Loading...
Searching...
No Matches
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 <cfloat> // for FLT_MAX
23#include <cstdlib>
24
25#include "allheaders.h"
26#include "blobs.h"
27#include "helpers.h"
28#include "matrix.h"
29#include "ocrblock.h"
30#include "unicharset.h"
31#include "werd.h"
32
33// Tolerance in pixels used for baseline and xheight on non-upper/lower scripts.
34const int kSloppyTolerance = 4;
35// Final tolerance in pixels added to the computed xheight range.
36const float kFinalPixelTolerance = 0.125f;
37
39 Init();
40}
41
43 rotation_ = nullptr;
44 *this = src;
45}
46
47
49 Clear();
50 inverse_ = src.inverse_;
51 predecessor_ = src.predecessor_;
52 pix_ = src.pix_;
53 block_ = src.block_;
54 if (src.rotation_ == nullptr)
55 rotation_ = nullptr;
56 else
57 rotation_ = new FCOORD(*src.rotation_);
58 x_origin_ = src.x_origin_;
59 y_origin_ = src.y_origin_;
60 x_scale_ = src.x_scale_;
61 y_scale_ = src.y_scale_;
62 final_xshift_ = src.final_xshift_;
63 final_yshift_ = src.final_yshift_;
64 return *this;
65}
66
68 Clear();
69}
70
71// Initializes the denorm for a transformation. For details see the large
72// comment in normalis.h.
73// Arguments:
74// block: if not nullptr, then this is the first transformation, and
75// block->re_rotation() needs to be used after the Denorm
76// transformation to get back to the image coords.
77// rotation: if not nullptr, apply this rotation after translation to the
78// origin and scaling. (Usually a classify rotation.)
79// predecessor: if not nullptr, then predecessor has been applied to the
80// input space and needs to be undone to complete the inverse.
81// The above pointers are not owned by this DENORM and are assumed to live
82// longer than this denorm, except rotation, which is deep copied on input.
83//
84// x_origin: The x origin which will be mapped to final_xshift in the result.
85// y_origin: The y origin which will be mapped to final_yshift in the result.
86// Added to result of row->baseline(x) if not nullptr.
87//
88// x_scale: scale factor for the x-coordinate.
89// y_scale: scale factor for the y-coordinate. Ignored if segs is given.
90// Note that these scale factors apply to the same x and y system as the
91// x-origin and y-origin apply, ie after any block rotation, but before
92// the rotation argument is applied.
93//
94// final_xshift: The x component of the final translation.
95// final_yshift: The y component of the final translation.
97 const FCOORD* rotation,
98 const DENORM* predecessor,
99 float x_origin, float y_origin,
100 float x_scale, float y_scale,
101 float final_xshift, float final_yshift) {
102 Clear();
103 block_ = block;
104 if (rotation == nullptr)
105 rotation_ = nullptr;
106 else
107 rotation_ = new FCOORD(*rotation);
108 predecessor_ = predecessor;
109 x_origin_ = x_origin;
110 y_origin_ = y_origin;
111 x_scale_ = x_scale;
112 y_scale_ = y_scale;
113 final_xshift_ = final_xshift;
114 final_yshift_ = final_yshift;
115}
116
117// Helper for SetupNonLinear computes an image of shortest run-lengths from
118// the x/y edges provided.
119// Based on "A nonlinear normalization method for handprinted Kanji character
120// recognition -- line density equalization" by Hiromitsu Yamada et al.
121// Eg below is an O in a 1-pixel margin-ed bounding box and the corresponding
122// ______________ input x_coords and y_coords.
123// | _________ | <empty>
124// | | _ | | 1, 6
125// | | | | | | 1, 3, 4, 6
126// | | | | | | 1, 3, 4, 6
127// | | | | | | 1, 3, 4, 6
128// | | |_| | | 1, 3, 4, 6
129// | |_________| | 1, 6
130// |_____________| <empty>
131// E 1 1 1 1 1 E
132// m 7 7 2 7 7 m
133// p 6 p
134// t 7 t
135// y y
136// The output image contains the min of the x and y run-length (distance
137// between edges) at each coordinate in the image thus:
138// ______________
139// |7 1_1_1_1_1 7|
140// |1|5 5 1 5 5|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|2 2|1|2 2|1|
145// |1|5_5_1_5_5|1|
146// |7_1_1_1_1_1_7|
147// Note that the input coords are all integer, so all partial pixels are dealt
148// with elsewhere. Although it is nice for outlines to be properly connected
149// and continuous, there is no requirement that they be as such, so they could
150// have been derived from a flaky source, such as greyscale.
151// This function works only within the provided box, and it is assumed that the
152// input x_coords and y_coords have already been translated to have the bottom-
153// left of box as the origin. Although an output, the minruns should have been
154// pre-initialized to be the same size as box. Each element will contain the
155// minimum of x and y run-length as shown above.
156static void ComputeRunlengthImage(
157 const TBOX& box,
158 const GenericVector<GenericVector<int> >& x_coords,
159 const GenericVector<GenericVector<int> >& y_coords,
160 GENERIC_2D_ARRAY<int>* minruns) {
161 int width = box.width();
162 int height = box.height();
163 ASSERT_HOST(minruns->dim1() == width);
164 ASSERT_HOST(minruns->dim2() == height);
165 // Set a 2-d image array to the run lengths at each pixel.
166 for (int ix = 0; ix < width; ++ix) {
167 int y = 0;
168 for (int i = 0; i < y_coords[ix].size(); ++i) {
169 int y_edge = ClipToRange(y_coords[ix][i], 0, height);
170 int gap = y_edge - y;
171 // Every pixel between the last and current edge get set to the gap.
172 while (y < y_edge) {
173 (*minruns)(ix, y) = gap;
174 ++y;
175 }
176 }
177 // Pretend there is a bounding box of edges all around the image.
178 int gap = height - y;
179 while (y < height) {
180 (*minruns)(ix, y) = gap;
181 ++y;
182 }
183 }
184 // Now set the image pixels the the MIN of the x and y runlengths.
185 for (int iy = 0; iy < height; ++iy) {
186 int x = 0;
187 for (int i = 0; i < x_coords[iy].size(); ++i) {
188 int x_edge = ClipToRange(x_coords[iy][i], 0, width);
189 int gap = x_edge - x;
190 while (x < x_edge) {
191 if (gap < (*minruns)(x, iy))
192 (*minruns)(x, iy) = gap;
193 ++x;
194 }
195 }
196 int gap = width - x;
197 while (x < width) {
198 if (gap < (*minruns)(x, iy))
199 (*minruns)(x, iy) = gap;
200 ++x;
201 }
202 }
203}
204// Converts the run-length image (see above to the edge density profiles used
205// for scaling, thus:
206// ______________
207// |7 1_1_1_1_1 7| = 5.28
208// |1|5 5 1 5 5|1| = 3.8
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|2 2|1|2 2|1| = 5
213// |1|5_5_1_5_5|1| = 3.8
214// |7_1_1_1_1_1_7| = 5.28
215// 6 4 4 8 4 4 6
216// . . . . . . .
217// 2 4 4 0 4 4 2
218// 8 8
219// Each profile is the sum of the reciprocals of the pixels in the image in
220// the appropriate row or column, and these are then normalized to sum to 1.
221// On output hx, hy contain an extra element, which will eventually be used
222// to guarantee that the top/right edge of the box (and anything beyond) always
223// gets mapped to the maximum target coordinate.
224static void ComputeEdgeDensityProfiles(const TBOX& box,
225 const GENERIC_2D_ARRAY<int>& minruns,
228 int width = box.width();
229 int height = box.height();
230 hx->init_to_size(width + 1, 0.0);
231 hy->init_to_size(height + 1, 0.0);
232 double total = 0.0;
233 for (int iy = 0; iy < height; ++iy) {
234 for (int ix = 0; ix < width; ++ix) {
235 int run = minruns(ix, iy);
236 if (run == 0) run = 1;
237 float density = 1.0f / run;
238 (*hx)[ix] += density;
239 (*hy)[iy] += density;
240 }
241 total += (*hy)[iy];
242 }
243 // Normalize each profile to sum to 1.
244 if (total > 0.0) {
245 for (int ix = 0; ix < width; ++ix) {
246 (*hx)[ix] /= total;
247 }
248 for (int iy = 0; iy < height; ++iy) {
249 (*hy)[iy] /= total;
250 }
251 }
252 // There is an extra element in each array, so initialize to 1.
253 (*hx)[width] = 1.0f;
254 (*hy)[height] = 1.0f;
255}
256
257// Sets up the DENORM to execute a non-linear transformation based on
258// preserving an even distribution of stroke edges. The transformation
259// operates only within the given box.
260// x_coords is a collection of the x-coords of vertical edges for each
261// y-coord starting at box.bottom().
262// y_coords is a collection of the y-coords of horizontal edges for each
263// x-coord starting at box.left().
264// Eg x_coords[0] is a collection of the x-coords of edges at y=bottom.
265// Eg x_coords[1] is a collection of the x-coords of edges at y=bottom + 1.
266// The second-level vectors must all be sorted in ascending order.
267// See comments on the helper functions above for more details.
269 const DENORM* predecessor, const TBOX& box, float target_width,
270 float target_height, float final_xshift, float final_yshift,
271 const GenericVector<GenericVector<int> >& x_coords,
272 const GenericVector<GenericVector<int> >& y_coords) {
273 Clear();
274 predecessor_ = predecessor;
275 // x_map_ and y_map_ store a mapping from input x and y coordinate to output
276 // x and y coordinate, based on scaling to the supplied target_width and
277 // target_height.
278 x_map_ = new GenericVector<float>;
279 y_map_ = new GenericVector<float>;
280 // Set a 2-d image array to the run lengths at each pixel.
281 int width = box.width();
282 int height = box.height();
283 GENERIC_2D_ARRAY<int> minruns(width, height, 0);
284 ComputeRunlengthImage(box, x_coords, y_coords, &minruns);
285 // Edge density is the sum of the inverses of the run lengths. Compute
286 // edge density projection profiles.
287 ComputeEdgeDensityProfiles(box, minruns, x_map_, y_map_);
288 // Convert the edge density profiles to the coordinates by multiplying by
289 // the desired size and accumulating.
290 (*x_map_)[width] = target_width;
291 for (int x = width - 1; x >= 0; --x) {
292 (*x_map_)[x] = (*x_map_)[x + 1] - (*x_map_)[x] * target_width;
293 }
294 (*y_map_)[height] = target_height;
295 for (int y = height - 1; y >= 0; --y) {
296 (*y_map_)[y] = (*y_map_)[y + 1] - (*y_map_)[y] * target_height;
297 }
298 x_origin_ = box.left();
299 y_origin_ = box.bottom();
300 final_xshift_ = final_xshift;
301 final_yshift_ = final_yshift;
302}
303
304// Transforms the given coords one step forward to normalized space, without
305// using any block rotation or predecessor.
306void DENORM::LocalNormTransform(const TPOINT& pt, TPOINT* transformed) const {
307 FCOORD src_pt(pt.x, pt.y);
308 FCOORD float_result;
309 LocalNormTransform(src_pt, &float_result);
310 transformed->x = IntCastRounded(float_result.x());
311 transformed->y = IntCastRounded(float_result.y());
312}
313void DENORM::LocalNormTransform(const FCOORD& pt, FCOORD* transformed) const {
314 FCOORD translated(pt.x() - x_origin_, pt.y() - y_origin_);
315 if (x_map_ != nullptr && y_map_ != nullptr) {
316 int x = ClipToRange(IntCastRounded(translated.x()), 0, x_map_->size()-1);
317 translated.set_x((*x_map_)[x]);
318 int y = ClipToRange(IntCastRounded(translated.y()), 0, y_map_->size()-1);
319 translated.set_y((*y_map_)[y]);
320 } else {
321 translated.set_x(translated.x() * x_scale_);
322 translated.set_y(translated.y() * y_scale_);
323 if (rotation_ != nullptr)
324 translated.rotate(*rotation_);
325 }
326 transformed->set_x(translated.x() + final_xshift_);
327 transformed->set_y(translated.y() + final_yshift_);
328}
329
330// Transforms the given coords forward to normalized space using the
331// full transformation sequence defined by the block rotation, the
332// predecessors, deepest first, and finally this. If first_norm is not nullptr,
333// then the first and deepest transformation used is first_norm, ending
334// with this, and the block rotation will not be applied.
335void DENORM::NormTransform(const DENORM* first_norm, const TPOINT& pt,
336 TPOINT* transformed) const {
337 FCOORD src_pt(pt.x, pt.y);
338 FCOORD float_result;
339 NormTransform(first_norm, src_pt, &float_result);
340 transformed->x = IntCastRounded(float_result.x());
341 transformed->y = IntCastRounded(float_result.y());
342}
343void DENORM::NormTransform(const DENORM* first_norm, const FCOORD& pt,
344 FCOORD* transformed) const {
345 FCOORD src_pt(pt);
346 if (first_norm != this) {
347 if (predecessor_ != nullptr) {
348 predecessor_->NormTransform(first_norm, pt, &src_pt);
349 } else if (block_ != nullptr) {
350 FCOORD fwd_rotation(block_->re_rotation().x(),
351 -block_->re_rotation().y());
352 src_pt.rotate(fwd_rotation);
353 }
354 }
355 LocalNormTransform(src_pt, transformed);
356}
357
358// Transforms the given coords one step back to source space, without
359// using to any block rotation or predecessor.
360void DENORM::LocalDenormTransform(const TPOINT& pt, TPOINT* original) const {
361 FCOORD src_pt(pt.x, pt.y);
362 FCOORD float_result;
363 LocalDenormTransform(src_pt, &float_result);
364 original->x = IntCastRounded(float_result.x());
365 original->y = IntCastRounded(float_result.y());
366}
367void DENORM::LocalDenormTransform(const FCOORD& pt, FCOORD* original) const {
368 FCOORD rotated(pt.x() - final_xshift_, pt.y() - final_yshift_);
369 if (x_map_ != nullptr && y_map_ != nullptr) {
370 int x = x_map_->binary_search(rotated.x());
371 original->set_x(x + x_origin_);
372 int y = y_map_->binary_search(rotated.y());
373 original->set_y(y + y_origin_);
374 } else {
375 if (rotation_ != nullptr) {
376 FCOORD inverse_rotation(rotation_->x(), -rotation_->y());
377 rotated.rotate(inverse_rotation);
378 }
379 original->set_x(rotated.x() / x_scale_ + x_origin_);
380 float y_scale = y_scale_;
381 original->set_y(rotated.y() / y_scale + y_origin_);
382 }
383}
384
385// Transforms the given coords all the way back to source image space using
386// the full transformation sequence defined by this and its predecessors
387// recursively, shallowest first, and finally any block re_rotation.
388// If last_denorm is not nullptr, then the last transformation used will
389// be last_denorm, and the block re_rotation will never be executed.
390void DENORM::DenormTransform(const DENORM* last_denorm, const TPOINT& pt,
391 TPOINT* original) const {
392 FCOORD src_pt(pt.x, pt.y);
393 FCOORD float_result;
394 DenormTransform(last_denorm, src_pt, &float_result);
395 original->x = IntCastRounded(float_result.x());
396 original->y = IntCastRounded(float_result.y());
397}
398void DENORM::DenormTransform(const DENORM* last_denorm, const FCOORD& pt,
399 FCOORD* original) const {
400 LocalDenormTransform(pt, original);
401 if (last_denorm != this) {
402 if (predecessor_ != nullptr) {
403 predecessor_->DenormTransform(last_denorm, *original, original);
404 } else if (block_ != nullptr) {
405 original->rotate(block_->re_rotation());
406 }
407 }
408}
409
410// Normalize a blob using blob transformations. Less accurate, but
411// more accurately copies the old way.
412void DENORM::LocalNormBlob(TBLOB* blob) const {
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_ != nullptr)
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.
428void 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 = FLT_MAX;
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(nullptr, mid_bot, &tmid_bot);
459 DenormTransform(nullptr, 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.
505void DENORM::Print() const {
506 if (pix_ != nullptr) {
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_ != nullptr && y_map_ != nullptr) {
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_ != nullptr)
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_ != nullptr) {
534 tprintf("Predecessor:\n");
535 predecessor_->Print();
536 }
537}
538
539
540// ============== Private Code ======================
541
542// Free allocated memory and clear pointers.
543void DENORM::Clear() {
544 delete x_map_;
545 x_map_ = nullptr;
546 delete y_map_;
547 y_map_ = nullptr;
548 delete rotation_;
549 rotation_ = nullptr;
550}
551
552// Setup default values.
553void DENORM::Init() {
554 inverse_ = false;
555 pix_ = nullptr;
556 block_ = nullptr;
557 rotation_ = nullptr;
558 predecessor_ = nullptr;
559 x_map_ = nullptr;
560 y_map_ = nullptr;
561 x_origin_ = 0.0f;
562 y_origin_ = 0.0f;
563 x_scale_ = 1.0f;
564 y_scale_ = 1.0f;
565 final_xshift_ = 0.0f;
566 final_yshift_ = static_cast<float>(kBlnBaselineOffset);
567}
const float kFinalPixelTolerance
Definition: normalis.cpp:36
const int kSloppyTolerance
Definition: normalis.cpp:34
const int kBlnBaselineOffset
Definition: normalis.h:25
const int kBlnCellHeight
Definition: normalis.h:23
const int kBlnXHeight
Definition: normalis.h:24
#define ASSERT_HOST(x)
Definition: errcode.h:88
int IntCastRounded(double x)
Definition: helpers.h:175
T ClipToRange(const T &x, const T &lower_bound, const T &upper_bound)
Definition: helpers.h:108
DLLSYM void tprintf(const char *format,...)
Definition: tprintf.cpp:35
void init_to_size(int size, const T &t)
int size() const
Definition: genericvector.h:72
int binary_search(const T &target) const
int dim2() const
Definition: matrix.h:210
int dim1() const
Definition: matrix.h:209
Definition: blobs.h:51
int16_t x
Definition: blobs.h:93
int16_t y
Definition: blobs.h:94
Definition: blobs.h:284
void Move(const ICOORD vec)
Definition: blobs.cpp:430
void Rotate(const FCOORD rotation)
Definition: blobs.cpp:422
void Scale(float factor)
Definition: blobs.cpp:438
void Print() const
Definition: normalis.cpp:505
void LocalDenormTransform(const TPOINT &pt, TPOINT *original) const
Definition: normalis.cpp:360
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:268
void LocalNormBlob(TBLOB *blob) const
Definition: normalis.cpp:412
void DenormTransform(const DENORM *last_denorm, const TPOINT &pt, TPOINT *original) const
Definition: normalis.cpp:390
DENORM()
Definition: normalis.cpp:38
float x_scale() const
Definition: normalis.h:267
DENORM & operator=(const DENORM &)
Definition: normalis.cpp:48
~DENORM()
Definition: normalis.cpp:67
void NormTransform(const DENORM *first_norm, const TPOINT &pt, TPOINT *transformed) const
Definition: normalis.cpp:335
void XHeightRange(int unichar_id, const UNICHARSET &unicharset, const TBOX &bbox, float *min_xht, float *max_xht, float *yshift) const
Definition: normalis.cpp:428
float y_scale() const
Definition: normalis.h:270
const DENORM * predecessor() const
Definition: normalis.h:263
void LocalNormTransform(const TPOINT &pt, TPOINT *transformed) const
Definition: normalis.cpp:306
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:96
const BLOCK * block() const
Definition: normalis.h:273
Definition: ocrblock.h:31
FCOORD re_rotation() const
Definition: ocrblock.h:134
integer coordinate
Definition: points.h:32
void set_x(int16_t xin)
rewrite function
Definition: points.h:61
void set_y(int16_t yin)
rewrite function
Definition: points.h:65
Definition: points.h:189
void rotate(const FCOORD vec)
Definition: points.h:763
float y() const
Definition: points.h:210
void set_y(float yin)
rewrite function
Definition: points.h:218
void set_x(float xin)
rewrite function
Definition: points.h:214
float x() const
Definition: points.h:207
float pt_to_pt_dist(const FCOORD &pt) const
Distance between pts.
Definition: points.h:242
Definition: rect.h:34
int16_t top() const
Definition: rect.h:58
int16_t width() const
Definition: rect.h:115
int16_t height() const
Definition: rect.h:108
int16_t left() const
Definition: rect.h:72
int16_t bottom() const
Definition: rect.h:65
int16_t right() const
Definition: rect.h:79
bool script_has_upper_lower() const
Definition: unicharset.h:897
bool top_bottom_useful() const
Definition: unicharset.h:537
void get_top_bottom(UNICHAR_ID unichar_id, int *min_bottom, int *max_bottom, int *min_top, int *max_top) const
Definition: unicharset.h:568