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