Tesseract
3.02
|
00001 /* -*-C-*- 00002 ******************************************************************************** 00003 * 00004 * File: seam.c (Formerly seam.c) 00005 * Description: 00006 * Author: Mark Seaman, OCR Technology 00007 * Created: Fri Oct 16 14:37:00 1987 00008 * Modified: Fri May 17 16:30:13 1991 (Mark Seaman) marks@hpgrlt 00009 * Language: C 00010 * Package: N/A 00011 * Status: Reusable Software Component 00012 * 00013 * (c) Copyright 1987, Hewlett-Packard Company. 00014 ** Licensed under the Apache License, Version 2.0 (the "License"); 00015 ** you may not use this file except in compliance with the License. 00016 ** You may obtain a copy of the License at 00017 ** http://www.apache.org/licenses/LICENSE-2.0 00018 ** Unless required by applicable law or agreed to in writing, software 00019 ** distributed under the License is distributed on an "AS IS" BASIS, 00020 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00021 ** See the License for the specific language governing permissions and 00022 ** limitations under the License. 00023 * 00024 *********************************************************************************/ 00025 /*---------------------------------------------------------------------- 00026 I n c l u d e s 00027 ----------------------------------------------------------------------*/ 00028 #include "seam.h" 00029 #include "blobs.h" 00030 #include "callcpp.h" 00031 #include "structures.h" 00032 00033 #ifdef __UNIX__ 00034 #include <assert.h> 00035 #endif 00036 00037 /*---------------------------------------------------------------------- 00038 V a r i a b l e s 00039 ----------------------------------------------------------------------*/ 00040 #define NUM_STARTING_SEAMS 20 00041 makestructure(newseam, free_seam, SEAM); 00042 00043 /*---------------------------------------------------------------------- 00044 Public Function Code 00045 ----------------------------------------------------------------------*/ 00053 bool point_in_split(SPLIT *split, EDGEPT *point1, EDGEPT *point2) { 00054 return ((split) ? ((exact_point (split->point1, point1) || 00055 exact_point (split->point1, point2) || 00056 exact_point (split->point2, point1) || 00057 exact_point (split->point2, point2)) ? TRUE : FALSE) 00058 : FALSE); 00059 } 00060 00061 00069 bool point_in_seam(SEAM *seam, SPLIT *split) { 00070 return (point_in_split(seam->split1, split->point1, split->point2) || 00071 point_in_split(seam->split2, split->point1, split->point2) || 00072 point_in_split(seam->split3, split->point1, split->point2)); 00073 } 00074 00081 bool point_used_by_split(SPLIT *split, EDGEPT *point) { 00082 if (split == NULL) return false; 00083 return point == split->point1 || point == split->point2; 00084 } 00085 00092 bool point_used_by_seam(SEAM *seam, EDGEPT *point) { 00093 if (seam == NULL) return false; 00094 return point_used_by_split(seam->split1, point) || 00095 point_used_by_split(seam->split2, point) || 00096 point_used_by_split(seam->split3, point); 00097 } 00098 00104 SEAMS add_seam(SEAMS seam_list, SEAM *seam) { 00105 return (array_push (seam_list, seam)); 00106 } 00107 00108 00116 void combine_seams(SEAM *dest_seam, SEAM *source_seam) { 00117 dest_seam->priority += source_seam->priority; 00118 dest_seam->location += source_seam->location; 00119 dest_seam->location /= 2; 00120 00121 if (source_seam->split1) { 00122 if (!dest_seam->split1) 00123 dest_seam->split1 = source_seam->split1; 00124 else if (!dest_seam->split2) 00125 dest_seam->split2 = source_seam->split1; 00126 else if (!dest_seam->split3) 00127 dest_seam->split3 = source_seam->split1; 00128 else 00129 cprintf("combine_seam: Seam is too crowded, can't be combined !\n"); 00130 } 00131 if (source_seam->split2) { 00132 if (!dest_seam->split2) 00133 dest_seam->split2 = source_seam->split2; 00134 else if (!dest_seam->split3) 00135 dest_seam->split3 = source_seam->split2; 00136 else 00137 cprintf("combine_seam: Seam is too crowded, can't be combined !\n"); 00138 } 00139 if (source_seam->split3) { 00140 if (!dest_seam->split3) 00141 dest_seam->split3 = source_seam->split3; 00142 else 00143 cprintf("combine_seam: Seam is too crowded, can't be combined !\n"); 00144 } 00145 free_seam(source_seam); 00146 } 00147 00148 00154 void delete_seam(void *arg) { //SEAM *seam) 00155 SEAM *seam = (SEAM *) arg; 00156 00157 if (seam) { 00158 if (seam->split1) 00159 delete_split(seam->split1); 00160 if (seam->split2) 00161 delete_split(seam->split2); 00162 if (seam->split3) 00163 delete_split(seam->split3); 00164 free_seam(seam); 00165 } 00166 } 00167 00175 SEAMS start_seam_list(TBLOB *blobs) { 00176 TBLOB *blob; 00177 SEAMS seam_list; 00178 TPOINT location; 00179 /* Seam slot per char */ 00180 seam_list = new_seam_list (); 00181 00182 for (blob = blobs; blob->next != NULL; blob = blob->next) { 00183 TBOX bbox = blob->bounding_box(); 00184 TBOX nbox = blob->next->bounding_box(); 00185 location.x = (bbox.right() + nbox.left()) / 2; 00186 location.y = (bbox.bottom() + bbox.top() + nbox.bottom() + nbox.top()) / 4; 00187 seam_list = add_seam(seam_list, 00188 new_seam(0.0, location, NULL, NULL, NULL)); 00189 } 00190 00191 return seam_list; 00192 } 00193 00200 void free_seam_list(SEAMS seam_list) { 00201 int x; 00202 00203 array_loop(seam_list, x) delete_seam(array_value (seam_list, x)); 00204 array_free(seam_list); 00205 } 00206 00207 00213 bool test_insert_seam(SEAMS seam_list, 00214 int index, 00215 TBLOB *left_blob, 00216 TBLOB *first_blob) { 00217 SEAM *test_seam; 00218 TBLOB *blob; 00219 int test_index; 00220 int list_length; 00221 00222 list_length = array_count (seam_list); 00223 for (test_index=0, blob=first_blob->next; 00224 test_index < index; 00225 test_index++, blob=blob->next) { 00226 test_seam = (SEAM *) array_value(seam_list, test_index); 00227 if (test_index + test_seam->widthp < index && 00228 test_seam->widthp + test_index == index - 1 && 00229 account_splits_right(test_seam, blob) < 0) 00230 return false; 00231 } 00232 for (test_index=index, blob=left_blob->next; 00233 test_index < list_length; 00234 test_index++, blob=blob->next) { 00235 test_seam = (SEAM *) array_value(seam_list, test_index); 00236 if (test_index - test_seam->widthn >= index && 00237 test_index - test_seam->widthn == index && 00238 account_splits_left(test_seam, first_blob, blob) < 0) 00239 return false; 00240 } 00241 return true; 00242 } 00243 00250 SEAMS insert_seam(SEAMS seam_list, 00251 int index, 00252 SEAM *seam, 00253 TBLOB *left_blob, 00254 TBLOB *first_blob) { 00255 SEAM *test_seam; 00256 TBLOB *blob; 00257 int test_index; 00258 int list_length; 00259 00260 list_length = array_count(seam_list); 00261 for (test_index=0, blob=first_blob->next; 00262 test_index < index; 00263 test_index++, blob=blob->next) { 00264 test_seam = (SEAM *) array_value(seam_list, test_index); 00265 if (test_index + test_seam->widthp >= index) { 00266 test_seam->widthp++; /*got in the way */ 00267 } else if (test_seam->widthp + test_index == index - 1) { 00268 test_seam->widthp = account_splits_right(test_seam, blob); 00269 if (test_seam->widthp < 0) { 00270 cprintf("Failed to find any right blob for a split!\n"); 00271 print_seam("New dud seam", seam); 00272 print_seam("Failed seam", test_seam); 00273 } 00274 } 00275 } 00276 for (test_index=index, blob=left_blob->next; 00277 test_index < list_length; 00278 test_index++, blob=blob->next) { 00279 test_seam = (SEAM *) array_value(seam_list, test_index); 00280 if (test_index - test_seam->widthn < index) { 00281 test_seam->widthn++; /*got in the way */ 00282 } else if (test_index - test_seam->widthn == index) { 00283 test_seam->widthn = account_splits_left(test_seam, first_blob, blob); 00284 if (test_seam->widthn < 0) { 00285 cprintf("Failed to find any left blob for a split!\n"); 00286 print_seam("New dud seam", seam); 00287 print_seam("Failed seam", test_seam); 00288 } 00289 } 00290 } 00291 return (array_insert (seam_list, index, seam)); 00292 } 00293 00294 00301 int account_splits_right(SEAM *seam, TBLOB *blob) { 00302 inT8 found_em[3]; 00303 inT8 width; 00304 00305 found_em[0] = seam->split1 == NULL; 00306 found_em[1] = seam->split2 == NULL; 00307 found_em[2] = seam->split3 == NULL; 00308 if (found_em[0] && found_em[1] && found_em[2]) 00309 return 0; 00310 width = 0; 00311 do { 00312 if (!found_em[0]) 00313 found_em[0] = find_split_in_blob(seam->split1, blob); 00314 if (!found_em[1]) 00315 found_em[1] = find_split_in_blob(seam->split2, blob); 00316 if (!found_em[2]) 00317 found_em[2] = find_split_in_blob(seam->split3, blob); 00318 if (found_em[0] && found_em[1] && found_em[2]) { 00319 return width; 00320 } 00321 width++; 00322 blob = blob->next; 00323 } while (blob != NULL); 00324 return -1; 00325 } 00326 00327 00334 int account_splits_left(SEAM *seam, TBLOB *blob, TBLOB *end_blob) { 00335 inT32 depth = 0; 00336 inT8 width = 0; 00337 inT8 found_em[3]; 00338 account_splits_left_helper(seam, blob, end_blob, &depth, &width, found_em); 00339 return width; 00340 } 00341 00342 void account_splits_left_helper(SEAM *seam, TBLOB *blob, TBLOB *end_blob, 00343 inT32 *depth, inT8 *width, inT8* found_em) { 00344 if (blob != end_blob) { 00345 (*depth)++; 00346 account_splits_left_helper(seam, blob->next, end_blob, 00347 depth, width, found_em); 00348 (*depth)--; 00349 } else { 00350 found_em[0] = seam->split1 == NULL; 00351 found_em[1] = seam->split2 == NULL; 00352 found_em[2] = seam->split3 == NULL; 00353 *width = 0; 00354 } 00355 if (!found_em[0]) 00356 found_em[0] = find_split_in_blob(seam->split1, blob); 00357 if (!found_em[1]) 00358 found_em[1] = find_split_in_blob(seam->split2, blob); 00359 if (!found_em[2]) 00360 found_em[2] = find_split_in_blob(seam->split3, blob); 00361 if (!found_em[0] || !found_em[1] || !found_em[2]) { 00362 (*width)++; 00363 if (*depth == 0) { 00364 *width = -1; 00365 } 00366 } 00367 } 00368 00369 00375 bool find_split_in_blob(SPLIT *split, TBLOB *blob) { 00376 TESSLINE *outline; 00377 00378 for (outline = blob->outlines; outline != NULL; outline = outline->next) 00379 if (outline->Contains(split->point1->pos)) 00380 break; 00381 if (outline == NULL) 00382 return FALSE; 00383 for (outline = blob->outlines; outline != NULL; outline = outline->next) 00384 if (outline->Contains(split->point2->pos)) 00385 return TRUE; 00386 return FALSE; 00387 } 00388 00389 00396 SEAM *join_two_seams(SEAM *seam1, SEAM *seam2) { 00397 SEAM *result = NULL; 00398 SEAM *temp; 00399 00400 assert(seam1 &&seam2); 00401 00402 if (((seam1->split3 == NULL && seam2->split2 == NULL) || 00403 (seam1->split2 == NULL && seam2->split3 == NULL) || 00404 seam1->split1 == NULL || seam2->split1 == NULL) && 00405 (!shared_split_points(seam1, seam2))) { 00406 clone_seam(result, seam1); 00407 clone_seam(temp, seam2); 00408 combine_seams(result, temp); 00409 } 00410 return (result); 00411 } 00412 00413 00421 SEAM *new_seam(PRIORITY priority, 00422 const TPOINT& location, 00423 SPLIT *split1, 00424 SPLIT *split2, 00425 SPLIT *split3) { 00426 SEAM *seam; 00427 00428 seam = newseam (); 00429 00430 seam->priority = priority; 00431 seam->location = location; 00432 seam->widthp = 0; 00433 seam->widthn = 0; 00434 seam->split1 = split1; 00435 seam->split2 = split2; 00436 seam->split3 = split3; 00437 00438 return (seam); 00439 } 00440 00441 00447 SEAMS new_seam_list() { 00448 return (array_new (NUM_STARTING_SEAMS)); 00449 } 00450 00451 00458 void print_seam(const char *label, SEAM *seam) { 00459 if (seam) { 00460 cprintf(label); 00461 cprintf(" %6.2f @ (%d,%d), p=%d, n=%d ", 00462 seam->priority, seam->location.x, seam->location.y, 00463 seam->widthp, seam->widthn); 00464 print_split(seam->split1); 00465 00466 if (seam->split2) { 00467 cprintf(", "); 00468 print_split (seam->split2); 00469 if (seam->split3) { 00470 cprintf(", "); 00471 print_split (seam->split3); 00472 } 00473 } 00474 cprintf ("\n"); 00475 } 00476 } 00477 00478 00485 void print_seams(const char *label, SEAMS seams) { 00486 int x; 00487 char number[CHARS_PER_LINE]; 00488 00489 if (seams) { 00490 cprintf("%s\n", label); 00491 array_loop(seams, x) { 00492 sprintf(number, "%2d: ", x); 00493 print_seam(number, (SEAM *) array_value(seams, x)); 00494 } 00495 cprintf("\n"); 00496 } 00497 } 00498 00499 00507 int shared_split_points(SEAM *seam1, SEAM *seam2) { 00508 if (seam1 == NULL || seam2 == NULL) 00509 return (FALSE); 00510 00511 if (seam2->split1 == NULL) 00512 return (FALSE); 00513 if (point_in_seam(seam1, seam2->split1)) 00514 return (TRUE); 00515 00516 if (seam2->split2 == NULL) 00517 return (FALSE); 00518 if (point_in_seam(seam1, seam2->split2)) 00519 return (TRUE); 00520 00521 if (seam2->split3 == NULL) 00522 return (FALSE); 00523 if (point_in_seam(seam1, seam2->split3)) 00524 return (TRUE); 00525 00526 return (FALSE); 00527 } 00528 00529 /********************************************************************** 00530 * break_pieces 00531 * 00532 * Break up the blobs in this chain so that they are all independent. 00533 * This operation should undo the affect of join_pieces. 00534 **********************************************************************/ 00535 void break_pieces(TBLOB *blobs, SEAMS seams, inT16 start, inT16 end) { 00536 TESSLINE *outline = blobs->outlines; 00537 TBLOB *next_blob; 00538 inT16 x; 00539 00540 for (x = start; x < end; x++) 00541 reveal_seam ((SEAM *) array_value (seams, x)); 00542 00543 next_blob = blobs->next; 00544 00545 while (outline && next_blob) { 00546 if (outline->next == next_blob->outlines) { 00547 outline->next = NULL; 00548 outline = next_blob->outlines; 00549 next_blob = next_blob->next; 00550 } 00551 else { 00552 outline = outline->next; 00553 } 00554 } 00555 } 00556 00557 00558 /********************************************************************** 00559 * join_pieces 00560 * 00561 * Join a group of base level pieces into a single blob that can then 00562 * be classified. 00563 **********************************************************************/ 00564 void join_pieces(TBLOB *piece_blobs, SEAMS seams, inT16 start, inT16 end) { 00565 TBLOB *next_blob; 00566 TBLOB *blob; 00567 inT16 x; 00568 TESSLINE *outline; 00569 SEAM *seam; 00570 00571 for (x = 0, blob = piece_blobs; x < start; x++) 00572 blob = blob->next; 00573 next_blob = blob->next; 00574 outline = blob->outlines; 00575 if (!outline) 00576 return; 00577 00578 while (x < end) { 00579 seam = (SEAM *) array_value (seams, x); 00580 if (x - seam->widthn >= start && x + seam->widthp < end) 00581 hide_seam(seam); 00582 while (outline->next) 00583 outline = outline->next; 00584 outline->next = next_blob->outlines; 00585 next_blob = next_blob->next; 00586 00587 x++; 00588 } 00589 } 00590 00591 00592 /********************************************************************** 00593 * hide_seam 00594 * 00595 * Change the edge points that are referenced by this seam to make 00596 * them hidden edges. 00597 **********************************************************************/ 00598 void hide_seam(SEAM *seam) { 00599 if (seam == NULL || seam->split1 == NULL) 00600 return; 00601 hide_edge_pair (seam->split1->point1, seam->split1->point2); 00602 00603 if (seam->split2 == NULL) 00604 return; 00605 hide_edge_pair (seam->split2->point1, seam->split2->point2); 00606 00607 if (seam->split3 == NULL) 00608 return; 00609 hide_edge_pair (seam->split3->point1, seam->split3->point2); 00610 } 00611 00612 00613 /********************************************************************** 00614 * hide_edge_pair 00615 * 00616 * Change the edge points that are referenced by this seam to make 00617 * them hidden edges. 00618 **********************************************************************/ 00619 void hide_edge_pair(EDGEPT *pt1, EDGEPT *pt2) { 00620 EDGEPT *edgept; 00621 00622 edgept = pt1; 00623 do { 00624 edgept->Hide(); 00625 edgept = edgept->next; 00626 } 00627 while (!exact_point (edgept, pt2) && edgept != pt1); 00628 if (edgept == pt1) { 00629 /* cprintf("Hid entire outline at (%d,%d)!!\n", 00630 edgept->pos.x,edgept->pos.y); */ 00631 } 00632 edgept = pt2; 00633 do { 00634 edgept->Hide(); 00635 edgept = edgept->next; 00636 } 00637 while (!exact_point (edgept, pt1) && edgept != pt2); 00638 if (edgept == pt2) { 00639 /* cprintf("Hid entire outline at (%d,%d)!!\n", 00640 edgept->pos.x,edgept->pos.y); */ 00641 } 00642 } 00643 00644 00645 /********************************************************************** 00646 * reveal_seam 00647 * 00648 * Change the edge points that are referenced by this seam to make 00649 * them hidden edges. 00650 **********************************************************************/ 00651 void reveal_seam(SEAM *seam) { 00652 if (seam == NULL || seam->split1 == NULL) 00653 return; 00654 reveal_edge_pair (seam->split1->point1, seam->split1->point2); 00655 00656 if (seam->split2 == NULL) 00657 return; 00658 reveal_edge_pair (seam->split2->point1, seam->split2->point2); 00659 00660 if (seam->split3 == NULL) 00661 return; 00662 reveal_edge_pair (seam->split3->point1, seam->split3->point2); 00663 } 00664 00665 00666 /********************************************************************** 00667 * reveal_edge_pair 00668 * 00669 * Change the edge points that are referenced by this seam to make 00670 * them hidden edges. 00671 **********************************************************************/ 00672 void reveal_edge_pair(EDGEPT *pt1, EDGEPT *pt2) { 00673 EDGEPT *edgept; 00674 00675 edgept = pt1; 00676 do { 00677 edgept->Reveal(); 00678 edgept = edgept->next; 00679 } 00680 while (!exact_point (edgept, pt2) && edgept != pt1); 00681 if (edgept == pt1) { 00682 /* cprintf("Hid entire outline at (%d,%d)!!\n", 00683 edgept->pos.x,edgept->pos.y); */ 00684 } 00685 edgept = pt2; 00686 do { 00687 edgept->Reveal(); 00688 edgept = edgept->next; 00689 } 00690 while (!exact_point (edgept, pt1) && edgept != pt2); 00691 if (edgept == pt2) { 00692 /* cprintf("Hid entire outline at (%d,%d)!!\n", 00693 edgept->pos.x,edgept->pos.y); */ 00694 } 00695 }