22 #include "config_auto.h" 28 #include "allheaders.h" 38 #define PROJECTION_MARGIN 10 //arbitrary 57 cblob_ptr->
rotate(rotation);
59 compute_bounding_box();
64 int left = -box.
right();
76 ICOORD bottom_pt(top_pt.x(), base_char_bottom_);
78 base_char_top_ = top_pt.y();
79 bottom_pt.rotate(rotation);
80 base_char_bottom_ = bottom_pt.y();
98 nextblob->joined =
TRUE;
105 if (other->cblob_ptr !=
nullptr) {
106 C_OUTLINE_IT ol_it(cblob_ptr->
out_list());
107 ol_it.add_list_after(other->cblob_ptr->
out_list());
122 BLOBNBOX_IT *start_it,
135 float test_ymin, test_ymax;
140 blobcount = (int16_t) floor (box.
width () / xheight);
141 if (blobcount > 1 && cblob_ptr !=
nullptr) {
143 blobwidth = (float) (box.
width () + 1) / blobcount;
144 for (blobindex = blobcount - 1, rightx = box.
right ();
145 blobindex >= 0; blobindex--, rightx -= blobwidth) {
146 ymin = (float) INT32_MAX;
147 ymax = (float) -INT32_MAX;
150 blob = blob_it.data ();
153 test_ymin, test_ymax);
157 while (blob != end_it->data ());
159 leftx = (int16_t) floor (rightx - blobwidth);
160 if (leftx < box.
left ())
162 bl =
ICOORD (leftx, (int16_t) floor (ymin));
163 tr =
ICOORD ((int16_t) ceil (rightx), (int16_t) ceil (ymax));
169 newblob->box =
TBOX (bl, tr);
171 newblob->base_char_top_ = tr.
y();
172 newblob->base_char_bottom_ = bl.
y();
173 end_it->add_after_stay_put (newblob);
183 for (
int dir = 0; dir <
BND_COUNT; ++dir) {
184 gaps[dir] = INT16_MAX;
189 gaps[dir] = box.
x_gap(n_box);
191 gaps[dir] = box.
y_gap(n_box);
202 int* v_min,
int* v_max)
const {
203 int max_dimension = std::max(box.
width(), box.
height());
208 if (*h_max > max_dimension && *h_min < max_dimension) *h_max = *h_min;
211 if (*v_max > max_dimension && *v_min < max_dimension) *v_max = *v_min;
216 for (
int dir = 0; dir <
BND_COUNT; ++dir) {
219 neighbours_[dir] =
nullptr;
220 good_stroke_neighbours_[dir] =
false;
229 for (
int dir = 0; dir <
BND_COUNT; ++dir) {
240 for (
int dir = 0; dir <
BND_COUNT; ++dir) {
254 if (
cblob() ==
nullptr)
return false;
255 int box_perimeter = 2 * (box.
height() + box.
width());
266 perimeter -= 4 *
cblob()->
area() / perimeter;
267 perimeter -= 2 * box.
width();
281 perimeter -= 4 *
cblob()->
area() / perimeter;
282 perimeter -= 2 * box.
height();
294 if (box.
left() < other.box.
left() && box.
left() < other.left_rule_)
296 if (other.box.
left() < box.
left() && other.box.
left() < left_rule_)
298 if (box.
right() > other.box.
right() && box.
right() > other.right_rule_)
300 if (other.box.
right() > box.
right() && other.box.
right() > right_rule_)
307 double fractional_tolerance,
308 double constant_tolerance)
const {
313 float h_tolerance = horz_stroke_width_ * fractional_tolerance
314 + constant_tolerance;
315 float v_tolerance = vert_stroke_width_ * fractional_tolerance
316 + constant_tolerance;
317 double p_tolerance = p_width * fractional_tolerance
318 + constant_tolerance;
319 bool h_zero = horz_stroke_width_ == 0.0f || other.horz_stroke_width_ == 0.0f;
320 bool v_zero = vert_stroke_width_ == 0.0f || other.vert_stroke_width_ == 0.0f;
321 bool h_ok = !h_zero &&
NearlyEqual(horz_stroke_width_,
322 other.horz_stroke_width_, h_tolerance);
323 bool v_ok = !v_zero &&
NearlyEqual(vert_stroke_width_,
324 other.vert_stroke_width_, v_tolerance);
325 bool p_ok = h_zero && v_zero &&
NearlyEqual(p_width, n_p_width, p_tolerance);
329 return p_ok || ((v_ok || h_ok) && (h_ok || h_zero) && (v_ok || v_zero));
335 FCOORD no_rotation(1.0f, 0.0f);
336 float top = box.
top();
337 float bottom = box.
bottom();
338 if (cblob_ptr !=
nullptr) {
340 static_cast<float>(right), no_rotation,
348 FCOORD bot_left(left, bottom);
349 FCOORD top_right(right, top);
350 TBOX shrunken_box(bot_left);
351 TBOX shrunken_box2(top_right);
352 shrunken_box += shrunken_box2;
359 baseline_y_ = box.
bottom();
360 if (cblob_ptr ==
nullptr)
return;
366 BLOBNBOX_IT blob_it(blobs);
367 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
368 blob_it.data()->CleanNeighbours();
374 BLOBNBOX_IT blob_it(blobs);
375 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
378 delete blob->
cblob();
379 delete blob_it.extract();
387 BLOBNBOX_LIST* blobs) {
390 int scale_factor = 1;
391 if (thresholds !=
nullptr && grey !=
nullptr) {
392 grey_height = pixGetHeight(grey);
393 thr_height = pixGetHeight(thresholds);
397 BLOBNBOX_IT blob_it(blobs);
398 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
400 if (blob->
cblob() !=
nullptr) {
402 l_uint32 threshold = 128;
403 if (thresholds !=
nullptr && grey !=
nullptr) {
408 pixGetPixel(thresholds, pt.
x / scale_factor,
409 thr_height - 1 - pt.
y / scale_factor, &threshold);
417 #ifndef GRAPHICS_DISABLED 424 BLOBNBOX_IT it(list);
425 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
426 it.data()->plot(win, body_colour, child_colour);
437 BLOBNBOX_IT it(list);
438 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
441 blob->
plot(win, body_colour, child_colour);
489 if (cblob_ptr !=
nullptr)
490 cblob_ptr->
plot(window, blob_colour, child_colour);
512 C_OUTLINE_IT out_it = blob->
out_list ();
514 ymin = (float) INT32_MAX;
515 ymax = (float) -INT32_MAX;
516 for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
517 outline = out_it.data ();
520 for (stepindex = 0; stepindex < outline->
pathlength (); stepindex++) {
522 if (pos.
x () >= leftx && pos.
x () <= rightx) {
525 vec = outline->
step (stepindex);
551 C_OUTLINE_IT out_it = blob->
out_list ();
553 ymin = (float) INT32_MAX;
554 ymax = (float) -INT32_MAX;
555 for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
556 outline = out_it.data ();
558 for (stepindex = 0; stepindex < outline->
pathlength (); stepindex++) {
560 if (pos.
x () >= leftx && pos.
x () <= rightx) {
563 vec = outline->
step (stepindex);
588 C_OUTLINE_IT out_it = blob->
out_list ();
590 xmin = (float) INT32_MAX;
591 xmax = (float) -INT32_MAX;
592 for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
593 outline = out_it.data ();
595 for (stepindex = 0; stepindex < outline->
pathlength (); stepindex++) {
597 if (pos.
y () >= bottomy && pos.
y () <= topy) {
600 vec = outline->
step (stepindex);
616 C_OUTLINE_LIST out_list;
618 C_OUTLINE_IT in_it = blob->
out_list ();
620 C_OUTLINE_IT out_it = &out_list;
622 for (in_it.mark_cycle_pt (); !in_it.cycled_list (); in_it.forward ()) {
623 out_it.add_after_then_move (
new C_OUTLINE (in_it.data (), rotation));
625 return new C_BLOB (&out_list);
648 if (blob->
cblob() ==
nullptr)
699 initial_y_min = bottom;
702 BLOBNBOX_IT it = &blobs;
704 it.add_to_end (blob);
705 diff = top - bottom - row_size;
711 else if ((top - bottom) * 3 < row_size) {
712 diff = row_size / 3 + bottom - top;
719 tprintf(
"pitch=%d, fp=%g, fps=%g, fpns=%g, prs=%g, prns=%g," 720 " spacing=%g xh=%g y_origin=%g xev=%d, asc=%g, desc=%g," 721 " body=%g, minsp=%d maxnsp=%d, thr=%d kern=%g sp=%g\n",
742 BLOBNBOX_IT it = &blobs;
744 it.add_to_end (blob);
745 allowed = row_size + y_min - y_max;
747 available = top > y_max ? top - y_max : 0;
750 available += y_min - bottom;
752 available += available;
753 if (available < allowed)
756 y_min -= (y_min - bottom) * allowed / available;
758 y_max += (top - y_max) * allowed / available;
773 BLOBNBOX_IT it = &blobs;
776 it.add_before_then_move (blob);
779 while (!it.cycled_list ()
780 && it.data ()->bounding_box ().left () <=
783 if (it.cycled_list ())
784 it.add_to_end (blob);
786 it.add_before_stay_put (blob);
803 if (blob_it.empty ())
805 row_box = blob_it.data ()->bounding_box ();
806 for (blob_it.mark_cycle_pt (); !blob_it.cycled_list (); blob_it.forward ())
807 row_box += blob_it.data ()->bounding_box ();
813 for (blob_it.mark_cycle_pt (); !blob_it.cycled_list (); blob_it.forward ()) {
814 blob = blob_it.data();
815 if (blob->
cblob() !=
nullptr)
826 void TO_ROW::clear() {
858 num_repeated_sets_ = -1;
874 C_OUTLINE_IT out_it = blob->
out_list ();
876 for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
897 C_OUTLINE_IT out_it = outline->
child ();
901 for (stepindex = 0; stepindex < length; stepindex++) {
902 step = outline->
step (stepindex);
904 stats->
add (pos.
x (), -pos.
y ());
905 }
else if (step.
x () < 0) {
906 stats->
add (pos.
x () - 1, pos.
y ());
911 for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
930 static void clear_blobnboxes(BLOBNBOX_LIST* boxes) {
931 BLOBNBOX_IT it = boxes;
934 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
968 clear_blobnboxes(&
blobs);
980 static void SizeFilterBlobs(
int min_height,
int max_height,
981 BLOBNBOX_LIST* src_list,
982 BLOBNBOX_LIST* noise_list,
983 BLOBNBOX_LIST* small_list,
984 BLOBNBOX_LIST* medium_list,
985 BLOBNBOX_LIST* large_list) {
986 BLOBNBOX_IT noise_it(noise_list);
987 BLOBNBOX_IT small_it(small_list);
988 BLOBNBOX_IT medium_it(medium_list);
989 BLOBNBOX_IT large_it(large_list);
990 for (BLOBNBOX_IT src_it(src_list); !src_it.empty(); src_it.forward()) {
995 if (height < min_height &&
996 (width < min_height || width > max_height))
997 noise_it.add_after_then_move(blob);
998 else if (height > max_height)
999 large_it.add_after_then_move(blob);
1000 else if (height < min_height)
1001 small_it.add_after_then_move(blob);
1003 medium_it.add_after_then_move(blob);
1015 BLOBNBOX_LIST noise_list;
1016 BLOBNBOX_LIST small_list;
1017 BLOBNBOX_LIST medium_list;
1018 BLOBNBOX_LIST large_list;
1019 SizeFilterBlobs(min_height, max_height, &
blobs,
1020 &noise_list, &small_list, &medium_list, &large_list);
1021 SizeFilterBlobs(min_height, max_height, &
large_blobs,
1022 &noise_list, &small_list, &medium_list, &large_list);
1023 SizeFilterBlobs(min_height, max_height, &
small_blobs,
1024 &noise_list, &small_list, &medium_list, &large_list);
1025 SizeFilterBlobs(min_height, max_height, &
noise_blobs,
1026 &noise_list, &small_list, &medium_list, &large_list);
1027 BLOBNBOX_IT blob_it(&
blobs);
1028 blob_it.add_list_after(&medium_list);
1030 blob_it.add_list_after(&large_list);
1032 blob_it.add_list_after(&small_list);
1034 blob_it.add_list_after(&noise_list);
1062 #ifndef GRAPHICS_DISABLED 1088 BLOBNBOX_LIST *list,
1091 BLOBNBOX_IT it = list;
1092 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
1093 it.data()->plot(win, body_colour, child_colour);
1096 #endif // GRAPHICS_DISABLED
void ReSetAndReFilterBlobs()
float area_stroke_width() const
TBOX box_next_pre_chopped(BLOBNBOX_IT *it)
bool DeletableNoise() const
void set_vert_possible(bool value)
void insert_blob(BLOBNBOX *blob)
bool DefiniteIndividualFlow()
static void PlotBlobs(BLOBNBOX_LIST *list, ScrollView::Color body_colour, ScrollView::Color child_colour, ScrollView *win)
void compute_vertical_projection()
void rotate(const FCOORD &vec)
float horz_stroke_width() const
int NoisyNeighbours() const
int y_gap(const TBOX &box) const
void set_diacritic_box(const TBOX &diacritic_box)
static void PlotNoiseBlobs(BLOBNBOX_LIST *list, ScrollView::Color body_colour, ScrollView::Color child_colour, ScrollView *win)
void add_blob(BLOBNBOX *blob, float top, float bottom, float row_size)
TBOX BoundsWithinLimits(int left, int right)
int16_t y() const
access_function
const ICOORD & start_pos() const
void merge(BLOBNBOX *nextblob)
int x_gap(const TBOX &box) const
void plot_noise_blobs(ScrollView *to_win)
void plot(ScrollView *window, ScrollView::Color blob_colour, ScrollView::Color child_colour)
void plot_blob_list(ScrollView *win, BLOBNBOX_LIST *list, ScrollView::Color body_colour, ScrollView::Color child_colour)
void MinMaxGapsClipped(int *h_min, int *h_max, int *v_min, int *v_max) const
void ComputeEdgeOffsets(int threshold, Pix *pix)
TBOX box_next(BLOBNBOX_IT *it)
#define ELIST2IZE(CLASSNAME)
const double kComplexShapePerimeterRatio
void reflect_box_in_y_axis()
void plot_graded_blobs(ScrollView *to_win)
void set_horz_possible(bool value)
void rotate_box(FCOORD rotation)
bool NearlyEqual(T x, T y, T tolerance)
const double kMinMediumSizeRatio
PITCH_TYPE pitch_decision
bool good_stroke_neighbour(BlobNeighbourDir n) const
int16_t x() const
access function
void EstimateBaselinePosition()
BlobRegionType region_type() const
bool set_range(int32_t min_bucket_value, int32_t max_bucket_value_plus_1)
bool joined_to_prev() const
int IntCastRounded(double x)
void find_cblob_hlimits(C_BLOB *blob, float bottomy, float topy, float &xmin, float &xmax)
const double kMaxMediumSizeRatio
const double kCosSmallAngle
const double kDefiniteAspectRatio
void NeighbourGaps(int gaps[BND_COUNT]) const
#define ELISTIZE(CLASSNAME)
int32_t pathlength() const
DLLSYM void tprintf(const char *format,...)
float vert_stroke_width() const
void ComputeEdgeOffsets(Pix *thresholds, Pix *grey)
void chop(BLOBNBOX_IT *start_it, BLOBNBOX_IT *blob_it, FCOORD rotation, float xheight)
void DeleteUnownedNoise()
static void ComputeEdgeOffsets(Pix *thresholds, Pix *grey, BLOBNBOX_LIST *blobs)
void rotate(const FCOORD &vec)
void add(int32_t value, int32_t count)
int16_t EstimateBaselinePosition()
TBOX bounding_box() const
C_BLOB * crotate_cblob(C_BLOB *blob, FCOORD rotation)
C_OUTLINE_LIST * out_list()
void vertical_coutline_projection(C_OUTLINE *outline, STATS *stats)
void find_cblob_limits(C_BLOB *blob, float leftx, float rightx, FCOORD rotation, float &ymin, float &ymax)
const TBOX & bounding_box() const
void rotate(FCOORD rotation)
bool ConfirmNoTabViolation(const BLOBNBOX &other) const
void plot(ScrollView *window, ScrollView::Color blob_colour, ScrollView::Color child_colour)
ScrollView::Color BoxColor() const
static void DeleteNoiseBlobs(BLOBNBOX_LIST *blobs)
BLOBNBOX_LIST large_blobs
#define PROJECTION_MARGIN
BLOBNBOX * neighbour(BlobNeighbourDir n) const
void find_cblob_vlimits(C_BLOB *blob, float leftx, float rightx, float &ymin, float &ymax)
ICOORD step(int index) const
void vertical_cblob_projection(C_BLOB *blob, STATS *stats)
void really_merge(BLOBNBOX *other)
BLOBNBOX_LIST * blob_list()
void compute_bounding_box()
BLOBNBOX_LIST small_blobs
bool MatchingStrokeWidth(const BLOBNBOX &other, double fractional_tolerance, double constant_tolerance) const
BLOBNBOX_LIST noise_blobs
void UpdateRange(const T1 &x, T2 *lower_bound, T2 *upper_bound)
PITCH_TYPE pitch_decision
static ScrollView::Color TextlineColor(BlobRegionType region_type, BlobTextFlowType flow_type)