48 int16_t half_pitch = pitch / 2 - 1;
52 if (half_pitch > 31) {
54 }
else if (half_pitch < 0) {
57 lead_flag = 1 << half_pitch;
61 sq_sum = offset * offset;
69 if (
x == array_origin) {
72 for (ind = 0; ind <= half_pitch; ind++) {
74 if (projection->
pile_count(ind) > zero_count) {
75 fwd_balance |= lead_flag;
79 back_balance = cutpts[
x - 1 - array_origin].back_balance << 1;
80 back_balance &= lead_flag + (lead_flag - 1);
84 fwd_balance = cutpts[
x - 1 - array_origin].fwd_balance >> 1;
85 if (projection->
pile_count(
x + half_pitch) > zero_count) {
86 fwd_balance |= lead_flag;
105 float projection_scale,
112 int16_t balance_count;
121 int16_t half_pitch = pitch / 2 - 1;
124 if (half_pitch > 31) {
126 }
else if (half_pitch < 0) {
129 lead_flag = 1 << half_pitch;
131 back_balance = cutpts[
x - 1 - array_origin].back_balance << 1;
132 back_balance &= lead_flag + (lead_flag - 1);
136 fwd_balance = cutpts[
x - 1 - array_origin].fwd_balance >> 1;
137 if (projection->
pile_count(
x + half_pitch) > zero_count) {
138 fwd_balance |= lead_flag;
148 for (
index =
x - pitch - pitch_error;
index <=
x - pitch + pitch_error;
index++) {
149 if (
index >= array_origin) {
150 segpt = &cutpts[
index - array_origin];
151 dist =
x - segpt->xpos;
156 lead_flag = back_balance ^ segpt->fwd_balance;
158 while (lead_flag != 0) {
160 lead_flag &= lead_flag - 1;
163 for (balance_index = 0;
index + balance_index <
x - balance_index; balance_index++) {
164 balance_count += (projection->
pile_count(
index + balance_index) <= zero_count) ^
165 (projection->
pile_count(
x - balance_index) <= zero_count);
171 r_index = segpt->region_index + 1;
172 total = segpt->mean_sum + dist;
173 balance_count += offset;
174 sq_dist = dist * dist + segpt->sq_sum + balance_count * balance_count;
175 mean = total / r_index;
176 factor = mean - pitch;
178 factor += sq_dist / (r_index)-mean * mean;
185 mid_cuts = segpt->mid_cuts + mid_cut;
186 region_index = r_index;
201 int16_t array_origin,
207 float projection_scale,
213 int16_t balance_count;
222 int16_t half_pitch = pitch / 2 - 1;
225 if (half_pitch > 31) {
227 }
else if (half_pitch < 0) {
230 lead_flag = 1 << half_pitch;
232 back_balance = cutpts[
x - 1 - array_origin].back_balance << 1;
233 back_balance &= lead_flag + (lead_flag - 1);
237 fwd_balance = cutpts[
x - 1 - array_origin].fwd_balance >> 1;
238 if (projection->
pile_count(
x + half_pitch) > zero_count) {
239 fwd_balance |= lead_flag;
250 if (
index >= array_origin) {
251 segpt = &cutpts[
index - array_origin];
252 dist =
x - segpt->xpos;
256 lead_flag = back_balance ^ segpt->fwd_balance;
258 while (lead_flag != 0) {
260 lead_flag &= lead_flag - 1;
265 r_index = segpt->region_index + 1;
266 total = segpt->mean_sum + dist;
267 balance_count += offset;
268 sq_dist = dist * dist + segpt->sq_sum + balance_count * balance_count;
269 mean = total / r_index;
270 factor = mean - pitch;
272 factor += sq_dist / (r_index)-mean * mean;
278 mid_cuts = segpt->mid_cuts + mid_cut;
279 region_index = r_index;
293 BLOBNBOX_IT *blob_it,
298 int16_t projection_left,
299 int16_t projection_right,
float projection_scale,
300 int16_t &occupation_count,
301 FPSEGPT_LIST *seg_list,
311 int16_t array_origin;
314 int16_t best_left_x = 0;
315 int16_t best_right_x = 0;
325 FPSEGPT_IT seg_it = seg_list;
335 if ((pitch - 3) / 2 < pitch_error) {
336 pitch_error = (pitch - 3) / 2;
347 for (left_edge = projection_left;
348 projection->
pile_count(left_edge) == 0 && left_edge < projection_right; left_edge++) {
351 for (right_edge = projection_right;
352 projection->
pile_count(right_edge) == 0 && right_edge > left_edge; right_edge--) {
357 return check_pitch_sync3(projection_left, projection_right, zero_count, pitch, pitch_error,
358 projection, projection_scale, occupation_count, seg_list, start, end);
360 array_origin = left_edge - pitch;
362 std::vector<FPCUTPT> cutpts(right_edge - left_edge + pitch * 2 + 1);
363 for (
x = array_origin;
x < left_edge;
x++) {
365 cutpts[
x - array_origin].setup(&cutpts[0], array_origin, projection, zero_count, pitch,
x, 0);
367 for (offset = 0; offset <= pitch_error; offset++,
x++) {
369 cutpts[
x - array_origin].setup(&cutpts[0], array_origin, projection, zero_count, pitch,
x,
379 while (
x < right_edge - pitch_error) {
380 if (
x > this_box.
right() + pitch_error && blob_index < blob_count) {
387 if (
x <= this_box.
left()) {
389 }
else if (
x <= this_box.
left() + pitch_error) {
390 offset =
x - this_box.
left();
391 }
else if (
x >= this_box.
right()) {
393 }
else if (
x >= next_box.
left() && blob_index < blob_count) {
394 offset =
x - next_box.
left();
395 if (this_box.
right() -
x < offset) {
396 offset = this_box.
right() -
x;
398 }
else if (
x >= this_box.
right() - pitch_error) {
399 offset = this_box.
right() -
x;
408 cutpts[
x - array_origin].assign(&cutpts[0], array_origin,
x, faking, mid_cut, offset,
409 projection, projection_scale, zero_count, pitch, pitch_error);
413 best_fake = INT16_MAX;
414 best_cost = INT32_MAX;
415 best_count = INT16_MAX;
416 while (
x < right_edge + pitch) {
417 offset =
x < right_edge ? right_edge -
x : 0;
418 cutpts[
x - array_origin].assign(&cutpts[0], array_origin,
x,
false,
false, offset, projection,
419 projection_scale, zero_count, pitch, pitch_error);
420 cutpts[
x - array_origin].terminal =
true;
421 if (cutpts[
x - array_origin].index() + cutpts[
x - array_origin].fake_count <=
422 best_count + best_fake) {
423 if (cutpts[
x - array_origin].fake_count < best_fake ||
424 (cutpts[
x - array_origin].fake_count == best_fake &&
425 cutpts[
x - array_origin].cost_function() < best_cost)) {
426 best_fake = cutpts[
x - array_origin].fake_count;
427 best_cost = cutpts[
x - array_origin].cost_function();
430 best_count = cutpts[
x - array_origin].index();
431 }
else if (cutpts[
x - array_origin].fake_count == best_fake &&
x == best_right_x + 1 &&
432 cutpts[
x - array_origin].cost_function() == best_cost) {
441 best_end = &cutpts[(best_left_x + best_right_x) / 2 - array_origin];
443 for (
x = left_edge - pitch;
x < right_edge + pitch;
x++) {
444 tprintf(
"x=%d, C=%g, s=%g, sq=%g, prev=%d\n",
x, cutpts[
x - array_origin].cost_function(),
445 cutpts[
x - array_origin].sum(), cutpts[
x - array_origin].squares(),
446 cutpts[
x - array_origin].previous()->position());
449 occupation_count = -1;
451 for (
x = best_end->
position() - pitch + pitch_error;
452 x < best_end->position() - pitch_error && projection->
pile_count(
x) == 0;
x++) {
455 if (x < best_end->position() - pitch_error) {
460 seg_it.add_before_then_move(segpt);
462 }
while (best_end !=
nullptr);
463 seg_it.move_to_last();
464 mean_sum = seg_it.data()->
sum();
465 mean_sum = mean_sum * mean_sum / best_count;
466 if (seg_it.data()->squares() - mean_sum < 0) {
467 tprintf(
"Impossible sqsum=%g, mean=%g, total=%d\n", seg_it.data()->squares(),
468 seg_it.data()->sum(), best_count);
473 return seg_it.data()->squares() - mean_sum;
485 int16_t projection_left,
486 int16_t projection_right, int16_t zero_count,
490 float projection_scale,
491 int16_t &occupation_count,
492 FPSEGPT_LIST *seg_list,
501 int16_t array_origin;
503 int16_t projection_offset;
507 int16_t best_left_x = 0;
508 int16_t best_right_x = 0;
517 FPSEGPT_IT seg_it = seg_list;
519 end = (end - start) % pitch;
523 if ((pitch - 3) / 2 < pitch_error) {
524 pitch_error = (pitch - 3) / 2;
528 for (left_edge = projection_left;
529 projection->
pile_count(left_edge) == 0 && left_edge < projection_right; left_edge++) {
532 for (right_edge = projection_right;
533 projection->
pile_count(right_edge) == 0 && right_edge > left_edge; right_edge--) {
536 array_origin = left_edge - pitch;
538 std::vector<FPCUTPT> cutpts(right_edge - left_edge + pitch * 2 + 1);
540 std::vector<bool> mins(pitch_error * 2 + 1);
541 for (
x = array_origin;
x < left_edge;
x++) {
543 cutpts[
x - array_origin].setup(&cutpts[0], array_origin, projection, zero_count, pitch,
x, 0);
545 prev_zero = left_edge - 1;
546 for (offset = 0; offset <= pitch_error; offset++,
x++) {
548 cutpts[
x - array_origin].setup(&cutpts[0], array_origin, projection, zero_count, pitch,
x,
554 for (offset = -pitch_error, minindex = 0; offset < pitch_error; offset++, minindex++) {
555 mins[minindex] = projection->
local_min(
x + offset);
557 next_zero =
x + zero_offset + 1;
558 for (offset = next_zero - 1; offset >=
x; offset--) {
559 if (projection->
pile_count(offset) <= zero_count) {
564 while (
x < right_edge - pitch_error) {
565 mins[minindex] = projection->
local_min(
x + pitch_error);
567 if (minindex > pitch_error * 2) {
576 for (offset = 1; offset <= pitch_error; offset++) {
577 if (projection->
pile_count(
x + offset) <= zero_count ||
578 projection->
pile_count(
x - offset) <= zero_count) {
583 if (offset > pitch_error) {
584 if (
x - prev_zero > zero_offset && next_zero -
x > zero_offset) {
585 for (offset = 0; offset <= pitch_error; offset++) {
586 test_index = minindex + pitch_error + offset;
587 if (test_index > pitch_error * 2) {
588 test_index -= pitch_error * 2 + 1;
590 if (mins[test_index]) {
593 test_index = minindex + pitch_error - offset;
594 if (test_index > pitch_error * 2) {
595 test_index -= pitch_error * 2 + 1;
597 if (mins[test_index]) {
602 if (offset > pitch_error) {
606 projection_offset =
static_cast<int16_t
>(projection->
pile_count(
x) / projection_scale);
607 if (projection_offset > offset) {
608 offset = projection_offset;
614 (
x - projection_left - start) % pitch <= end) {
615 cutpts[
x - array_origin].assign(&cutpts[0], array_origin,
x, faking, mid_cut, offset,
616 projection, projection_scale, zero_count, pitch, pitch_error);
618 cutpts[
x - array_origin].assign_cheap(&cutpts[0], array_origin,
x, faking, mid_cut, offset,
619 projection, projection_scale, zero_count, pitch,
623 if (next_zero <
x || next_zero ==
x + zero_offset) {
624 next_zero =
x + zero_offset + 1;
626 if (projection->
pile_count(
x + zero_offset) <= zero_count) {
627 next_zero =
x + zero_offset;
631 best_fake = INT16_MAX;
632 best_cost = INT32_MAX;
633 best_count = INT16_MAX;
634 while (
x < right_edge + pitch) {
635 offset =
x < right_edge ? right_edge -
x : 0;
636 cutpts[
x - array_origin].assign(&cutpts[0], array_origin,
x,
false,
false, offset, projection,
637 projection_scale, zero_count, pitch, pitch_error);
638 cutpts[
x - array_origin].terminal =
true;
639 if (cutpts[
x - array_origin].index() + cutpts[
x - array_origin].fake_count <=
640 best_count + best_fake) {
641 if (cutpts[
x - array_origin].fake_count < best_fake ||
642 (cutpts[
x - array_origin].fake_count == best_fake &&
643 cutpts[
x - array_origin].cost_function() < best_cost)) {
644 best_fake = cutpts[
x - array_origin].fake_count;
645 best_cost = cutpts[
x - array_origin].cost_function();
648 best_count = cutpts[
x - array_origin].index();
649 }
else if (cutpts[
x - array_origin].fake_count == best_fake &&
x == best_right_x + 1 &&
650 cutpts[
x - array_origin].cost_function() == best_cost) {
659 best_end = &cutpts[(best_left_x + best_right_x) / 2 - array_origin];
668 occupation_count = -1;
670 for (
x = best_end->
position() - pitch + pitch_error;
673 if (x < best_end->position() - pitch_error) {
678 seg_it.add_before_then_move(segpt);
680 }
while (best_end !=
nullptr);
681 seg_it.move_to_last();
682 mean_sum = seg_it.data()->
sum();
683 mean_sum = mean_sum * mean_sum / best_count;
684 if (seg_it.data()->squares() - mean_sum < 0) {
685 tprintf(
"Impossible sqsum=%g, mean=%g, total=%d\n", seg_it.data()->squares(),
686 seg_it.data()->sum(), best_count);
688 return seg_it.data()->squares() - mean_sum;
void tprintf(const char *format,...)
int pitsync_linear_version
double pitsync_joined_edge
double check_pitch_sync2(BLOBNBOX_IT *blob_it, int16_t blob_count, int16_t pitch, int16_t pitch_error, STATS *projection, int16_t projection_left, int16_t projection_right, float projection_scale, int16_t &occupation_count, FPSEGPT_LIST *seg_list, int16_t start, int16_t end)
double textord_balance_factor
bool textord_fast_pitch_test
double check_pitch_sync3(int16_t projection_left, int16_t projection_right, int16_t zero_count, int16_t pitch, int16_t pitch_error, STATS *projection, float projection_scale, int16_t &occupation_count, FPSEGPT_LIST *seg_list, int16_t start, int16_t end)
TBOX box_next(BLOBNBOX_IT *it)
int32_t pile_count(int32_t value) const
bool local_min(int32_t x) const
void assign(FPCUTPT cutpts[], int16_t array_origin, int16_t x, bool faking, bool mid_cut, int16_t offset, STATS *projection, float projection_scale, int16_t zero_count, int16_t pitch, int16_t pitch_error)
void setup(FPCUTPT cutpts[], int16_t array_origin, STATS *projection, int16_t zero_count, int16_t pitch, int16_t x, int16_t offset)
void assign_cheap(FPCUTPT cutpts[], int16_t array_origin, int16_t x, bool faking, bool mid_cut, int16_t offset, STATS *projection, float projection_scale, int16_t zero_count, int16_t pitch, int16_t pitch_error)