Tesseract
3.02
|
00001 /********************************************************************** 00002 * File: pitsync1.cpp (Formerly pitsync.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 #include "mfcpch.h" 00021 #ifdef __UNIX__ 00022 #include <assert.h> 00023 #endif 00024 #include <math.h> 00025 #include "memry.h" 00026 #include "pitsync1.h" 00027 00028 #include "notdll.h" 00029 00030 ELISTIZE (FPSEGPT) CLISTIZE (FPSEGPT_LIST) 00031 #define EXTERN 00032 EXTERN 00033 INT_VAR (pitsync_linear_version, 6, "Use new fast algorithm"); 00034 EXTERN 00035 double_VAR (pitsync_joined_edge, 0.75, 00036 "Dist inside big blob for chopping"); 00037 EXTERN 00038 double_VAR (pitsync_offset_freecut_fraction, 0.25, 00039 "Fraction of cut for free cuts"); 00040 EXTERN 00041 INT_VAR (pitsync_fake_depth, 1, "Max advance fake generation"); 00042 00043 /********************************************************************** 00044 * FPSEGPT::FPSEGPT 00045 * 00046 * Constructor to make a new FPSEGPT. 00047 * The existing FPCUTPT is duplicated. 00048 **********************************************************************/ 00049 00050 FPSEGPT::FPSEGPT( //constructor 00051 FPCUTPT *cutpt //create from new form 00052 ) { 00053 pred = NULL; 00054 mean_sum = cutpt->sum (); 00055 sq_sum = cutpt->squares (); 00056 cost = cutpt->cost_function (); 00057 faked = cutpt->faked; 00058 terminal = cutpt->terminal; 00059 fake_count = cutpt->fake_count; 00060 xpos = cutpt->position (); 00061 mid_cuts = cutpt->cheap_cuts (); 00062 } 00063 00064 00065 /********************************************************************** 00066 * FPSEGPT::FPSEGPT 00067 * 00068 * Constructor to make a new FPSEGPT. 00069 **********************************************************************/ 00070 00071 FPSEGPT::FPSEGPT ( //constructor 00072 inT16 x //position 00073 ):xpos (x) { 00074 pred = NULL; 00075 mean_sum = 0; 00076 sq_sum = 0; 00077 cost = 0; 00078 faked = FALSE; 00079 terminal = FALSE; 00080 fake_count = 0; 00081 mid_cuts = 0; 00082 } 00083 00084 00085 /********************************************************************** 00086 * FPSEGPT::FPSEGPT 00087 * 00088 * Constructor to make a new FPSEGPT. 00089 **********************************************************************/ 00090 00091 FPSEGPT::FPSEGPT ( //constructor 00092 inT16 x, //position 00093 BOOL8 faking, //faking this one 00094 inT16 offset, //dist to gap 00095 inT16 region_index, //segment number 00096 inT16 pitch, //proposed pitch 00097 inT16 pitch_error, //allowed tolerance 00098 FPSEGPT_LIST * prev_list //previous segment 00099 ):xpos (x) { 00100 inT16 best_fake; //on previous 00101 FPSEGPT *segpt; //segment point 00102 inT32 dist; //from prev segment 00103 double sq_dist; //squared distance 00104 double mean; //mean pitch 00105 double total; //total dists 00106 double factor; //cost function 00107 FPSEGPT_IT pred_it = prev_list;//for previuos segment 00108 00109 cost = MAX_FLOAT32; 00110 pred = NULL; 00111 faked = faking; 00112 terminal = FALSE; 00113 best_fake = MAX_INT16; 00114 mid_cuts = 0; 00115 for (pred_it.mark_cycle_pt (); !pred_it.cycled_list (); pred_it.forward ()) { 00116 segpt = pred_it.data (); 00117 if (segpt->fake_count < best_fake) 00118 best_fake = segpt->fake_count; 00119 dist = x - segpt->xpos; 00120 if (dist >= pitch - pitch_error && dist <= pitch + pitch_error 00121 && !segpt->terminal) { 00122 total = segpt->mean_sum + dist; 00123 sq_dist = dist * dist + segpt->sq_sum + offset * offset; 00124 //sum of squarees 00125 mean = total / region_index; 00126 factor = mean - pitch; 00127 factor *= factor; 00128 factor += sq_dist / (region_index) - mean * mean; 00129 if (factor < cost) { 00130 cost = factor; //find least cost 00131 pred = segpt; //save path 00132 mean_sum = total; 00133 sq_sum = sq_dist; 00134 fake_count = segpt->fake_count + faked; 00135 } 00136 } 00137 } 00138 if (fake_count > best_fake + 1) 00139 pred = NULL; //fail it 00140 } 00141 00142 00143 /********************************************************************** 00144 * check_pitch_sync 00145 * 00146 * Construct the lattice of possible segmentation points and choose the 00147 * optimal path. Return the optimal path only. 00148 * The return value is a measure of goodness of the sync. 00149 **********************************************************************/ 00150 00151 double check_pitch_sync( //find segmentation 00152 BLOBNBOX_IT *blob_it, //blobs to do 00153 inT16 blob_count, //no of blobs 00154 inT16 pitch, //pitch estimate 00155 inT16 pitch_error, //tolerance 00156 STATS *projection, //vertical 00157 FPSEGPT_LIST *seg_list //output list 00158 ) { 00159 inT16 x; //current coord 00160 inT16 min_index; //blob number 00161 inT16 max_index; //blob number 00162 inT16 left_edge; //of word 00163 inT16 right_edge; //of word 00164 inT16 right_max; //max allowed x 00165 inT16 min_x; //in this region 00166 inT16 max_x; 00167 inT16 region_index; 00168 inT16 best_region_index = 0; //for best result 00169 inT16 offset; //dist to legal area 00170 inT16 left_best_x; //edge of good region 00171 inT16 right_best_x; //right edge 00172 TBOX min_box; //bounding box 00173 TBOX max_box; //bounding box 00174 TBOX next_box; //box of next blob 00175 FPSEGPT *segpt; //segment point 00176 FPSEGPT_LIST *segpts; //points in a segment 00177 double best_cost; //best path 00178 double mean_sum; //computes result 00179 FPSEGPT *best_end; //end of best path 00180 BLOBNBOX_IT min_it; //copy iterator 00181 BLOBNBOX_IT max_it; //copy iterator 00182 FPSEGPT_IT segpt_it; //iterator 00183 //output segments 00184 FPSEGPT_IT outseg_it = seg_list; 00185 FPSEGPT_LIST_CLIST lattice; //list of lists 00186 //region iterator 00187 FPSEGPT_LIST_C_IT lattice_it = &lattice; 00188 00189 // tprintf("Computing sync on word of %d blobs with pitch %d\n", 00190 // blob_count, pitch); 00191 // if (blob_count==8 && pitch==27) 00192 // projection->print(stdout,TRUE); 00193 if (pitch < 3) 00194 pitch = 3; //nothing ludicrous 00195 if ((pitch - 3) / 2 < pitch_error) 00196 pitch_error = (pitch - 3) / 2; 00197 min_it = *blob_it; 00198 min_box = box_next (&min_it); //get box 00199 // if (blob_count==8 && pitch==27) 00200 // tprintf("1st box at (%d,%d)->(%d,%d)\n", 00201 // min_box.left(),min_box.bottom(), 00202 // min_box.right(),min_box.top()); 00203 //left of word 00204 left_edge = min_box.left () + pitch_error; 00205 for (min_index = 1; min_index < blob_count; min_index++) { 00206 min_box = box_next (&min_it); 00207 // if (blob_count==8 && pitch==27) 00208 // tprintf("Box at (%d,%d)->(%d,%d)\n", 00209 // min_box.left(),min_box.bottom(), 00210 // min_box.right(),min_box.top()); 00211 } 00212 right_edge = min_box.right (); //end of word 00213 max_x = left_edge; 00214 //min permissible 00215 min_x = max_x - pitch + pitch_error * 2 + 1; 00216 right_max = right_edge + pitch - pitch_error - 1; 00217 segpts = new FPSEGPT_LIST; //list of points 00218 segpt_it.set_to_list (segpts); 00219 for (x = min_x; x <= max_x; x++) { 00220 segpt = new FPSEGPT (x); //make a new one 00221 //put in list 00222 segpt_it.add_after_then_move (segpt); 00223 } 00224 //first segment 00225 lattice_it.add_before_then_move (segpts); 00226 min_index = 0; 00227 region_index = 1; 00228 best_cost = MAX_FLOAT32; 00229 best_end = NULL; 00230 min_it = *blob_it; 00231 min_box = box_next (&min_it); //first box 00232 do { 00233 left_best_x = -1; 00234 right_best_x = -1; 00235 segpts = new FPSEGPT_LIST; //list of points 00236 segpt_it.set_to_list (segpts); 00237 min_x += pitch - pitch_error;//next limits 00238 max_x += pitch + pitch_error; 00239 while (min_box.right () < min_x && min_index < blob_count) { 00240 min_index++; 00241 min_box = box_next (&min_it); 00242 } 00243 max_it = min_it; 00244 max_index = min_index; 00245 max_box = min_box; 00246 next_box = box_next (&max_it); 00247 for (x = min_x; x <= max_x && x <= right_max; x++) { 00248 while (x < right_edge && max_index < blob_count 00249 && x > max_box.right ()) { 00250 max_index++; 00251 max_box = next_box; 00252 next_box = box_next (&max_it); 00253 } 00254 if (x <= max_box.left () + pitch_error 00255 || x >= max_box.right () - pitch_error || x >= right_edge 00256 || (max_index < blob_count - 1 && x >= next_box.left ()) 00257 || (x - max_box.left () > pitch * pitsync_joined_edge 00258 && max_box.right () - x > pitch * pitsync_joined_edge)) { 00259 // || projection->local_min(x)) 00260 if (x - max_box.left () > 0 00261 && x - max_box.left () <= pitch_error) 00262 //dist to real break 00263 offset = x - max_box.left (); 00264 else if (max_box.right () - x > 0 00265 && max_box.right () - x <= pitch_error 00266 && (max_index >= blob_count - 1 00267 || x < next_box.left ())) 00268 offset = max_box.right () - x; 00269 else 00270 offset = 0; 00271 // offset=pitsync_offset_freecut_fraction*projection->pile_count(x); 00272 segpt = new FPSEGPT (x, FALSE, offset, region_index, 00273 pitch, pitch_error, lattice_it.data ()); 00274 } 00275 else { 00276 offset = projection->pile_count (x); 00277 segpt = new FPSEGPT (x, TRUE, offset, region_index, 00278 pitch, pitch_error, lattice_it.data ()); 00279 } 00280 if (segpt->previous () != NULL) { 00281 segpt_it.add_after_then_move (segpt); 00282 if (x >= right_edge - pitch_error) { 00283 segpt->terminal = TRUE;//no more wanted 00284 if (segpt->cost_function () < best_cost) { 00285 best_cost = segpt->cost_function (); 00286 //find least 00287 best_end = segpt; 00288 best_region_index = region_index; 00289 left_best_x = x; 00290 right_best_x = x; 00291 } 00292 else if (segpt->cost_function () == best_cost 00293 && right_best_x == x - 1) 00294 right_best_x = x; 00295 } 00296 } 00297 else { 00298 delete segpt; //no good 00299 } 00300 } 00301 if (segpts->empty ()) { 00302 if (best_end != NULL) 00303 break; //already found one 00304 make_illegal_segment (lattice_it.data (), min_box, min_it, 00305 region_index, pitch, pitch_error, segpts); 00306 } 00307 else { 00308 if (right_best_x > left_best_x + 1) { 00309 left_best_x = (left_best_x + right_best_x + 1) / 2; 00310 for (segpt_it.mark_cycle_pt (); !segpt_it.cycled_list () 00311 && segpt_it.data ()->position () != left_best_x; 00312 segpt_it.forward ()); 00313 if (segpt_it.data ()->position () == left_best_x) 00314 //middle of region 00315 best_end = segpt_it.data (); 00316 } 00317 } 00318 //new segment 00319 lattice_it.add_before_then_move (segpts); 00320 region_index++; 00321 } 00322 while (min_x < right_edge); 00323 ASSERT_HOST (best_end != NULL);//must always find some 00324 00325 for (lattice_it.mark_cycle_pt (); !lattice_it.cycled_list (); 00326 lattice_it.forward ()) { 00327 segpts = lattice_it.data (); 00328 segpt_it.set_to_list (segpts); 00329 // if (blob_count==8 && pitch==27) 00330 // { 00331 // for (segpt_it.mark_cycle_pt();!segpt_it.cycled_list();segpt_it.forward()) 00332 // { 00333 // segpt=segpt_it.data(); 00334 // tprintf("At %d, (%x) cost=%g, m=%g, sq=%g, pred=%x\n", 00335 // segpt->position(),segpt,segpt->cost_function(), 00336 // segpt->sum(),segpt->squares(),segpt->previous()); 00337 // } 00338 // tprintf("\n"); 00339 // } 00340 for (segpt_it.mark_cycle_pt (); !segpt_it.cycled_list () 00341 && segpt_it.data () != best_end; segpt_it.forward ()); 00342 if (segpt_it.data () == best_end) { 00343 //save good one 00344 segpt = segpt_it.extract (); 00345 outseg_it.add_before_then_move (segpt); 00346 best_end = segpt->previous (); 00347 } 00348 } 00349 ASSERT_HOST (best_end == NULL); 00350 ASSERT_HOST (!outseg_it.empty ()); 00351 outseg_it.move_to_last (); 00352 mean_sum = outseg_it.data ()->sum (); 00353 mean_sum = mean_sum * mean_sum / best_region_index; 00354 if (outseg_it.data ()->squares () - mean_sum < 0) 00355 tprintf ("Impossible sqsum=%g, mean=%g, total=%d\n", 00356 outseg_it.data ()->squares (), outseg_it.data ()->sum (), 00357 best_region_index); 00358 lattice.deep_clear (); //shift the lot 00359 return outseg_it.data ()->squares () - mean_sum; 00360 } 00361 00362 00363 /********************************************************************** 00364 * make_illegal_segment 00365 * 00366 * Make a fake set of chop points due to having no legal places. 00367 **********************************************************************/ 00368 00369 void make_illegal_segment( //find segmentation 00370 FPSEGPT_LIST *prev_list, //previous segments 00371 TBOX blob_box, //bounding box 00372 BLOBNBOX_IT blob_it, //iterator 00373 inT16 region_index, //number of segment 00374 inT16 pitch, //pitch estimate 00375 inT16 pitch_error, //tolerance 00376 FPSEGPT_LIST *seg_list //output list 00377 ) { 00378 inT16 x; //current coord 00379 inT16 min_x = 0; //in this region 00380 inT16 max_x = 0; 00381 inT16 offset; //dist to edge 00382 FPSEGPT *segpt; //segment point 00383 FPSEGPT *prevpt; //previous point 00384 float best_cost; //best path 00385 FPSEGPT_IT segpt_it = seg_list;//iterator 00386 //previous points 00387 FPSEGPT_IT prevpt_it = prev_list; 00388 00389 best_cost = MAX_FLOAT32; 00390 for (prevpt_it.mark_cycle_pt (); !prevpt_it.cycled_list (); 00391 prevpt_it.forward ()) { 00392 prevpt = prevpt_it.data (); 00393 if (prevpt->cost_function () < best_cost) { 00394 //find least 00395 best_cost = prevpt->cost_function (); 00396 min_x = prevpt->position (); 00397 max_x = min_x; //limits on coords 00398 } 00399 else if (prevpt->cost_function () == best_cost) { 00400 max_x = prevpt->position (); 00401 } 00402 } 00403 min_x += pitch - pitch_error; 00404 max_x += pitch + pitch_error; 00405 for (x = min_x; x <= max_x; x++) { 00406 while (x > blob_box.right ()) { 00407 blob_box = box_next (&blob_it); 00408 } 00409 offset = x - blob_box.left (); 00410 if (blob_box.right () - x < offset) 00411 offset = blob_box.right () - x; 00412 segpt = new FPSEGPT (x, FALSE, offset, 00413 region_index, pitch, pitch_error, prev_list); 00414 if (segpt->previous () != NULL) { 00415 ASSERT_HOST (offset >= 0); 00416 fprintf (stderr, "made fake at %d\n", x); 00417 //make one up 00418 segpt_it.add_after_then_move (segpt); 00419 segpt->faked = TRUE; 00420 segpt->fake_count++; 00421 } 00422 else 00423 delete segpt; 00424 } 00425 }