tesseract  4.0.0-1-g2a2b
pithsync.cpp
Go to the documentation of this file.
1 /**********************************************************************
2  * File: pithsync.cpp (Formerly pitsync2.c)
3  * Description: Code to find the optimum fixed pitch segmentation of some blobs.
4  * Author: Ray Smith
5  * Created: Thu Nov 19 11:48:05 GMT 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 <cmath>
21 #include <cfloat> // for FLT_MAX
22 #include <vector> // for std::vector
23 #include "makerow.h"
24 #include "pitsync1.h"
25 #include "topitch.h"
26 #include "pithsync.h"
27 #include "tprintf.h"
28 
29 #define PROJECTION_MARGIN 10 //arbitrary
30 
31 /**********************************************************************
32  * FPCUTPT::setup
33  *
34  * Constructor to make a new FPCUTPT.
35  **********************************************************************/
36 
37 void FPCUTPT::setup( //constructor
38  FPCUTPT *cutpts, //predecessors
39  int16_t array_origin, //start coord
40  STATS *projection, //vertical occupation
41  int16_t zero_count, //official zero
42  int16_t pitch, //proposed pitch
43  int16_t x, //position
44  int16_t offset //dist to gap
45  ) {
46  //half of pitch
47  int16_t half_pitch = pitch / 2 - 1;
48  uint32_t lead_flag; //new flag
49  int32_t ind; //current position
50 
51  if (half_pitch > 31)
52  half_pitch = 31;
53  else if (half_pitch < 0)
54  half_pitch = 0;
55  lead_flag = 1 << half_pitch;
56 
57  pred = nullptr;
58  mean_sum = 0;
59  sq_sum = offset * offset;
60  cost = sq_sum;
61  faked = FALSE;
62  terminal = false;
63  fake_count = 0;
64  xpos = x;
65  region_index = 0;
66  mid_cuts = 0;
67  if (x == array_origin) {
68  back_balance = 0;
69  fwd_balance = 0;
70  for (ind = 0; ind <= half_pitch; ind++) {
71  fwd_balance >>= 1;
72  if (projection->pile_count (ind) > zero_count)
73  fwd_balance |= lead_flag;
74  }
75  }
76  else {
77  back_balance = cutpts[x - 1 - array_origin].back_balance << 1;
78  back_balance &= lead_flag + lead_flag - 1;
79  if (projection->pile_count (x) > zero_count)
80  back_balance |= 1;
81  fwd_balance = cutpts[x - 1 - array_origin].fwd_balance >> 1;
82  if (projection->pile_count (x + half_pitch) > zero_count)
83  fwd_balance |= lead_flag;
84  }
85 }
86 
87 
88 /**********************************************************************
89  * FPCUTPT::assign
90  *
91  * Constructor to make a new FPCUTPT.
92  **********************************************************************/
93 
94 void FPCUTPT::assign( //constructor
95  FPCUTPT* cutpts, //predecessors
96  int16_t array_origin, //start coord
97  int16_t x, //position
98  bool faking, //faking this one
99  bool mid_cut, //cheap cut.
100  int16_t offset, //dist to gap
101  STATS* projection, //vertical occupation
102  float projection_scale, //scaling
103  int16_t zero_count, //official zero
104  int16_t pitch, //proposed pitch
105  int16_t pitch_error //allowed tolerance
106 ) {
107  int index; //test index
108  int balance_index; //for balance factor
109  int16_t balance_count; //ding factor
110  int16_t r_index; //test cut number
111  FPCUTPT *segpt; //segment point
112  int32_t dist; //from prev segment
113  double sq_dist; //squared distance
114  double mean; //mean pitch
115  double total; //total dists
116  double factor; //cost function
117  //half of pitch
118  int16_t half_pitch = pitch / 2 - 1;
119  uint32_t lead_flag; //new flag
120 
121  if (half_pitch > 31)
122  half_pitch = 31;
123  else if (half_pitch < 0)
124  half_pitch = 0;
125  lead_flag = 1 << half_pitch;
126 
127  back_balance = cutpts[x - 1 - array_origin].back_balance << 1;
128  back_balance &= lead_flag + lead_flag - 1;
129  if (projection->pile_count (x) > zero_count)
130  back_balance |= 1;
131  fwd_balance = cutpts[x - 1 - array_origin].fwd_balance >> 1;
132  if (projection->pile_count (x + half_pitch) > zero_count)
133  fwd_balance |= lead_flag;
134 
135  xpos = x;
136  cost = FLT_MAX;
137  pred = nullptr;
138  faked = faking;
139  terminal = false;
140  region_index = 0;
141  fake_count = INT16_MAX;
142  for (index = x - pitch - pitch_error; index <= x - pitch + pitch_error;
143  index++) {
144  if (index >= array_origin) {
145  segpt = &cutpts[index - array_origin];
146  dist = x - segpt->xpos;
147  if (!segpt->terminal && segpt->fake_count < INT16_MAX) {
148  balance_count = 0;
149  if (textord_balance_factor > 0) {
151  lead_flag = back_balance ^ segpt->fwd_balance;
152  balance_count = 0;
153  while (lead_flag != 0) {
154  balance_count++;
155  lead_flag &= lead_flag - 1;
156  }
157  }
158  else {
159  for (balance_index = 0;
160  index + balance_index < x - balance_index;
161  balance_index++)
162  balance_count +=
163  (projection->pile_count (index + balance_index) <=
164  zero_count) ^ (projection->pile_count (x -
165  balance_index)
166  <= zero_count);
167  }
168  balance_count =
169  (int16_t) (balance_count * textord_balance_factor /
170  projection_scale);
171  }
172  r_index = segpt->region_index + 1;
173  total = segpt->mean_sum + dist;
174  balance_count += offset;
175  sq_dist =
176  dist * dist + segpt->sq_sum + balance_count * balance_count;
177  mean = total / r_index;
178  factor = mean - pitch;
179  factor *= factor;
180  factor += sq_dist / (r_index) - mean * mean;
181  if (factor < cost && segpt->fake_count + faked <= fake_count) {
182  cost = factor; //find least cost
183  pred = segpt; //save path
184  mean_sum = total;
185  sq_sum = sq_dist;
186  fake_count = segpt->fake_count + faked;
187  mid_cuts = segpt->mid_cuts + mid_cut;
188  region_index = r_index;
189  }
190  }
191  }
192  }
193 }
194 
195 
196 /**********************************************************************
197  * FPCUTPT::assign_cheap
198  *
199  * Constructor to make a new FPCUTPT on the cheap.
200  **********************************************************************/
201 
202 void FPCUTPT::assign_cheap( //constructor
203  FPCUTPT *cutpts, //predecessors
204  int16_t array_origin, //start coord
205  int16_t x, //position
206  BOOL8 faking, //faking this one
207  BOOL8 mid_cut, //cheap cut.
208  int16_t offset, //dist to gap
209  STATS *projection, //vertical occupation
210  float projection_scale, //scaling
211  int16_t zero_count, //official zero
212  int16_t pitch, //proposed pitch
213  int16_t pitch_error //allowed tolerance
214  ) {
215  int index; //test index
216  int16_t balance_count; //ding factor
217  int16_t r_index; //test cut number
218  FPCUTPT *segpt; //segment point
219  int32_t dist; //from prev segment
220  double sq_dist; //squared distance
221  double mean; //mean pitch
222  double total; //total dists
223  double factor; //cost function
224  //half of pitch
225  int16_t half_pitch = pitch / 2 - 1;
226  uint32_t lead_flag; //new flag
227 
228  if (half_pitch > 31)
229  half_pitch = 31;
230  else if (half_pitch < 0)
231  half_pitch = 0;
232  lead_flag = 1 << half_pitch;
233 
234  back_balance = cutpts[x - 1 - array_origin].back_balance << 1;
235  back_balance &= lead_flag + lead_flag - 1;
236  if (projection->pile_count (x) > zero_count)
237  back_balance |= 1;
238  fwd_balance = cutpts[x - 1 - array_origin].fwd_balance >> 1;
239  if (projection->pile_count (x + half_pitch) > zero_count)
240  fwd_balance |= lead_flag;
241 
242  xpos = x;
243  cost = FLT_MAX;
244  pred = nullptr;
245  faked = faking;
246  terminal = false;
247  region_index = 0;
248  fake_count = INT16_MAX;
249  index = x - pitch;
250  if (index >= array_origin) {
251  segpt = &cutpts[index - array_origin];
252  dist = x - segpt->xpos;
253  if (!segpt->terminal && segpt->fake_count < INT16_MAX) {
254  balance_count = 0;
255  if (textord_balance_factor > 0) {
256  lead_flag = back_balance ^ segpt->fwd_balance;
257  balance_count = 0;
258  while (lead_flag != 0) {
259  balance_count++;
260  lead_flag &= lead_flag - 1;
261  }
262  balance_count = (int16_t) (balance_count * textord_balance_factor
263  / projection_scale);
264  }
265  r_index = segpt->region_index + 1;
266  total = segpt->mean_sum + dist;
267  balance_count += offset;
268  sq_dist =
269  dist * dist + segpt->sq_sum + balance_count * balance_count;
270  mean = total / r_index;
271  factor = mean - pitch;
272  factor *= factor;
273  factor += sq_dist / (r_index) - mean * mean;
274  cost = factor; //find least cost
275  pred = segpt; //save path
276  mean_sum = total;
277  sq_sum = sq_dist;
278  fake_count = segpt->fake_count + faked;
279  mid_cuts = segpt->mid_cuts + mid_cut;
280  region_index = r_index;
281  }
282  }
283 }
284 
285 
286 /**********************************************************************
287  * check_pitch_sync
288  *
289  * Construct the lattice of possible segmentation points and choose the
290  * optimal path. Return the optimal path only.
291  * The return value is a measure of goodness of the sync.
292  **********************************************************************/
293 
294 double check_pitch_sync2( //find segmentation
295  BLOBNBOX_IT *blob_it, //blobs to do
296  int16_t blob_count, //no of blobs
297  int16_t pitch, //pitch estimate
298  int16_t pitch_error, //tolerance
299  STATS *projection, //vertical
300  int16_t projection_left, //edges //scale factor
301  int16_t projection_right,
302  float projection_scale,
303  int16_t &occupation_count, //no of occupied cells
304  FPSEGPT_LIST *seg_list, //output list
305  int16_t start, //start of good range
306  int16_t end //end of good range
307  ) {
308  bool faking; //illegal cut pt
309  bool mid_cut; //cheap cut pt.
310  int16_t x; //current coord
311  int16_t blob_index; //blob number
312  int16_t left_edge; //of word
313  int16_t right_edge; //of word
314  int16_t array_origin; //x coord of array
315  int16_t offset; //dist to legal area
316  int16_t zero_count; //projection zero
317  int16_t best_left_x = 0; //for equals
318  int16_t best_right_x = 0; //right edge
319  TBOX this_box; //bounding box
320  TBOX next_box; //box of next blob
321  FPSEGPT *segpt; //segment point
322  double best_cost; //best path
323  double mean_sum; //computes result
324  FPCUTPT *best_end; //end of best path
325  int16_t best_fake; //best fake level
326  int16_t best_count; //no of cuts
327  BLOBNBOX_IT this_it; //copy iterator
328  FPSEGPT_IT seg_it = seg_list; //output iterator
329 
330  // tprintf("Computing sync on word of %d blobs with pitch %d\n",
331  // blob_count, pitch);
332  // if (blob_count==8 && pitch==27)
333  // projection->print(stdout,TRUE);
334  zero_count = 0;
335  if (pitch < 3)
336  pitch = 3; //nothing ludicrous
337  if ((pitch - 3) / 2 < pitch_error)
338  pitch_error = (pitch - 3) / 2;
339  this_it = *blob_it;
340  this_box = box_next (&this_it);//get box
341  // left_edge=this_box.left(); //left of word
342  // right_edge=this_box.right();
343  // for (blob_index=1;blob_index<blob_count;blob_index++)
344  // {
345  // this_box=box_next(&this_it);
346  // if (this_box.right()>right_edge)
347  // right_edge=this_box.right();
348  // }
349  for (left_edge = projection_left; projection->pile_count (left_edge) == 0
350  && left_edge < projection_right; left_edge++);
351  for (right_edge = projection_right; projection->pile_count (right_edge) == 0
352  && right_edge > left_edge; right_edge--);
353  ASSERT_HOST (right_edge >= left_edge);
354  if (pitsync_linear_version >= 4)
355  return check_pitch_sync3 (projection_left, projection_right, zero_count,
356  pitch, pitch_error, projection,
357  projection_scale, occupation_count, seg_list,
358  start, end);
359  array_origin = left_edge - pitch;
360  // array of points
361  std::vector<FPCUTPT> cutpts(right_edge - left_edge + pitch * 2 + 1);
362  for (x = array_origin; x < left_edge; x++)
363  //free cuts
364  cutpts[x - array_origin].setup(&cutpts[0], array_origin, projection,
365  zero_count, pitch, x, 0);
366  for (offset = 0; offset <= pitch_error; offset++, x++)
367  //not quite free
368  cutpts[x - array_origin].setup(&cutpts[0], array_origin, projection,
369  zero_count, pitch, x, offset);
370 
371  this_it = *blob_it;
372  best_cost = FLT_MAX;
373  best_end = nullptr;
374  this_box = box_next (&this_it);//first box
375  next_box = box_next (&this_it);//second box
376  blob_index = 1;
377  while (x < right_edge - pitch_error) {
378  if (x > this_box.right () + pitch_error && blob_index < blob_count) {
379  this_box = next_box;
380  next_box = box_next (&this_it);
381  blob_index++;
382  }
383  faking = false;
384  mid_cut = false;
385  if (x <= this_box.left ())
386  offset = 0;
387  else if (x <= this_box.left () + pitch_error)
388  offset = x - this_box.left ();
389  else if (x >= this_box.right ())
390  offset = 0;
391  else if (x >= next_box.left () && blob_index < blob_count) {
392  offset = x - next_box.left ();
393  if (this_box.right () - x < offset)
394  offset = this_box.right () - x;
395  }
396  else if (x >= this_box.right () - pitch_error)
397  offset = this_box.right () - x;
398  else if (x - this_box.left () > pitch * pitsync_joined_edge
399  && this_box.right () - x > pitch * pitsync_joined_edge) {
400  mid_cut = true;
401  offset = 0;
402  }
403  else {
404  faking = true;
405  offset = projection->pile_count (x);
406  }
407  cutpts[x - array_origin].assign (&cutpts[0], array_origin, x,
408  faking, mid_cut, offset, projection,
409  projection_scale, zero_count, pitch,
410  pitch_error);
411  x++;
412  }
413 
414  best_fake = INT16_MAX;
415  best_cost = INT32_MAX;
416  best_count = INT16_MAX;
417  while (x < right_edge + pitch) {
418  offset = x < right_edge ? right_edge - x : 0;
419  cutpts[x - array_origin].assign (&cutpts[0], array_origin, x,
420  false, false, offset, projection,
421  projection_scale, zero_count, pitch,
422  pitch_error);
423  cutpts[x - array_origin].terminal = true;
424  if (cutpts[x - array_origin].index () +
425  cutpts[x - array_origin].fake_count <= best_count + best_fake) {
426  if (cutpts[x - array_origin].fake_count < best_fake
427  || (cutpts[x - array_origin].fake_count == best_fake
428  && cutpts[x - array_origin].cost_function () < best_cost)) {
429  best_fake = cutpts[x - array_origin].fake_count;
430  best_cost = cutpts[x - array_origin].cost_function ();
431  best_left_x = x;
432  best_right_x = x;
433  best_count = cutpts[x - array_origin].index ();
434  }
435  else if (cutpts[x - array_origin].fake_count == best_fake
436  && x == best_right_x + 1
437  && cutpts[x - array_origin].cost_function () == best_cost) {
438  //exactly equal
439  best_right_x = x;
440  }
441  }
442  x++;
443  }
444  ASSERT_HOST (best_fake < INT16_MAX);
445 
446  best_end = &cutpts[(best_left_x + best_right_x) / 2 - array_origin];
447  if (this_box.right () == textord_test_x
448  && this_box.top () == textord_test_y) {
449  for (x = left_edge - pitch; x < right_edge + pitch; x++) {
450  tprintf ("x=%d, C=%g, s=%g, sq=%g, prev=%d\n",
451  x, cutpts[x - array_origin].cost_function (),
452  cutpts[x - array_origin].sum (),
453  cutpts[x - array_origin].squares (),
454  cutpts[x - array_origin].previous ()->position ());
455  }
456  }
457  occupation_count = -1;
458  do {
459  for (x = best_end->position () - pitch + pitch_error;
460  x < best_end->position () - pitch_error
461  && projection->pile_count (x) == 0; x++);
462  if (x < best_end->position () - pitch_error)
463  occupation_count++;
464  //copy it
465  segpt = new FPSEGPT (best_end);
466  seg_it.add_before_then_move (segpt);
467  best_end = best_end->previous ();
468  }
469  while (best_end != nullptr);
470  seg_it.move_to_last ();
471  mean_sum = seg_it.data ()->sum ();
472  mean_sum = mean_sum * mean_sum / best_count;
473  if (seg_it.data ()->squares () - mean_sum < 0)
474  tprintf ("Impossible sqsum=%g, mean=%g, total=%d\n",
475  seg_it.data ()->squares (), seg_it.data ()->sum (), best_count);
476  // tprintf("blob_count=%d, pitch=%d, sync=%g, occ=%d\n",
477  // blob_count,pitch,seg_it.data()->squares()-mean_sum,
478  // occupation_count);
479  return seg_it.data ()->squares () - mean_sum;
480 }
481 
482 
483 /**********************************************************************
484  * check_pitch_sync
485  *
486  * Construct the lattice of possible segmentation points and choose the
487  * optimal path. Return the optimal path only.
488  * The return value is a measure of goodness of the sync.
489  **********************************************************************/
490 
491 double check_pitch_sync3( //find segmentation
492  int16_t projection_left, //edges //to be considered 0
493  int16_t projection_right,
494  int16_t zero_count,
495  int16_t pitch, //pitch estimate
496  int16_t pitch_error, //tolerance
497  STATS *projection, //vertical
498  float projection_scale, //scale factor
499  int16_t &occupation_count, //no of occupied cells
500  FPSEGPT_LIST *seg_list, //output list
501  int16_t start, //start of good range
502  int16_t end //end of good range
503  ) {
504  bool faking; //illegal cut pt
505  bool mid_cut; //cheap cut pt.
506  int16_t left_edge; //of word
507  int16_t right_edge; //of word
508  int16_t x; //current coord
509  int16_t array_origin; //x coord of array
510  int16_t offset; //dist to legal area
511  int16_t projection_offset; //from scaled projection
512  int16_t prev_zero; //previous zero dist
513  int16_t next_zero; //next zero dist
514  int16_t zero_offset; //scan window
515  int16_t best_left_x = 0; //for equals
516  int16_t best_right_x = 0; //right edge
517  FPSEGPT *segpt; //segment point
518  int minindex; //next input position
519  int test_index; //index to mins
520  double best_cost; //best path
521  double mean_sum; //computes result
522  FPCUTPT *best_end; //end of best path
523  int16_t best_fake; //best fake level
524  int16_t best_count; //no of cuts
525  FPSEGPT_IT seg_it = seg_list; //output iterator
526 
527  end = (end - start) % pitch;
528  if (pitch < 3)
529  pitch = 3; //nothing ludicrous
530  if ((pitch - 3) / 2 < pitch_error)
531  pitch_error = (pitch - 3) / 2;
532  //min dist of zero
533  zero_offset = (int16_t) (pitch * pitsync_joined_edge);
534  for (left_edge = projection_left; projection->pile_count (left_edge) == 0
535  && left_edge < projection_right; left_edge++);
536  for (right_edge = projection_right; projection->pile_count (right_edge) == 0
537  && right_edge > left_edge; right_edge--);
538  array_origin = left_edge - pitch;
539  // array of points
540  std::vector<FPCUTPT> cutpts(right_edge - left_edge + pitch * 2 + 1);
541  // local min results
542  std::vector<BOOL8> mins(pitch_error * 2 + 1);
543  for (x = array_origin; x < left_edge; x++)
544  //free cuts
545  cutpts[x - array_origin].setup(&cutpts[0], array_origin, projection,
546  zero_count, pitch, x, 0);
547  prev_zero = left_edge - 1;
548  for (offset = 0; offset <= pitch_error; offset++, x++)
549  //not quite free
550  cutpts[x - array_origin].setup(&cutpts[0], array_origin, projection,
551  zero_count, pitch, x, offset);
552 
553  best_cost = FLT_MAX;
554  best_end = nullptr;
555  for (offset = -pitch_error, minindex = 0; offset < pitch_error;
556  offset++, minindex++)
557  mins[minindex] = projection->local_min (x + offset);
558  next_zero = x + zero_offset + 1;
559  for (offset = next_zero - 1; offset >= x; offset--) {
560  if (projection->pile_count (offset) <= zero_count) {
561  next_zero = offset;
562  break;
563  }
564  }
565  while (x < right_edge - pitch_error) {
566  mins[minindex] = projection->local_min (x + pitch_error);
567  minindex++;
568  if (minindex > pitch_error * 2)
569  minindex = 0;
570  faking = false;
571  mid_cut = false;
572  offset = 0;
573  if (projection->pile_count (x) <= zero_count) {
574  prev_zero = x;
575  }
576  else {
577  for (offset = 1; offset <= pitch_error; offset++)
578  if (projection->pile_count (x + offset) <= zero_count
579  || projection->pile_count (x - offset) <= zero_count)
580  break;
581  }
582  if (offset > pitch_error) {
583  if (x - prev_zero > zero_offset && next_zero - x > zero_offset) {
584  for (offset = 0; offset <= pitch_error; offset++) {
585  test_index = minindex + pitch_error + offset;
586  if (test_index > pitch_error * 2)
587  test_index -= pitch_error * 2 + 1;
588  if (mins[test_index])
589  break;
590  test_index = minindex + pitch_error - offset;
591  if (test_index > pitch_error * 2)
592  test_index -= pitch_error * 2 + 1;
593  if (mins[test_index])
594  break;
595  }
596  }
597  if (offset > pitch_error) {
598  offset = projection->pile_count (x);
599  faking = true;
600  }
601  else {
602  projection_offset =
603  (int16_t) (projection->pile_count (x) / projection_scale);
604  if (projection_offset > offset)
605  offset = projection_offset;
606  mid_cut = true;
607  }
608  }
609  if ((start == 0 && end == 0)
611  || (x - projection_left - start) % pitch <= end)
612  cutpts[x - array_origin].assign(&cutpts[0], array_origin, x,
613  faking, mid_cut, offset, projection,
614  projection_scale, zero_count, pitch,
615  pitch_error);
616  else
617  cutpts[x - array_origin].assign_cheap(&cutpts[0], array_origin, x,
618  faking, mid_cut, offset,
619  projection, projection_scale,
620  zero_count, pitch,
621  pitch_error);
622  x++;
623  if (next_zero < x || next_zero == x + zero_offset)
624  next_zero = x + zero_offset + 1;
625  if (projection->pile_count (x + zero_offset) <= zero_count)
626  next_zero = x + zero_offset;
627  }
628 
629  best_fake = INT16_MAX;
630  best_cost = INT32_MAX;
631  best_count = INT16_MAX;
632  while (x < right_edge + pitch) {
633  offset = x < right_edge ? right_edge - x : 0;
634  cutpts[x - array_origin].assign(&cutpts[0], array_origin, x,
635  false, false, offset, projection,
636  projection_scale, zero_count, pitch,
637  pitch_error);
638  cutpts[x - array_origin].terminal = true;
639  if (cutpts[x - array_origin].index () +
640  cutpts[x - array_origin].fake_count <= 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 ();
646  best_left_x = x;
647  best_right_x = x;
648  best_count = cutpts[x - array_origin].index ();
649  }
650  else if (cutpts[x - array_origin].fake_count == best_fake
651  && x == best_right_x + 1
652  && cutpts[x - array_origin].cost_function () == best_cost) {
653  //exactly equal
654  best_right_x = x;
655  }
656  }
657  x++;
658  }
659  ASSERT_HOST (best_fake < INT16_MAX);
660 
661  best_end = &cutpts[(best_left_x + best_right_x) / 2 - array_origin];
662  // for (x=left_edge-pitch;x<right_edge+pitch;x++)
663  // {
664  // tprintf("x=%d, C=%g, s=%g, sq=%g, prev=%d\n",
665  // x,cutpts[x-array_origin].cost_function(),
666  // cutpts[x-array_origin].sum(),
667  // cutpts[x-array_origin].squares(),
668  // cutpts[x-array_origin].previous()->position());
669  // }
670  occupation_count = -1;
671  do {
672  for (x = best_end->position () - pitch + pitch_error;
673  x < best_end->position () - pitch_error
674  && projection->pile_count (x) == 0; x++);
675  if (x < best_end->position () - pitch_error)
676  occupation_count++;
677  //copy it
678  segpt = new FPSEGPT (best_end);
679  seg_it.add_before_then_move (segpt);
680  best_end = best_end->previous ();
681  }
682  while (best_end != nullptr);
683  seg_it.move_to_last ();
684  mean_sum = seg_it.data ()->sum ();
685  mean_sum = mean_sum * mean_sum / best_count;
686  if (seg_it.data ()->squares () - mean_sum < 0)
687  tprintf ("Impossible sqsum=%g, mean=%g, total=%d\n",
688  seg_it.data ()->squares (), seg_it.data ()->sum (), best_count);
689  return seg_it.data ()->squares () - mean_sum;
690 }
EXTERN bool textord_fast_pitch_test
Definition: topitch.cpp:46
int32_t pile_count(int32_t value) const
Definition: statistc.h:78
int32_t position()
Definition: pithsync.h:68
void setup(FPCUTPT cutpts[], int16_t array_origin, STATS *projection, int16_t zero_count, int16_t pitch, int16_t x, int16_t offset)
Definition: pithsync.cpp:37
double pitsync_joined_edge
Definition: pitsync1.cpp:27
bool local_min(int32_t x) const
Definition: statistc.cpp:261
bool terminal
Definition: pithsync.h:91
Definition: rect.h:34
FPCUTPT * previous()
Definition: pithsync.h:80
void assign_cheap(FPCUTPT cutpts[], int16_t array_origin, int16_t x, BOOL8 faking, BOOL8 mid_cut, int16_t offset, STATS *projection, float projection_scale, int16_t zero_count, int16_t pitch, int16_t pitch_error)
Definition: pithsync.cpp:202
EXTERN double textord_balance_factor
Definition: topitch.cpp:57
Definition: statistc.h:33
TBOX box_next(BLOBNBOX_IT *it)
Definition: blobbox.cpp:637
double sum()
Definition: pithsync.h:77
int16_t index() const
Definition: pithsync.h:86
int16_t fake_count
Definition: pithsync.h:92
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)
Definition: pithsync.cpp:294
int16_t left() const
Definition: rect.h:72
int16_t top() const
Definition: rect.h:58
#define FALSE
Definition: capi.h:52
unsigned char BOOL8
Definition: host.h:34
DLLSYM void tprintf(const char *format,...)
Definition: tprintf.cpp:37
int textord_test_y
Definition: makerow.cpp:62
bool faked
Definition: pithsync.h:90
int textord_test_x
Definition: makerow.cpp:61
int16_t right() const
Definition: rect.h:79
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)
Definition: pithsync.cpp:491
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)
Definition: pithsync.cpp:94
#define ASSERT_HOST(x)
Definition: errcode.h:84