tesseract
3.03
|
00001 /********************************************************************** 00002 * File: pithsync.cpp (Formerly pitsync2.c) 00003 * Description: Code to find the optimum fixed pitch segmentation of some blobs. 00004 * Author: Ray Smith 00005 * Created: Thu Nov 19 11:48:05 GMT 1992 00006 * 00007 * (C) Copyright 1992, Hewlett-Packard Ltd. 00008 ** Licensed under the Apache License, Version 2.0 (the "License"); 00009 ** you may not use this file except in compliance with the License. 00010 ** You may obtain a copy of the License at 00011 ** http://www.apache.org/licenses/LICENSE-2.0 00012 ** Unless required by applicable law or agreed to in writing, software 00013 ** distributed under the License is distributed on an "AS IS" BASIS, 00014 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00015 ** See the License for the specific language governing permissions and 00016 ** limitations under the License. 00017 * 00018 **********************************************************************/ 00019 00020 #ifdef __UNIX__ 00021 #include <assert.h> 00022 #endif 00023 #include <math.h> 00024 #include "memry.h" 00025 #include "makerow.h" 00026 #include "pitsync1.h" 00027 #include "topitch.h" 00028 #include "pithsync.h" 00029 #include "tprintf.h" 00030 00031 #define PROJECTION_MARGIN 10 //arbitrary 00032 00033 #define EXTERN 00034 00035 /********************************************************************** 00036 * FPCUTPT::setup 00037 * 00038 * Constructor to make a new FPCUTPT. 00039 **********************************************************************/ 00040 00041 void FPCUTPT::setup( //constructor 00042 FPCUTPT *cutpts, //predecessors 00043 inT16 array_origin, //start coord 00044 STATS *projection, //vertical occupation 00045 inT16 zero_count, //official zero 00046 inT16 pitch, //proposed pitch 00047 inT16 x, //position 00048 inT16 offset //dist to gap 00049 ) { 00050 //half of pitch 00051 inT16 half_pitch = pitch / 2 - 1; 00052 uinT32 lead_flag; //new flag 00053 inT32 ind; //current position 00054 00055 if (half_pitch > 31) 00056 half_pitch = 31; 00057 else if (half_pitch < 0) 00058 half_pitch = 0; 00059 lead_flag = 1 << half_pitch; 00060 00061 pred = NULL; 00062 mean_sum = 0; 00063 sq_sum = offset * offset; 00064 cost = sq_sum; 00065 faked = FALSE; 00066 terminal = FALSE; 00067 fake_count = 0; 00068 xpos = x; 00069 region_index = 0; 00070 mid_cuts = 0; 00071 if (x == array_origin) { 00072 back_balance = 0; 00073 fwd_balance = 0; 00074 for (ind = 0; ind <= half_pitch; ind++) { 00075 fwd_balance >>= 1; 00076 if (projection->pile_count (ind) > zero_count) 00077 fwd_balance |= lead_flag; 00078 } 00079 } 00080 else { 00081 back_balance = cutpts[x - 1 - array_origin].back_balance << 1; 00082 back_balance &= lead_flag + lead_flag - 1; 00083 if (projection->pile_count (x) > zero_count) 00084 back_balance |= 1; 00085 fwd_balance = cutpts[x - 1 - array_origin].fwd_balance >> 1; 00086 if (projection->pile_count (x + half_pitch) > zero_count) 00087 fwd_balance |= lead_flag; 00088 } 00089 } 00090 00091 00092 /********************************************************************** 00093 * FPCUTPT::assign 00094 * 00095 * Constructor to make a new FPCUTPT. 00096 **********************************************************************/ 00097 00098 void FPCUTPT::assign( //constructor 00099 FPCUTPT *cutpts, //predecessors 00100 inT16 array_origin, //start coord 00101 inT16 x, //position 00102 BOOL8 faking, //faking this one 00103 BOOL8 mid_cut, //cheap cut. 00104 inT16 offset, //dist to gap 00105 STATS *projection, //vertical occupation 00106 float projection_scale, //scaling 00107 inT16 zero_count, //official zero 00108 inT16 pitch, //proposed pitch 00109 inT16 pitch_error //allowed tolerance 00110 ) { 00111 int index; //test index 00112 int balance_index; //for balance factor 00113 inT16 balance_count; //ding factor 00114 inT16 r_index; //test cut number 00115 FPCUTPT *segpt; //segment point 00116 inT32 dist; //from prev segment 00117 double sq_dist; //squared distance 00118 double mean; //mean pitch 00119 double total; //total dists 00120 double factor; //cost function 00121 //half of pitch 00122 inT16 half_pitch = pitch / 2 - 1; 00123 uinT32 lead_flag; //new flag 00124 00125 if (half_pitch > 31) 00126 half_pitch = 31; 00127 else if (half_pitch < 0) 00128 half_pitch = 0; 00129 lead_flag = 1 << half_pitch; 00130 00131 back_balance = cutpts[x - 1 - array_origin].back_balance << 1; 00132 back_balance &= lead_flag + lead_flag - 1; 00133 if (projection->pile_count (x) > zero_count) 00134 back_balance |= 1; 00135 fwd_balance = cutpts[x - 1 - array_origin].fwd_balance >> 1; 00136 if (projection->pile_count (x + half_pitch) > zero_count) 00137 fwd_balance |= lead_flag; 00138 00139 xpos = x; 00140 cost = MAX_FLOAT32; 00141 pred = NULL; 00142 faked = faking; 00143 terminal = FALSE; 00144 region_index = 0; 00145 fake_count = MAX_INT16; 00146 for (index = x - pitch - pitch_error; index <= x - pitch + pitch_error; 00147 index++) { 00148 if (index >= array_origin) { 00149 segpt = &cutpts[index - array_origin]; 00150 dist = x - segpt->xpos; 00151 if (!segpt->terminal && segpt->fake_count < MAX_INT16) { 00152 balance_count = 0; 00153 if (textord_balance_factor > 0) { 00154 if (textord_fast_pitch_test) { 00155 lead_flag = back_balance ^ segpt->fwd_balance; 00156 balance_count = 0; 00157 while (lead_flag != 0) { 00158 balance_count++; 00159 lead_flag &= lead_flag - 1; 00160 } 00161 } 00162 else { 00163 for (balance_index = 0; 00164 index + balance_index < x - balance_index; 00165 balance_index++) 00166 balance_count += 00167 (projection->pile_count (index + balance_index) <= 00168 zero_count) ^ (projection->pile_count (x - 00169 balance_index) 00170 <= zero_count); 00171 } 00172 balance_count = 00173 (inT16) (balance_count * textord_balance_factor / 00174 projection_scale); 00175 } 00176 r_index = segpt->region_index + 1; 00177 total = segpt->mean_sum + dist; 00178 balance_count += offset; 00179 sq_dist = 00180 dist * dist + segpt->sq_sum + balance_count * balance_count; 00181 mean = total / r_index; 00182 factor = mean - pitch; 00183 factor *= factor; 00184 factor += sq_dist / (r_index) - mean * mean; 00185 if (factor < cost && segpt->fake_count + faked <= fake_count) { 00186 cost = factor; //find least cost 00187 pred = segpt; //save path 00188 mean_sum = total; 00189 sq_sum = sq_dist; 00190 fake_count = segpt->fake_count + faked; 00191 mid_cuts = segpt->mid_cuts + mid_cut; 00192 region_index = r_index; 00193 } 00194 } 00195 } 00196 } 00197 } 00198 00199 00200 /********************************************************************** 00201 * FPCUTPT::assign_cheap 00202 * 00203 * Constructor to make a new FPCUTPT on the cheap. 00204 **********************************************************************/ 00205 00206 void FPCUTPT::assign_cheap( //constructor 00207 FPCUTPT *cutpts, //predecessors 00208 inT16 array_origin, //start coord 00209 inT16 x, //position 00210 BOOL8 faking, //faking this one 00211 BOOL8 mid_cut, //cheap cut. 00212 inT16 offset, //dist to gap 00213 STATS *projection, //vertical occupation 00214 float projection_scale, //scaling 00215 inT16 zero_count, //official zero 00216 inT16 pitch, //proposed pitch 00217 inT16 pitch_error //allowed tolerance 00218 ) { 00219 int index; //test index 00220 inT16 balance_count; //ding factor 00221 inT16 r_index; //test cut number 00222 FPCUTPT *segpt; //segment point 00223 inT32 dist; //from prev segment 00224 double sq_dist; //squared distance 00225 double mean; //mean pitch 00226 double total; //total dists 00227 double factor; //cost function 00228 //half of pitch 00229 inT16 half_pitch = pitch / 2 - 1; 00230 uinT32 lead_flag; //new flag 00231 00232 if (half_pitch > 31) 00233 half_pitch = 31; 00234 else if (half_pitch < 0) 00235 half_pitch = 0; 00236 lead_flag = 1 << half_pitch; 00237 00238 back_balance = cutpts[x - 1 - array_origin].back_balance << 1; 00239 back_balance &= lead_flag + lead_flag - 1; 00240 if (projection->pile_count (x) > zero_count) 00241 back_balance |= 1; 00242 fwd_balance = cutpts[x - 1 - array_origin].fwd_balance >> 1; 00243 if (projection->pile_count (x + half_pitch) > zero_count) 00244 fwd_balance |= lead_flag; 00245 00246 xpos = x; 00247 cost = MAX_FLOAT32; 00248 pred = NULL; 00249 faked = faking; 00250 terminal = FALSE; 00251 region_index = 0; 00252 fake_count = MAX_INT16; 00253 index = x - pitch; 00254 if (index >= array_origin) { 00255 segpt = &cutpts[index - array_origin]; 00256 dist = x - segpt->xpos; 00257 if (!segpt->terminal && segpt->fake_count < MAX_INT16) { 00258 balance_count = 0; 00259 if (textord_balance_factor > 0) { 00260 lead_flag = back_balance ^ segpt->fwd_balance; 00261 balance_count = 0; 00262 while (lead_flag != 0) { 00263 balance_count++; 00264 lead_flag &= lead_flag - 1; 00265 } 00266 balance_count = (inT16) (balance_count * textord_balance_factor 00267 / projection_scale); 00268 } 00269 r_index = segpt->region_index + 1; 00270 total = segpt->mean_sum + dist; 00271 balance_count += offset; 00272 sq_dist = 00273 dist * dist + segpt->sq_sum + balance_count * balance_count; 00274 mean = total / r_index; 00275 factor = mean - pitch; 00276 factor *= factor; 00277 factor += sq_dist / (r_index) - mean * mean; 00278 cost = factor; //find least cost 00279 pred = segpt; //save path 00280 mean_sum = total; 00281 sq_sum = sq_dist; 00282 fake_count = segpt->fake_count + faked; 00283 mid_cuts = segpt->mid_cuts + mid_cut; 00284 region_index = r_index; 00285 } 00286 } 00287 } 00288 00289 00290 /********************************************************************** 00291 * check_pitch_sync 00292 * 00293 * Construct the lattice of possible segmentation points and choose the 00294 * optimal path. Return the optimal path only. 00295 * The return value is a measure of goodness of the sync. 00296 **********************************************************************/ 00297 00298 double check_pitch_sync2( //find segmentation 00299 BLOBNBOX_IT *blob_it, //blobs to do 00300 inT16 blob_count, //no of blobs 00301 inT16 pitch, //pitch estimate 00302 inT16 pitch_error, //tolerance 00303 STATS *projection, //vertical 00304 inT16 projection_left, //edges //scale factor 00305 inT16 projection_right, 00306 float projection_scale, 00307 inT16 &occupation_count, //no of occupied cells 00308 FPSEGPT_LIST *seg_list, //output list 00309 inT16 start, //start of good range 00310 inT16 end //end of good range 00311 ) { 00312 BOOL8 faking; //illegal cut pt 00313 BOOL8 mid_cut; //cheap cut pt. 00314 inT16 x; //current coord 00315 inT16 blob_index; //blob number 00316 inT16 left_edge; //of word 00317 inT16 right_edge; //of word 00318 inT16 array_origin; //x coord of array 00319 inT16 offset; //dist to legal area 00320 inT16 zero_count; //projection zero 00321 inT16 best_left_x = 0; //for equals 00322 inT16 best_right_x = 0; //right edge 00323 TBOX this_box; //bounding box 00324 TBOX next_box; //box of next blob 00325 FPSEGPT *segpt; //segment point 00326 FPCUTPT *cutpts; //array of points 00327 double best_cost; //best path 00328 double mean_sum; //computes result 00329 FPCUTPT *best_end; //end of best path 00330 inT16 best_fake; //best fake level 00331 inT16 best_count; //no of cuts 00332 BLOBNBOX_IT this_it; //copy iterator 00333 FPSEGPT_IT seg_it = seg_list; //output iterator 00334 00335 // tprintf("Computing sync on word of %d blobs with pitch %d\n", 00336 // blob_count, pitch); 00337 // if (blob_count==8 && pitch==27) 00338 // projection->print(stdout,TRUE); 00339 zero_count = 0; 00340 if (pitch < 3) 00341 pitch = 3; //nothing ludicrous 00342 if ((pitch - 3) / 2 < pitch_error) 00343 pitch_error = (pitch - 3) / 2; 00344 this_it = *blob_it; 00345 this_box = box_next (&this_it);//get box 00346 // left_edge=this_box.left(); //left of word 00347 // right_edge=this_box.right(); 00348 // for (blob_index=1;blob_index<blob_count;blob_index++) 00349 // { 00350 // this_box=box_next(&this_it); 00351 // if (this_box.right()>right_edge) 00352 // right_edge=this_box.right(); 00353 // } 00354 for (left_edge = projection_left; projection->pile_count (left_edge) == 0 00355 && left_edge < projection_right; left_edge++); 00356 for (right_edge = projection_right; projection->pile_count (right_edge) == 0 00357 && right_edge > left_edge; right_edge--); 00358 ASSERT_HOST (right_edge >= left_edge); 00359 if (pitsync_linear_version >= 4) 00360 return check_pitch_sync3 (projection_left, projection_right, zero_count, 00361 pitch, pitch_error, projection, 00362 projection_scale, occupation_count, seg_list, 00363 start, end); 00364 array_origin = left_edge - pitch; 00365 cutpts = (FPCUTPT *) alloc_mem ((right_edge - left_edge + pitch * 2 + 1) 00366 * sizeof (FPCUTPT)); 00367 for (x = array_origin; x < left_edge; x++) 00368 //free cuts 00369 cutpts[x - array_origin].setup (cutpts, array_origin, projection, zero_count, pitch, x, 0); 00370 for (offset = 0; offset <= pitch_error; offset++, x++) 00371 //not quite free 00372 cutpts[x - array_origin].setup (cutpts, array_origin, projection, zero_count, pitch, x, offset); 00373 00374 this_it = *blob_it; 00375 best_cost = MAX_FLOAT32; 00376 best_end = NULL; 00377 this_box = box_next (&this_it);//first box 00378 next_box = box_next (&this_it);//second box 00379 blob_index = 1; 00380 while (x < right_edge - pitch_error) { 00381 if (x > this_box.right () + pitch_error && blob_index < blob_count) { 00382 this_box = next_box; 00383 next_box = box_next (&this_it); 00384 blob_index++; 00385 } 00386 faking = FALSE; 00387 mid_cut = FALSE; 00388 if (x <= this_box.left ()) 00389 offset = 0; 00390 else if (x <= this_box.left () + pitch_error) 00391 offset = x - this_box.left (); 00392 else if (x >= this_box.right ()) 00393 offset = 0; 00394 else if (x >= next_box.left () && blob_index < blob_count) { 00395 offset = x - next_box.left (); 00396 if (this_box.right () - x < offset) 00397 offset = this_box.right () - x; 00398 } 00399 else if (x >= this_box.right () - pitch_error) 00400 offset = this_box.right () - x; 00401 else if (x - this_box.left () > pitch * pitsync_joined_edge 00402 && this_box.right () - x > pitch * pitsync_joined_edge) { 00403 mid_cut = TRUE; 00404 offset = 0; 00405 } 00406 else { 00407 faking = TRUE; 00408 offset = projection->pile_count (x); 00409 } 00410 cutpts[x - array_origin].assign (cutpts, array_origin, x, 00411 faking, mid_cut, offset, projection, 00412 projection_scale, zero_count, pitch, 00413 pitch_error); 00414 x++; 00415 } 00416 00417 best_fake = MAX_INT16; 00418 best_cost = MAX_INT32; 00419 best_count = MAX_INT16; 00420 while (x < right_edge + pitch) { 00421 offset = x < right_edge ? right_edge - x : 0; 00422 cutpts[x - array_origin].assign (cutpts, array_origin, x, 00423 FALSE, FALSE, offset, projection, 00424 projection_scale, zero_count, pitch, 00425 pitch_error); 00426 cutpts[x - array_origin].terminal = TRUE; 00427 if (cutpts[x - array_origin].index () + 00428 cutpts[x - array_origin].fake_count <= best_count + best_fake) { 00429 if (cutpts[x - array_origin].fake_count < best_fake 00430 || (cutpts[x - array_origin].fake_count == best_fake 00431 && cutpts[x - array_origin].cost_function () < best_cost)) { 00432 best_fake = cutpts[x - array_origin].fake_count; 00433 best_cost = cutpts[x - array_origin].cost_function (); 00434 best_left_x = x; 00435 best_right_x = x; 00436 best_count = cutpts[x - array_origin].index (); 00437 } 00438 else if (cutpts[x - array_origin].fake_count == best_fake 00439 && x == best_right_x + 1 00440 && cutpts[x - array_origin].cost_function () == best_cost) { 00441 //exactly equal 00442 best_right_x = x; 00443 } 00444 } 00445 x++; 00446 } 00447 ASSERT_HOST (best_fake < MAX_INT16); 00448 00449 best_end = &cutpts[(best_left_x + best_right_x) / 2 - array_origin]; 00450 if (this_box.right () == textord_test_x 00451 && this_box.top () == textord_test_y) { 00452 for (x = left_edge - pitch; x < right_edge + pitch; x++) { 00453 tprintf ("x=%d, C=%g, s=%g, sq=%g, prev=%d\n", 00454 x, cutpts[x - array_origin].cost_function (), 00455 cutpts[x - array_origin].sum (), 00456 cutpts[x - array_origin].squares (), 00457 cutpts[x - array_origin].previous ()->position ()); 00458 } 00459 } 00460 occupation_count = -1; 00461 do { 00462 for (x = best_end->position () - pitch + pitch_error; 00463 x < best_end->position () - pitch_error 00464 && projection->pile_count (x) == 0; x++); 00465 if (x < best_end->position () - pitch_error) 00466 occupation_count++; 00467 //copy it 00468 segpt = new FPSEGPT (best_end); 00469 seg_it.add_before_then_move (segpt); 00470 best_end = best_end->previous (); 00471 } 00472 while (best_end != NULL); 00473 seg_it.move_to_last (); 00474 mean_sum = seg_it.data ()->sum (); 00475 mean_sum = mean_sum * mean_sum / best_count; 00476 if (seg_it.data ()->squares () - mean_sum < 0) 00477 tprintf ("Impossible sqsum=%g, mean=%g, total=%d\n", 00478 seg_it.data ()->squares (), seg_it.data ()->sum (), best_count); 00479 free_mem(cutpts); 00480 // tprintf("blob_count=%d, pitch=%d, sync=%g, occ=%d\n", 00481 // blob_count,pitch,seg_it.data()->squares()-mean_sum, 00482 // occupation_count); 00483 return seg_it.data ()->squares () - mean_sum; 00484 } 00485 00486 00487 /********************************************************************** 00488 * check_pitch_sync 00489 * 00490 * Construct the lattice of possible segmentation points and choose the 00491 * optimal path. Return the optimal path only. 00492 * The return value is a measure of goodness of the sync. 00493 **********************************************************************/ 00494 00495 double check_pitch_sync3( //find segmentation 00496 inT16 projection_left, //edges //to be considered 0 00497 inT16 projection_right, 00498 inT16 zero_count, 00499 inT16 pitch, //pitch estimate 00500 inT16 pitch_error, //tolerance 00501 STATS *projection, //vertical 00502 float projection_scale, //scale factor 00503 inT16 &occupation_count, //no of occupied cells 00504 FPSEGPT_LIST *seg_list, //output list 00505 inT16 start, //start of good range 00506 inT16 end //end of good range 00507 ) { 00508 BOOL8 faking; //illegal cut pt 00509 BOOL8 mid_cut; //cheap cut pt. 00510 inT16 left_edge; //of word 00511 inT16 right_edge; //of word 00512 inT16 x; //current coord 00513 inT16 array_origin; //x coord of array 00514 inT16 offset; //dist to legal area 00515 inT16 projection_offset; //from scaled projection 00516 inT16 prev_zero; //previous zero dist 00517 inT16 next_zero; //next zero dist 00518 inT16 zero_offset; //scan window 00519 inT16 best_left_x = 0; //for equals 00520 inT16 best_right_x = 0; //right edge 00521 FPSEGPT *segpt; //segment point 00522 FPCUTPT *cutpts; //array of points 00523 BOOL8 *mins; //local min results 00524 int minindex; //next input position 00525 int test_index; //index to mins 00526 double best_cost; //best path 00527 double mean_sum; //computes result 00528 FPCUTPT *best_end; //end of best path 00529 inT16 best_fake; //best fake level 00530 inT16 best_count; //no of cuts 00531 FPSEGPT_IT seg_it = seg_list; //output iterator 00532 00533 end = (end - start) % pitch; 00534 if (pitch < 3) 00535 pitch = 3; //nothing ludicrous 00536 if ((pitch - 3) / 2 < pitch_error) 00537 pitch_error = (pitch - 3) / 2; 00538 //min dist of zero 00539 zero_offset = (inT16) (pitch * pitsync_joined_edge); 00540 for (left_edge = projection_left; projection->pile_count (left_edge) == 0 00541 && left_edge < projection_right; left_edge++); 00542 for (right_edge = projection_right; projection->pile_count (right_edge) == 0 00543 && right_edge > left_edge; right_edge--); 00544 array_origin = left_edge - pitch; 00545 cutpts = (FPCUTPT *) alloc_mem ((right_edge - left_edge + pitch * 2 + 1) 00546 * sizeof (FPCUTPT)); 00547 mins = (BOOL8 *) alloc_mem ((pitch_error * 2 + 1) * sizeof (BOOL8)); 00548 for (x = array_origin; x < left_edge; x++) 00549 //free cuts 00550 cutpts[x - array_origin].setup (cutpts, array_origin, projection, zero_count, pitch, x, 0); 00551 prev_zero = left_edge - 1; 00552 for (offset = 0; offset <= pitch_error; offset++, x++) 00553 //not quite free 00554 cutpts[x - array_origin].setup (cutpts, array_origin, projection, zero_count, pitch, x, offset); 00555 00556 best_cost = MAX_FLOAT32; 00557 best_end = NULL; 00558 for (offset = -pitch_error, minindex = 0; offset < pitch_error; 00559 offset++, minindex++) 00560 mins[minindex] = projection->local_min (x + offset); 00561 next_zero = x + zero_offset + 1; 00562 for (offset = next_zero - 1; offset >= x; offset--) { 00563 if (projection->pile_count (offset) <= zero_count) { 00564 next_zero = offset; 00565 break; 00566 } 00567 } 00568 while (x < right_edge - pitch_error) { 00569 mins[minindex] = projection->local_min (x + pitch_error); 00570 minindex++; 00571 if (minindex > pitch_error * 2) 00572 minindex = 0; 00573 faking = FALSE; 00574 mid_cut = FALSE; 00575 offset = 0; 00576 if (projection->pile_count (x) <= zero_count) { 00577 prev_zero = x; 00578 } 00579 else { 00580 for (offset = 1; offset <= pitch_error; offset++) 00581 if (projection->pile_count (x + offset) <= zero_count 00582 || projection->pile_count (x - offset) <= zero_count) 00583 break; 00584 } 00585 if (offset > pitch_error) { 00586 if (x - prev_zero > zero_offset && next_zero - x > zero_offset) { 00587 for (offset = 0; offset <= pitch_error; offset++) { 00588 test_index = minindex + pitch_error + offset; 00589 if (test_index > pitch_error * 2) 00590 test_index -= pitch_error * 2 + 1; 00591 if (mins[test_index]) 00592 break; 00593 test_index = minindex + pitch_error - offset; 00594 if (test_index > pitch_error * 2) 00595 test_index -= pitch_error * 2 + 1; 00596 if (mins[test_index]) 00597 break; 00598 } 00599 } 00600 if (offset > pitch_error) { 00601 offset = projection->pile_count (x); 00602 faking = TRUE; 00603 } 00604 else { 00605 projection_offset = 00606 (inT16) (projection->pile_count (x) / projection_scale); 00607 if (projection_offset > offset) 00608 offset = projection_offset; 00609 mid_cut = TRUE; 00610 } 00611 } 00612 if ((start == 0 && end == 0) 00613 || !textord_fast_pitch_test 00614 || (x - projection_left - start) % pitch <= end) 00615 cutpts[x - array_origin].assign (cutpts, array_origin, x, 00616 faking, mid_cut, offset, projection, 00617 projection_scale, zero_count, pitch, 00618 pitch_error); 00619 else 00620 cutpts[x - array_origin].assign_cheap (cutpts, array_origin, x, 00621 faking, mid_cut, offset, 00622 projection, projection_scale, 00623 zero_count, pitch, 00624 pitch_error); 00625 x++; 00626 if (next_zero < x || next_zero == x + zero_offset) 00627 next_zero = x + zero_offset + 1; 00628 if (projection->pile_count (x + zero_offset) <= zero_count) 00629 next_zero = x + zero_offset; 00630 } 00631 00632 best_fake = MAX_INT16; 00633 best_cost = MAX_INT32; 00634 best_count = MAX_INT16; 00635 while (x < right_edge + pitch) { 00636 offset = x < right_edge ? right_edge - x : 0; 00637 cutpts[x - array_origin].assign (cutpts, array_origin, x, 00638 FALSE, FALSE, offset, projection, 00639 projection_scale, zero_count, pitch, 00640 pitch_error); 00641 cutpts[x - array_origin].terminal = TRUE; 00642 if (cutpts[x - array_origin].index () + 00643 cutpts[x - array_origin].fake_count <= best_count + best_fake) { 00644 if (cutpts[x - array_origin].fake_count < best_fake 00645 || (cutpts[x - array_origin].fake_count == best_fake 00646 && cutpts[x - array_origin].cost_function () < best_cost)) { 00647 best_fake = cutpts[x - array_origin].fake_count; 00648 best_cost = cutpts[x - array_origin].cost_function (); 00649 best_left_x = x; 00650 best_right_x = x; 00651 best_count = cutpts[x - array_origin].index (); 00652 } 00653 else if (cutpts[x - array_origin].fake_count == best_fake 00654 && x == best_right_x + 1 00655 && cutpts[x - array_origin].cost_function () == best_cost) { 00656 //exactly equal 00657 best_right_x = x; 00658 } 00659 } 00660 x++; 00661 } 00662 ASSERT_HOST (best_fake < MAX_INT16); 00663 00664 best_end = &cutpts[(best_left_x + best_right_x) / 2 - array_origin]; 00665 // for (x=left_edge-pitch;x<right_edge+pitch;x++) 00666 // { 00667 // tprintf("x=%d, C=%g, s=%g, sq=%g, prev=%d\n", 00668 // x,cutpts[x-array_origin].cost_function(), 00669 // cutpts[x-array_origin].sum(), 00670 // cutpts[x-array_origin].squares(), 00671 // cutpts[x-array_origin].previous()->position()); 00672 // } 00673 occupation_count = -1; 00674 do { 00675 for (x = best_end->position () - pitch + pitch_error; 00676 x < best_end->position () - pitch_error 00677 && projection->pile_count (x) == 0; x++); 00678 if (x < best_end->position () - pitch_error) 00679 occupation_count++; 00680 //copy it 00681 segpt = new FPSEGPT (best_end); 00682 seg_it.add_before_then_move (segpt); 00683 best_end = best_end->previous (); 00684 } 00685 while (best_end != NULL); 00686 seg_it.move_to_last (); 00687 mean_sum = seg_it.data ()->sum (); 00688 mean_sum = mean_sum * mean_sum / best_count; 00689 if (seg_it.data ()->squares () - mean_sum < 0) 00690 tprintf ("Impossible sqsum=%g, mean=%g, total=%d\n", 00691 seg_it.data ()->squares (), seg_it.data ()->sum (), best_count); 00692 free_mem(mins); 00693 free_mem(cutpts); 00694 return seg_it.data ()->squares () - mean_sum; 00695 }