21 #include "config_auto.h"
27 #include "allheaders.h"
37 #define PROJECTION_MARGIN 10 //arbitrary
56 cblob_ptr->
rotate(rotation);
58 compute_bounding_box();
63 int left = -box.
right();
75 ICOORD bottom_pt(top_pt.x(), base_char_bottom_);
77 base_char_top_ = top_pt.y();
78 bottom_pt.rotate(rotation);
79 base_char_bottom_ = bottom_pt.y();
97 nextblob->joined =
true;
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());
121 BLOBNBOX_IT *start_it,
134 float test_ymin, test_ymax;
139 blobcount = static_cast<int16_t>(floor (box.
width () / xheight));
140 if (blobcount > 1 && cblob_ptr !=
nullptr) {
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);
149 blob = blob_it.data ();
152 test_ymin, test_ymax);
156 while (blob != end_it->data ());
158 leftx = static_cast<int16_t>(floor (rightx - blobwidth));
159 if (leftx < box.
left ())
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)));
168 newblob->box =
TBOX (bl, tr);
170 newblob->base_char_top_ = tr.
y();
171 newblob->base_char_bottom_ = bl.
y();
172 end_it->add_after_stay_put (newblob);
182 for (
int dir = 0; dir <
BND_COUNT; ++dir) {
183 gaps[dir] = INT16_MAX;
188 gaps[dir] = box.
x_gap(n_box);
190 gaps[dir] = box.
y_gap(n_box);
201 int* v_min,
int* v_max)
const {
202 int max_dimension = std::max(box.
width(), box.
height());
207 if (*h_max > max_dimension && *h_min < max_dimension) *h_max = *h_min;
210 if (*v_max > max_dimension && *v_min < max_dimension) *v_max = *v_min;
215 for (
int dir = 0; dir <
BND_COUNT; ++dir) {
218 neighbours_[dir] =
nullptr;
219 good_stroke_neighbours_[dir] =
false;
228 for (
int dir = 0; dir <
BND_COUNT; ++dir) {
229 auto bnd = static_cast<BlobNeighbourDir>(dir);
239 for (
int dir = 0; dir <
BND_COUNT; ++dir) {
240 auto bnd = static_cast<BlobNeighbourDir>(dir);
253 if (
cblob() ==
nullptr)
return false;
254 int box_perimeter = 2 * (box.
height() + box.
width());
265 perimeter -= 4 *
cblob()->
area() / perimeter;
266 perimeter -= 2 * box.
width();
280 perimeter -= 4 *
cblob()->
area() / perimeter;
281 perimeter -= 2 * box.
height();
293 if (box.
left() < other.box.
left() && box.
left() < other.left_rule_)
295 if (other.box.
left() < box.
left() && other.box.
left() < left_rule_)
297 if (box.
right() > other.box.
right() && box.
right() > other.right_rule_)
299 if (other.box.
right() > box.
right() && other.box.
right() > right_rule_)
306 double fractional_tolerance,
307 double constant_tolerance)
const {
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);
328 return p_ok || ((v_ok || h_ok) && (h_ok || h_zero) && (v_ok || v_zero));
334 FCOORD no_rotation(1.0f, 0.0f);
335 float top = box.
top();
336 float bottom = box.
bottom();
337 if (cblob_ptr !=
nullptr) {
339 static_cast<float>(right), no_rotation,
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;
358 baseline_y_ = box.
bottom();
359 if (cblob_ptr ==
nullptr)
return;
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();
373 BLOBNBOX_IT blob_it(blobs);
374 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
377 delete blob->
cblob();
378 delete blob_it.extract();
386 BLOBNBOX_LIST* blobs) {
389 int scale_factor = 1;
390 if (thresholds !=
nullptr && grey !=
nullptr) {
391 grey_height = pixGetHeight(grey);
392 thr_height = pixGetHeight(thresholds);
396 BLOBNBOX_IT blob_it(blobs);
397 for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
399 if (blob->
cblob() !=
nullptr) {
401 l_uint32 threshold = 128;
402 if (thresholds !=
nullptr && grey !=
nullptr) {
407 pixGetPixel(thresholds, pt.
x / scale_factor,
408 thr_height - 1 - pt.
y / scale_factor, &threshold);
416 #ifndef GRAPHICS_DISABLED
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);
436 BLOBNBOX_IT it(list);
437 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
440 blob->
plot(win, body_colour, child_colour);
488 if (cblob_ptr !=
nullptr)
489 cblob_ptr->
plot(window, blob_colour, child_colour);
511 C_OUTLINE_IT out_it = blob->
out_list ();
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 ();
519 for (stepindex = 0; stepindex < outline->
pathlength (); stepindex++) {
521 if (pos.
x () >= leftx && pos.
x () <= rightx) {
524 vec = outline->
step (stepindex);
550 C_OUTLINE_IT out_it = blob->
out_list ();
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 ();
557 for (stepindex = 0; stepindex < outline->
pathlength (); stepindex++) {
559 if (pos.
x () >= leftx && pos.
x () <= rightx) {
562 vec = outline->
step (stepindex);
587 C_OUTLINE_IT out_it = blob->
out_list ();
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 ();
594 for (stepindex = 0; stepindex < outline->
pathlength (); stepindex++) {
596 if (pos.
y () >= bottomy && pos.
y () <= topy) {
599 vec = outline->
step (stepindex);
615 C_OUTLINE_LIST out_list;
617 C_OUTLINE_IT in_it = blob->
out_list ();
619 C_OUTLINE_IT out_it = &out_list;
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));
624 return new C_BLOB (&out_list);
647 if (blob->
cblob() ==
nullptr)
698 initial_y_min = bottom;
701 BLOBNBOX_IT it = &blobs;
703 it.add_to_end (blob);
704 diff = top - bottom - row_size;
710 else if ((top - bottom) * 3 < row_size) {
711 diff = row_size / 3 + bottom - top;
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",
741 BLOBNBOX_IT it = &blobs;
743 it.add_to_end (blob);
744 allowed = row_size + y_min - y_max;
746 available = top > y_max ? top - y_max : 0;
749 available += y_min - bottom;
751 available += available;
752 if (available < allowed)
755 y_min -= (y_min - bottom) * allowed / available;
757 y_max += (top - y_max) * allowed / available;
772 BLOBNBOX_IT it = &blobs;
775 it.add_before_then_move (blob);
778 while (!it.cycled_list ()
779 && it.data ()->bounding_box ().left () <=
782 if (it.cycled_list ())
783 it.add_to_end (blob);
785 it.add_before_stay_put (blob);
802 if (blob_it.empty ())
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 ();
812 for (blob_it.mark_cycle_pt (); !blob_it.cycled_list (); blob_it.forward ()) {
813 blob = blob_it.data();
814 if (blob->
cblob() !=
nullptr)
825 void TO_ROW::clear() {
857 num_repeated_sets_ = -1;
875 for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
896 C_OUTLINE_IT out_it = outline->
child ();
900 for (stepindex = 0; stepindex < length; stepindex++) {
901 step = outline->
step (stepindex);
903 stats->
add (pos.
x (), -pos.
y ());
904 }
else if (step.
x () < 0) {
905 stats->
add (pos.
x () - 1, pos.
y ());
910 for (out_it.mark_cycle_pt (); !out_it.cycled_list (); out_it.forward ()) {
929 static void clear_blobnboxes(BLOBNBOX_LIST* boxes) {
930 BLOBNBOX_IT it = boxes;
933 for (it.mark_cycle_pt(); !it.cycled_list(); it.forward()) {
967 clear_blobnboxes(&
blobs);
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()) {
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);
1002 medium_it.add_after_then_move(blob);
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);
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);
1029 blob_it.add_list_after(&large_list);
1031 blob_it.add_list_after(&small_list);
1033 blob_it.add_list_after(&noise_list);
1061 #ifndef GRAPHICS_DISABLED
1087 BLOBNBOX_LIST *list,
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);
1095 #endif // GRAPHICS_DISABLED