|
|
|
/***************************************************************************
|
|
|
|
kadmosocr.cpp - Kadmos cpp interface
|
|
|
|
-------------------
|
|
|
|
begin : Fri Jun 30 2000
|
|
|
|
|
|
|
|
(c) 2002 re Recognition AG Hafenstrasse 50b CH-8280 Kreuzlingen
|
|
|
|
Switzerland Phone: +41 (0)71 6780000 Fax: +41 (0)71 6780099
|
|
|
|
Website: www.reRecognition.com E-mail: info@reRecognition.com
|
|
|
|
|
|
|
|
Author: Tamas Nagy (nagy@rerecognition.com)
|
|
|
|
Klaas Freitag <freitag@suse.de>
|
|
|
|
Heike Stuerzenhofecker <heike@freisturz.de>
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
* *
|
|
|
|
* This file may be distributed and/or modified under the terms of the *
|
|
|
|
* GNU General Public License version 2 as published by the Free Software *
|
|
|
|
* Foundation and appearing in the file COPYING included in the *
|
|
|
|
* packaging of this file. *
|
|
|
|
*
|
|
|
|
* As a special exception, permission is given to link this program *
|
|
|
|
* with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
|
|
|
|
* Kreuzlingen and distribute the resulting executable without *
|
|
|
|
* including the source code for KADMOS in the source distribution. *
|
|
|
|
*
|
|
|
|
* As a special exception, permission is given to link this program *
|
|
|
|
* with any edition of Qt, and distribute the resulting executable, *
|
|
|
|
* without including the source code for Qt in the source distribution. *
|
|
|
|
* *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
/* Kadmos CPP object oriented interface */
|
|
|
|
|
|
|
|
#include <tqimage.h>
|
|
|
|
#include <tqpainter.h>
|
|
|
|
#include <tqstring.h>
|
|
|
|
#include <tqrect.h>
|
|
|
|
#include <tqstringlist.h>
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <memory.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
|
|
|
|
#include "kadmosocr.h"
|
|
|
|
#include "ocrword.h"
|
|
|
|
|
|
|
|
#ifdef HAVE_KADMOS
|
|
|
|
|
|
|
|
using namespace Kadmos;
|
|
|
|
|
|
|
|
/* -------------------- CRep -------------------- */
|
|
|
|
CRep::CRep()
|
|
|
|
:TQObject()
|
|
|
|
{
|
|
|
|
memset(&m_RepData, 0, sizeof(m_RepData));
|
|
|
|
m_Error = RE_SUCCESS;
|
|
|
|
m_undetectChar = TQChar('_');
|
|
|
|
}
|
|
|
|
|
|
|
|
CRep::~CRep()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
RelGraph* CRep::getGraphKnode(int line, int offset )
|
|
|
|
{
|
|
|
|
Kadmos::RepResult *res = getRepResult(line);
|
|
|
|
if( res )
|
|
|
|
return ( &(getRepResult(line)->rel_graph[0])+offset);
|
|
|
|
else
|
|
|
|
return 0L;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RepResult* CRep::getRepResult(int line)
|
|
|
|
{
|
|
|
|
if( line<0 || line >= m_RepData.rep_result_len ) return 0L;
|
|
|
|
return &(m_RepData.rep_result[line]);
|
|
|
|
}
|
|
|
|
|
|
|
|
RelResult* CRep::getRelResult(int line, RelGraph* graph, int alternative)
|
|
|
|
{
|
|
|
|
if( ! ( graph && getRepResult(line))) return 0L;
|
|
|
|
int offset = graph->result_number[alternative];
|
|
|
|
return( &(getRepResult(line)->rel_result[0]) + offset );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
KADMOS_ERROR CRep::Init(const char* ClassifierFilename)
|
|
|
|
{
|
|
|
|
/* prepare RepData structure */
|
|
|
|
m_RepData.init.rel_grid_maxlen = GRID_MAX_LEN;
|
|
|
|
m_RepData.init.rel_graph_maxlen = GRAPH_MAX_LEN;
|
|
|
|
m_RepData.init.rel_result_maxlen = CHAR_MAX_LEN;
|
|
|
|
m_RepData.init.rep_memory_size = LINE_MAX_LEN * sizeof(RepResult) +
|
|
|
|
(long)LINE_MAX_LEN * CHAR_MAX_LEN * (sizeof(RelGraph)+
|
|
|
|
sizeof(RelResult));
|
|
|
|
m_RepData.init.rep_memory = malloc( m_RepData.init.rep_memory_size );
|
|
|
|
if (!m_RepData.init.rep_memory) {
|
|
|
|
CheckError();
|
|
|
|
return m_Error;
|
|
|
|
}
|
|
|
|
strcpy(m_RepData.init.version, INC_KADMOS);
|
|
|
|
|
|
|
|
m_Error = rep_init(&m_RepData, (char*)ClassifierFilename);
|
|
|
|
CheckError();
|
|
|
|
return m_Error;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CRep::run() // KADMOS_ERROR CRep::Recognize()
|
|
|
|
{
|
|
|
|
kdDebug(28000) << "ooo Locked and ocr!" << endl;
|
|
|
|
m_Error = rep_do(&m_RepData);
|
|
|
|
CheckError();
|
|
|
|
}
|
|
|
|
|
|
|
|
KADMOS_ERROR CRep::End()
|
|
|
|
{
|
|
|
|
m_Error = rep_end(&m_RepData);
|
|
|
|
CheckError();
|
|
|
|
return m_Error;
|
|
|
|
}
|
|
|
|
|
|
|
|
int CRep::GetMaxLine()
|
|
|
|
{
|
|
|
|
return m_RepData.rep_result_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* CRep::RepTextLine(int nLine, unsigned char RejectLevel, int RejectChar, long Format)
|
|
|
|
{
|
|
|
|
m_Error = rep_textline(&m_RepData, nLine, m_Line,
|
|
|
|
2*CHAR_MAX_LEN, RejectLevel, RejectChar, Format);
|
|
|
|
CheckError();
|
|
|
|
return m_Line;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method handles the given line. It takes repRes and goes through the
|
|
|
|
* kadmos result tree structures recursivly.
|
|
|
|
*/
|
|
|
|
ocrWordList CRep::getLineWords( int line )
|
|
|
|
{
|
|
|
|
ocrWordList repWords;
|
|
|
|
bool ok = true;
|
|
|
|
|
|
|
|
Kadmos::RepResult *repRes = getRepResult(line);
|
|
|
|
|
|
|
|
if( ! repRes )
|
|
|
|
{
|
|
|
|
kdDebug(28000) << "repRes-Pointer is null" << endl;
|
|
|
|
ok = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( ok )
|
|
|
|
{
|
|
|
|
int nextKnode=0;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
TQString resultWord;
|
|
|
|
TQRect boundingRect;
|
|
|
|
|
|
|
|
int newNextKnode = nextBestWord( line, nextKnode, resultWord, boundingRect );
|
|
|
|
boundingRect.moveBy( repRes->left, repRes->top );
|
|
|
|
|
|
|
|
ocrWord newWord;
|
|
|
|
newWord = resultWord;
|
|
|
|
newWord.setKnode(nextKnode);
|
|
|
|
newWord.setLine(line);
|
|
|
|
newWord.setRect(boundingRect);
|
|
|
|
repWords.push_back(newWord);
|
|
|
|
|
|
|
|
/* set nextKnode to the next Knode */
|
|
|
|
nextKnode = newNextKnode;
|
|
|
|
|
|
|
|
|
|
|
|
// Alternativen:
|
|
|
|
// partStrings( line, nextKnode, TQString()); // fills m_parts - list with alternative words
|
|
|
|
// nextKnode = newNextKnode;
|
|
|
|
// kdDebug(28000) << "NextKnodeWord: " << resultWord << endl;
|
|
|
|
}
|
|
|
|
while( nextKnode > 0 );
|
|
|
|
}
|
|
|
|
return repWords;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* This fills theWord with the next best word and returns the
|
|
|
|
* next knode or 0 if there is no next node
|
|
|
|
*/
|
|
|
|
int CRep::nextBestWord( int line, int knode, TQString& theWord, TQRect& brect )
|
|
|
|
{
|
|
|
|
|
|
|
|
Kadmos::RelGraph *relg = getGraphKnode( line, knode );
|
|
|
|
// kdDebug(28000) << "GraphKnode is " << knode << endl;
|
|
|
|
int nextKnode = knode;
|
|
|
|
|
|
|
|
while( relg )
|
|
|
|
{
|
|
|
|
Kadmos::RelResult *relr = getRelResult( line, relg, 0 ); // best alternative
|
|
|
|
if( relr )
|
|
|
|
{
|
|
|
|
// kdDebug(28000) << "Leading Blanks: " << relg->leading_blanks <<
|
|
|
|
// " und Knode " << knode << endl;
|
|
|
|
char c = relr->rec_char[0][0];
|
|
|
|
TQChar newChar = c;
|
|
|
|
if( c == 0 )
|
|
|
|
{
|
|
|
|
kdDebug(28000) << "Undetected char found !" << endl;
|
|
|
|
newChar = m_undetectChar;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( (nextKnode != knode) && (relg->leading_blanks > 0))
|
|
|
|
{
|
|
|
|
/* this means the word ends here. */
|
|
|
|
// kdDebug(28000) << "----" << theWord << endl;
|
|
|
|
relg = 0L; /* Leave the loop. */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* append the character */
|
|
|
|
theWord.append(newChar);
|
|
|
|
|
|
|
|
/* save the bounding rect */
|
|
|
|
// kdDebug(28000) << "LEFT: " << relr->left << " TOP: " << relr->top << endl;
|
|
|
|
TQRect r( relr->left, relr->top, relr->width, relr->height );
|
|
|
|
|
|
|
|
if( brect.isNull() )
|
|
|
|
{
|
|
|
|
brect = r;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
brect = brect.unite( r );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* next knode */
|
|
|
|
if( relg->next[0] > 0 )
|
|
|
|
{
|
|
|
|
nextKnode = relg->next[0];
|
|
|
|
relg = getGraphKnode( line, nextKnode );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* end of the line */
|
|
|
|
nextKnode = 0;
|
|
|
|
relg = 0L;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return( nextKnode );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CRep::partStrings( int line, int graphKnode, TQString soFar )
|
|
|
|
{
|
|
|
|
/* The following knodes after a word break */
|
|
|
|
Kadmos::RelGraph *relg = getGraphKnode( line, graphKnode );
|
|
|
|
// kdDebug(28000) << "GraphKnode is " << graphKnode << endl;
|
|
|
|
|
|
|
|
TQString theWord="";
|
|
|
|
for( int resNo=0; resNo < SEG_ALT; resNo++ )
|
|
|
|
{
|
|
|
|
// kdDebug(28000) << "Alternative " << resNo << " is " << relg->result_number[resNo] << endl;
|
|
|
|
if( relg->result_number[resNo] == -1 )
|
|
|
|
{
|
|
|
|
/* This means that there is no other alternative. Go out here. */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
Kadmos::RelResult *relr = getRelResult( line, relg, resNo );
|
|
|
|
theWord = TQChar(relr->rec_char[0][0]);
|
|
|
|
|
|
|
|
if ( !soFar.isEmpty() && relg->leading_blanks )
|
|
|
|
{
|
|
|
|
/* this means the previous words end. */
|
|
|
|
// TODO: This forgets the alternatives of _this_ first character of the new word.
|
|
|
|
|
|
|
|
kdDebug(28000) << "---- " << soFar << endl;
|
|
|
|
m_parts << soFar;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* make a TQString from this single char and append it. */
|
|
|
|
soFar += theWord;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( relg->next[resNo] > 0 )
|
|
|
|
{
|
|
|
|
/* There is a follower to this knode. Combine the result list from a recursive call
|
|
|
|
* to this function with the follower knode.
|
|
|
|
*/
|
|
|
|
partStrings( line, relg->next[resNo], soFar );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* There is no follower */
|
|
|
|
kdDebug(28000) << "No followers - theWord is " << soFar << endl;
|
|
|
|
m_parts<<soFar;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CRep::drawCharBox( TQPixmap *pix, const TQRect& r )
|
|
|
|
{
|
|
|
|
drawBox( pix, r, TQColor( Qt::red ));
|
|
|
|
}
|
|
|
|
|
|
|
|
void CRep::drawLineBox( TQPixmap* pix, const TQRect& r )
|
|
|
|
{
|
|
|
|
drawBox( pix, r, TQColor( Qt::blue ));
|
|
|
|
}
|
|
|
|
|
|
|
|
void CRep::drawBox( TQPixmap* pix, const TQRect& r, const TQColor& color )
|
|
|
|
{
|
|
|
|
TQPainter p;
|
|
|
|
p.begin(pix);
|
|
|
|
|
|
|
|
p.setPen( color );
|
|
|
|
p.drawRect(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
KADMOS_ERROR CRep::SetImage( const TQString file )
|
|
|
|
{
|
|
|
|
ReImageHandle image_handle;
|
|
|
|
image_handle = re_readimage(file.latin1(), &m_RepData.image);
|
|
|
|
if( ! image_handle )
|
|
|
|
{
|
|
|
|
kdDebug(28000) << "Can not load input file" << endl;
|
|
|
|
}
|
|
|
|
CheckError();
|
|
|
|
return RE_SUCCESS;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
KADMOS_ERROR CRep::SetImage(TQImage *Image)
|
|
|
|
{
|
|
|
|
// memcpy(&m_RepData.image, Image.bits(), Image.numBytes());
|
|
|
|
if( !Image ) return RE_PARAMETERERROR;
|
|
|
|
|
|
|
|
kdDebug(28000) << "Setting image manually." << endl;
|
|
|
|
m_RepData.image.data = (void*)Image->bits();
|
|
|
|
m_RepData.image.imgtype = IMGTYPE_PIXELARRAY;
|
|
|
|
m_RepData.image.width = Image->width();
|
|
|
|
m_RepData.image.height = Image->height();
|
|
|
|
m_RepData.image.bitsperpixel = Image->depth();
|
|
|
|
m_RepData.image.alignment = 1;
|
|
|
|
m_RepData.image.fillorder = FILLORDER_MSB2LSB;
|
|
|
|
// color
|
|
|
|
if( Image->depth() == 1 || (Image->numColors()==2 && Image->depth() == 8) )
|
|
|
|
{
|
|
|
|
m_RepData.image.color=COLOR_BINARY;
|
|
|
|
kdDebug(28000) << "Setting Binary" << endl;
|
|
|
|
} else if( Image->isGrayscale() ) {
|
|
|
|
m_RepData.image.color = COLOR_GRAY;
|
|
|
|
kdDebug(28000) << "Setting GRAY" << endl;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
m_RepData.image.color = COLOR_RGB;
|
|
|
|
kdDebug(28000) << "Setting Color RGB" << endl;
|
|
|
|
}
|
|
|
|
// orientation
|
|
|
|
m_RepData.image.orientation = ORIENTATION_TOPLEFT;
|
|
|
|
m_RepData.image.photometric = PHOTOMETRIC_MINISWHITE;
|
|
|
|
m_RepData.image.resunit = RESUNIT_INCH;
|
|
|
|
m_RepData.image.xresolution = 200;
|
|
|
|
m_RepData.image.yresolution = 200;
|
|
|
|
|
|
|
|
CheckError();
|
|
|
|
|
|
|
|
return RE_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CRep::SetNoiseReduction(bool bNoiseReduction)
|
|
|
|
{
|
|
|
|
if (bNoiseReduction) {
|
|
|
|
m_RepData.parm.prep |= PREP_AUTO_NOISEREDUCTION;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
m_RepData.parm.prep &= !PREP_AUTO_NOISEREDUCTION;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CRep::SetScaling(bool bScaling)
|
|
|
|
{
|
|
|
|
if (bScaling) {
|
|
|
|
m_RepData.parm.prep |= PREP_SCALING;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
m_RepData.parm.prep &= !PREP_SCALING;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CRep::CheckError()
|
|
|
|
{
|
|
|
|
if ( kadmosError() )
|
|
|
|
{
|
|
|
|
kdDebug(28000) << "KADMOS ERROR: " << getErrorText() << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* returns a TQString containing the string describing the kadmos error */
|
|
|
|
TQString CRep::getErrorText() const
|
|
|
|
{
|
|
|
|
re_ErrorText Err;
|
|
|
|
re_GetErrorText(&Err);
|
|
|
|
return TQString::fromLocal8Bit( Err.text );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CRep::kadmosError()
|
|
|
|
{
|
|
|
|
return m_Error != RE_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "kadmosocr.moc"
|
|
|
|
|
|
|
|
#endif /* HAVE_KADMOS */
|
|
|
|
|
|
|
|
|
|
|
|
// } /* End of Kadmos namespace */
|