blob: 4db3d6f616c4bb5807c3f156ab3fc5900a9a396e [file] [log] [blame]
/**********************************************************************
* 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 ScrollView* 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
ScrollView* 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 != NULL)
// overlap_picture_ops(TRUE); //update window
ScrollView::Update();
#endif
}
/**********************************************************************
* complete_edge
*
* Complete the edge by cleaning it up andapproximating it.
**********************************************************************/
void complete_edge( //clean and approximate
CRACKEDGE *start //start of loop
) {
ScrollView::Color 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 == ScrollView::RED || colour == ScrollView::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.
**********************************************************************/
ScrollView::Color 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 ScrollView::YELLOW;
}
else if (length < MINEDGELENGTH) {
short_edges++;
return ScrollView::MAGENTA;
}
else {
ED_ILLEGAL_SUM.error ("check_path_legal", TESSLOG, "chainsum=%d",
chainsum);
return ScrollView::GREEN;
}
}
//colour on inside
return chainsum < 0 ? ScrollView::BLUE : ScrollView::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;
}