/********************************************************************** * File: edgloop.c (Formerly edgeloop.c) * Description: Functions to clean up an outline before approximation. * Author: Ray Smith * Created: Tue Mar 26 16:56:25 GMT 1991 * * (C) Copyright 1991, Hewlett-Packard Ltd. ** 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. * **********************************************************************/ #include "mfcpch.h" #include "scanedg.h" #include "drawedg.h" #include "edgloop.h" #define MINEDGELENGTH 8 //min decent length #define EXTERN EXTERN double_VAR (edges_threshold_greyfraction, 0.07, "Min edge diff for grad vector"); EXTERN BOOL_VAR (edges_show_paths, FALSE, "Draw raw outlines"); EXTERN BOOL_VAR (edges_show_needles, FALSE, "Draw edge needles"); EXTERN INT_VAR (edges_maxedgelength, 16000, "Max steps in any outline"); #ifndef GRAPHICS_DISABLED static WINDOW edge_win; //window #endif static C_OUTLINE_IT *outline_it; //iterator static int short_edges; //no of short ones static int long_edges; //no of long ones /********************************************************************** * get_outlines * * Run the edge detector over the block and return a list of outlines. **********************************************************************/ DLLSYM void get_outlines( //edge detect #ifndef GRAPHICS_DISABLED WINDOW window, //window for output #endif IMAGE *image, //image to scan IMAGE *t_image, //thresholded image ICOORD page_tr, //corner of page PDBLK *block, //block to scan C_OUTLINE_IT *out_it //output iterator ) { #ifndef GRAPHICS_DISABLED edge_win = window; //set statics #endif outline_it = out_it; block_edges(t_image, block, page_tr); out_it->move_to_first (); #ifndef GRAPHICS_DISABLED if (window != NO_WINDOW) overlap_picture_ops(TRUE); //update window #endif } /********************************************************************** * complete_edge * * Complete the edge by cleaning it up andapproximating it. **********************************************************************/ void complete_edge( //clean and approximate CRACKEDGE *start //start of loop ) { COLOUR colour; //colour to draw in INT16 looplength; //steps in loop ICOORD botleft; //bounding box ICOORD topright; C_OUTLINE *outline; //new outline //check length etc. colour = check_path_legal (start); #ifndef GRAPHICS_DISABLED if (edges_show_paths) { //in red draw_raw_edge(edge_win, start, colour); } #endif if (colour == RED || colour == BLUE) { looplength = loop_bounding_box (start, botleft, topright); outline = new C_OUTLINE (start, botleft, topright, looplength); //add to list outline_it->add_after_then_move (outline); } } /********************************************************************** * check_path_legal * * Check that the outline is legal for length and for chaincode sum. * The return value is RED for a normal black-inside outline, * BLUE for a white-inside outline, MAGENTA if it is too short, * YELLOW if it is too long, and GREEN if it is illegal. * These colours are used to draw the raw outline. **********************************************************************/ COLOUR check_path_legal( //certify outline CRACKEDGE *start //start of loop ) { int lastchain; //last chain code int chaindiff; //chain code diff INT32 length; //length of loop INT32 chainsum; //sum of chain diffs CRACKEDGE *edgept; //current point const ERRCODE ED_ILLEGAL_SUM = "Illegal sum of chain codes"; length = 0; chainsum = 0; //sum of chain codes edgept = start; lastchain = edgept->prev->stepdir; //previous chain code do { length++; if (edgept->stepdir != lastchain) { //chain code difference chaindiff = edgept->stepdir - lastchain; if (chaindiff > 2) chaindiff -= 4; else if (chaindiff < -2) chaindiff += 4; chainsum += chaindiff; //sum differences lastchain = edgept->stepdir; } edgept = edgept->next; } while (edgept != start && length < edges_maxedgelength); if (chainsum != 4 && chainsum != -4 || edgept != start || length < MINEDGELENGTH) { if (edgept != start) { long_edges++; return YELLOW; } else if (length < MINEDGELENGTH) { short_edges++; return MAGENTA; } else { ED_ILLEGAL_SUM.error ("check_path_legal", LOG, "chainsum=%d", chainsum); return GREEN; } } //colour on inside return chainsum < 0 ? BLUE : RED; } /********************************************************************** * loop_bounding_box * * Find the bounding box of the edge loop. **********************************************************************/ INT16 loop_bounding_box( //get bounding box CRACKEDGE *&start, //edge loop ICOORD &botleft, //bounding box ICOORD &topright) { INT16 length; //length of loop INT16 leftmost; //on top row CRACKEDGE *edgept; //current point CRACKEDGE *realstart; //topleft start edgept = start; realstart = start; botleft = topright = ICOORD (edgept->pos.x (), edgept->pos.y ()); leftmost = edgept->pos.x (); length = 0; //coutn length do { edgept = edgept->next; if (edgept->pos.x () < botleft.x ()) //get bounding box botleft.set_x (edgept->pos.x ()); else if (edgept->pos.x () > topright.x ()) topright.set_x (edgept->pos.x ()); if (edgept->pos.y () < botleft.y ()) //get bounding box botleft.set_y (edgept->pos.y ()); else if (edgept->pos.y () > topright.y ()) { realstart = edgept; leftmost = edgept->pos.x (); topright.set_y (edgept->pos.y ()); } else if (edgept->pos.y () == topright.y () && edgept->pos.x () < leftmost) { //leftmost on line leftmost = edgept->pos.x (); realstart = edgept; } length++; //count elements } while (edgept != start); start = realstart; //shift it to topleft return length; }