blob: 4de5b1424f645a5122f988eb158b6bbf6a844720 [file] [log] [blame]
/* -*-C-*-
********************************************************************************
*
* File: pieces.c (Formerly pieces.c)
* Description:
* Author: Mark Seaman, OCR Technology
* Created: Fri Oct 16 14:37:00 1987
* Modified: Mon May 20 12:12:35 1991 (Mark Seaman) marks@hpgrlt
* Language: C
* Package: N/A
* Status: Reusable Software Component
*
* (c) Copyright 1987, Hewlett-Packard Company.
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
** http://www.apache.org/licenses/LICENSE-2.0
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*
*********************************************************************************/
/*----------------------------------------------------------------------
I n c l u d e s
----------------------------------------------------------------------*/
#include "pieces.h"
#include "blobs.h"
#include "freelist.h"
#include "hideedge.h"
#include "matchtab.h"
#include "ndminx.h"
#include "plotseg.h"
#include "ratngs.h"
#include "wordclass.h"
#include "wordrec.h"
/*----------------------------------------------------------------------
M a c r o s
----------------------------------------------------------------------*/
/**********************************************************************
* set_bounds_entry
*
* Set the value of the entry in an array of bounds elements.
**********************************************************************/
#define set_bounds_entry(array,index,top_left,bot_right) \
((array)[index].topleft = (top_left), \
(array)[index].botright = (bot_right)) \
/**********************************************************************
* get_bounds_entry
*
* Get the value of the entry in an array of bounds elements.
**********************************************************************/
#define get_bounds_entry(array,index,top_left,bot_right) \
((top_left) = (array)[index].topleft, \
(bot_right) = (array)[index].botright) \
/*----------------------------------------------------------------------
F u n c t i o n s
----------------------------------------------------------------------*/
/**********************************************************************
* break_pieces
*
* Break up the blobs in this chain so that they are all independent.
* This operation should undo the affect of join_pieces.
**********************************************************************/
void break_pieces(TBLOB *blobs, SEAMS seams, inT16 start, inT16 end) {
TESSLINE *outline = blobs->outlines;
TBLOB *next_blob;
inT16 x;
for (x = start; x < end; x++)
reveal_seam ((SEAM *) array_value (seams, x));
next_blob = blobs->next;
while (outline && next_blob) {
if (outline->next == next_blob->outlines) {
outline->next = NULL;
outline = next_blob->outlines;
next_blob = next_blob->next;
}
else {
outline = outline->next;
}
}
}
/**********************************************************************
* join_pieces
*
* Join a group of base level pieces into a single blob that can then
* be classified.
**********************************************************************/
void join_pieces(TBLOB *piece_blobs, SEAMS seams, inT16 start, inT16 end) {
TBLOB *next_blob;
TBLOB *blob;
inT16 x;
TESSLINE *outline;
SEAM *seam;
for (x = 0, blob = piece_blobs; x < start; x++)
blob = blob->next;
next_blob = blob->next;
outline = blob->outlines;
if (!outline)
return;
while (x < end) {
seam = (SEAM *) array_value (seams, x);
if (x - seam->widthn >= start && x + seam->widthp < end)
hide_seam(seam);
while (outline->next)
outline = outline->next;
outline->next = next_blob->outlines;
next_blob = next_blob->next;
x++;
}
}
/**********************************************************************
* hide_seam
*
* Change the edge points that are referenced by this seam to make
* them hidden edges.
**********************************************************************/
void hide_seam(SEAM *seam) {
if (seam == NULL || seam->split1 == NULL)
return;
hide_edge_pair (seam->split1->point1, seam->split1->point2);
if (seam->split2 == NULL)
return;
hide_edge_pair (seam->split2->point1, seam->split2->point2);
if (seam->split3 == NULL)
return;
hide_edge_pair (seam->split3->point1, seam->split3->point2);
}
/**********************************************************************
* hide_edge_pair
*
* Change the edge points that are referenced by this seam to make
* them hidden edges.
**********************************************************************/
void hide_edge_pair(EDGEPT *pt1, EDGEPT *pt2) {
EDGEPT *edgept;
edgept = pt1;
do {
hide_edge(edgept);
edgept = edgept->next;
}
while (!exact_point (edgept, pt2) && edgept != pt1);
if (edgept == pt1) {
/* cprintf("Hid entire outline at (%d,%d)!!\n",
edgept->pos.x,edgept->pos.y); */
}
edgept = pt2;
do {
hide_edge(edgept);
edgept = edgept->next;
}
while (!exact_point (edgept, pt1) && edgept != pt2);
if (edgept == pt2) {
/* cprintf("Hid entire outline at (%d,%d)!!\n",
edgept->pos.x,edgept->pos.y); */
}
}
/**********************************************************************
* reveal_seam
*
* Change the edge points that are referenced by this seam to make
* them hidden edges.
**********************************************************************/
void reveal_seam(SEAM *seam) {
if (seam == NULL || seam->split1 == NULL)
return;
reveal_edge_pair (seam->split1->point1, seam->split1->point2);
if (seam->split2 == NULL)
return;
reveal_edge_pair (seam->split2->point1, seam->split2->point2);
if (seam->split3 == NULL)
return;
reveal_edge_pair (seam->split3->point1, seam->split3->point2);
}
/**********************************************************************
* reveal_edge_pair
*
* Change the edge points that are referenced by this seam to make
* them hidden edges.
**********************************************************************/
void reveal_edge_pair(EDGEPT *pt1, EDGEPT *pt2) {
EDGEPT *edgept;
edgept = pt1;
do {
reveal_edge(edgept);
edgept = edgept->next;
}
while (!exact_point (edgept, pt2) && edgept != pt1);
if (edgept == pt1) {
/* cprintf("Hid entire outline at (%d,%d)!!\n",
edgept->pos.x,edgept->pos.y); */
}
edgept = pt2;
do {
reveal_edge(edgept);
edgept = edgept->next;
}
while (!exact_point (edgept, pt1) && edgept != pt2);
if (edgept == pt2) {
/* cprintf("Hid entire outline at (%d,%d)!!\n",
edgept->pos.x,edgept->pos.y); */
}
}
/**********************************************************************
* bounds_of_piece
*
* Find the bounds of the piece that will be created by joining the
* requested collection of pieces together.
**********************************************************************/
void bounds_of_piece(BOUNDS_LIST bounds,
inT16 start,
inT16 end,
TPOINT *extreme_tl,
TPOINT *extreme_br) {
TPOINT topleft;
TPOINT botright;
inT16 x;
get_bounds_entry(bounds, start, *extreme_tl, *extreme_br);
for (x = start + 1; x <= end; x++) {
get_bounds_entry(bounds, x, topleft, botright);
extreme_tl->x = MIN (topleft.x, extreme_tl->x);
extreme_tl->y = MAX (topleft.y, extreme_tl->y);
extreme_br->x = MAX (botright.x, extreme_br->x);
extreme_br->y = MIN (botright.y, extreme_br->y);
}
}
/**********************************************************************
* classify_piece
*
* Create a larger piece from a collection of smaller ones. Classify
* it and return the results. Take the large piece apart to leave
* the collection of small pieces un modified.
**********************************************************************/
namespace tesseract {
BLOB_CHOICE_LIST *Wordrec::classify_piece(TBLOB *pieces,
SEAMS seams,
inT16 start,
inT16 end) {
STATE current_state;
BLOB_CHOICE_LIST *choices;
TBLOB *pblob;
TBLOB *blob;
TBLOB *nblob;
inT16 x;
SEARCH_STATE chunk_groups;
set_n_ones (&current_state, array_count (seams));
join_pieces(pieces, seams, start, end);
for (blob = pieces, pblob = NULL, x = 0; x < start; x++) {
pblob = blob;
blob = blob->next;
}
for (nblob = blob->next; x < end; x++)
nblob = nblob->next;
choices = classify_blob (pblob, blob, nblob, NULL, "pieces:", White);
break_pieces(blob, seams, start, end);
#ifndef GRAPHICS_DISABLED
if (display_segmentations > 2) {
chunk_groups = bin_to_chunks (&current_state, array_count (seams));
display_segmentation(pieces, chunk_groups);
window_wait(segm_window);
memfree(chunk_groups);
}
#endif
return (choices);
}
/**********************************************************************
* get_piece_rating
*
* Check to see if this piece has already been classified. If it has
* return that rating. Otherwise build the piece from the smaller
* pieces, classify it, store the rating for later, and take the piece
* apart again.
**********************************************************************/
BLOB_CHOICE_LIST *Wordrec::get_piece_rating(MATRIX *ratings,
TBLOB *blobs,
SEAMS seams,
inT16 start,
inT16 end) {
BLOB_CHOICE_LIST *choices = ratings->get(start, end);
if (choices == NOT_CLASSIFIED) {
choices = classify_piece(blobs,
seams,
start,
end);
ratings->put(start, end, choices);
}
return (choices);
}
} // namespace tesseract
/**********************************************************************
* record_blob_bounds
*
* Set up and initialize an array that holds the bounds of a set of
* blobs.
**********************************************************************/
BOUNDS_LIST record_blob_bounds(TBLOB *blobs) {
TBLOB *blob;
BOUNDS_LIST bounds;
TPOINT topleft;
TPOINT botright;
inT16 x = 0;
bounds = (BOUNDS_LIST) memalloc (count_blobs (blobs) * sizeof (BOUNDS));
iterate_blobs(blob, blobs) {
blob_bounding_box(blob, &topleft, &botright);
set_bounds_entry(bounds, x, topleft, botright);
x++;
}
return (bounds);
}
/**********************************************************************
* record_piece_ratings
*
* Save the choices for all the pieces that have been classified into
* a matrix that can be used to look them up later. A two dimensional
* matrix is created. The indices correspond to the starting and
* ending initial piece number.
**********************************************************************/
MATRIX *record_piece_ratings(TBLOB *blobs) {
BOUNDS_LIST bounds;
inT16 num_blobs;
inT16 x;
inT16 y;
TPOINT tp_topleft;
TPOINT tp_botright;
unsigned int topleft;
unsigned int botright;
MATRIX *ratings;
BLOB_CHOICE_LIST *choices;
bounds = record_blob_bounds (blobs);
num_blobs = count_blobs (blobs);
ratings = new MATRIX(num_blobs);
for (x = 0; x < num_blobs; x++) {
for (y = x; y < num_blobs; y++) {
bounds_of_piece(bounds, x, y, &tp_topleft, &tp_botright);
topleft = *(unsigned int *) &tp_topleft;
botright = *(unsigned int *) &tp_botright;
choices = get_match_by_bounds (topleft, botright);
if (choices != NULL) {
ratings->put(x, y, choices);
}
}
}
memfree(bounds);
return (ratings);
}