File indexing completed on 2024-05-12 15:55:07

0001 /***************************************************************************
0002                       kadmosocr.cpp - Kadmos cpp interface
0003                              -------------------
0004     begin                : Fri Jun 30 2000
0005 
0006     (c) 2002 re Recognition AG      Hafenstrasse 50b  CH-8280 Kreuzlingen
0007     Switzerland          Phone: +41 (0)71 6780000  Fax: +41 (0)71 6780099
0008     Website: www.reRecognition.com         E-mail: info@reRecognition.com
0009 
0010     Author: Tamas Nagy (nagy@rerecognition.com)
0011             Klaas Freitag <freitag@suse.de>
0012             Heike Stuerzenhofecker <heike@freisturz.de>
0013  ***************************************************************************/
0014 
0015 /***************************************************************************
0016  *                                                                         *
0017  *  This file may be distributed and/or modified under the terms of the    *
0018  *  GNU General Public License version 2 as published by the Free Software *
0019  *  Foundation and appearing in the file COPYING included in the           *
0020  *  packaging of this file.                                                *
0021  *
0022  *  As a special exception, permission is given to link this program       *
0023  *  with any version of the KADMOS ocr/icr engine of reRecognition GmbH,   *
0024  *  Kreuzlingen and distribute the resulting executable without            *
0025  *  including the source code for KADMOS in the source distribution.       *
0026  *
0027  *  As a special exception, permission is given to link this program       *
0028  *  with any edition of Qt, and distribute the resulting executable,       *
0029  *  without including the source code for Qt in the source distribution.   *
0030  *                                                                         *
0031  ***************************************************************************/
0032 
0033 /* Kadmos CPP object oriented interface */
0034 
0035 #include <qimage.h>
0036 #include <qpainter.h>
0037 #include <qstring.h>
0038 #include <qrect.h>
0039 #include <qstringlist.h>
0040 
0041 #include <assert.h>
0042 
0043 #include <string.h>
0044 #include <stdlib.h>
0045 #include <memory.h>
0046 #include <QDebug>
0047 
0048 #include "kadmosocr.h"
0049 #include "ocrword.h"
0050 
0051 #ifdef HAVE_KADMOS
0052 
0053 using namespace Kadmos;
0054 
0055 /* -------------------- CRep -------------------- */
0056 CRep::CRep()
0057     : QObject()
0058 {
0059     memset(&m_RepData, 0, sizeof(m_RepData));
0060     m_Error = RE_SUCCESS;
0061     m_undetectChar = QChar('_');
0062 }
0063 
0064 CRep::~CRep()
0065 {
0066 }
0067 
0068 RelGraph *CRep::getGraphKnode(int line, int offset)
0069 {
0070     Kadmos::RepResult *res = getRepResult(line);
0071     if (res) {
0072         return (&(getRepResult(line)->rel_graph[0]) + offset);
0073     } else {
0074         return 0L;
0075     }
0076 
0077 }
0078 
0079 RepResult *CRep::getRepResult(int line)
0080 {
0081     if (line < 0 || line >= m_RepData.rep_result_len) {
0082         return 0L;
0083     }
0084     return &(m_RepData.rep_result[line]);
0085 }
0086 
0087 RelResult *CRep::getRelResult(int line, RelGraph *graph, int alternative)
0088 {
0089     if (!(graph && getRepResult(line))) {
0090         return 0L;
0091     }
0092     int offset = graph->result_number[alternative];
0093     return (&(getRepResult(line)->rel_result[0]) + offset);
0094 }
0095 
0096 KADMOS_ERROR CRep::Init(const char *ClassifierFilename)
0097 {
0098     /* prepare RepData structure */
0099     m_RepData.init.rel_grid_maxlen   = GRID_MAX_LEN;
0100     m_RepData.init.rel_graph_maxlen  = GRAPH_MAX_LEN;
0101     m_RepData.init.rel_result_maxlen = CHAR_MAX_LEN;
0102     m_RepData.init.rep_memory_size   = LINE_MAX_LEN * sizeof(RepResult) +
0103                                        (long)LINE_MAX_LEN * CHAR_MAX_LEN * (sizeof(RelGraph) +
0104                                                sizeof(RelResult));
0105     m_RepData.init.rep_memory = malloc(m_RepData.init.rep_memory_size);
0106     if (!m_RepData.init.rep_memory) {
0107         ChecqCritical();
0108         return m_Error;
0109     }
0110     strcpy(m_RepData.init.version, INC_KADMOS);
0111 
0112     m_Error = rep_init(&m_RepData, (char *)ClassifierFilename);
0113     ChecqCritical();
0114     return m_Error;
0115 }
0116 
0117 void CRep::run() // KADMOS_ERROR CRep::Recognize()
0118 {
0119     kdDebug(28000) << "ooo Locked and ocr!" << endl;
0120     m_Error = rep_do(&m_RepData);
0121     ChecqCritical();
0122 }
0123 
0124 KADMOS_ERROR CRep::End()
0125 {
0126     m_Error = rep_end(&m_RepData);
0127     ChecqCritical();
0128     return m_Error;
0129 }
0130 
0131 int CRep::GetMaxLine()
0132 {
0133     return m_RepData.rep_result_len;
0134 }
0135 
0136 const char *CRep::RepTextLine(int nLine, unsigned char RejectLevel, int RejectChar, long Format)
0137 {
0138     m_Error = rep_textline(&m_RepData, nLine, m_Line,
0139                            2 * CHAR_MAX_LEN, RejectLevel, RejectChar, Format);
0140     ChecqCritical();
0141     return m_Line;
0142 }
0143 
0144 /**
0145  * This method handles the given line. It takes repRes and goes through the
0146  * kadmos result tree structures recursively.
0147  */
0148 ocrWordList CRep::getLineWords(int line)
0149 {
0150     ocrWordList repWords;
0151     bool ok = true;
0152 
0153     Kadmos::RepResult *repRes = getRepResult(line);
0154 
0155     if (! repRes) {
0156         kdDebug(28000) << "repRes-Pointer is null" << endl;
0157         ok = false;
0158     }
0159 
0160     if (ok) {
0161         int nextKnode = 0;
0162 
0163         do {
0164             QString resultWord;
0165             QRect boundingRect;
0166 
0167             int newNextKnode = nextBestWord(line, nextKnode, resultWord, boundingRect);
0168             boundingRect.moveBy(repRes->left, repRes->top);
0169 
0170             ocrWord newWord;
0171             newWord = resultWord;
0172             newWord.setKnode(nextKnode);
0173             newWord.setLine(line);
0174             newWord.setRect(boundingRect);
0175             repWords.push_back(newWord);
0176 
0177             /* set nextKnode to the next Knode */
0178             nextKnode = newNextKnode;
0179 
0180             // Alternativen:
0181             // partStrings( line, nextKnode, QString());   // fills m_parts - list with alternative words
0182             // nextKnode = newNextKnode;
0183             // kdDebug(28000) << "NextKnodeWord: " << resultWord << endl;
0184         } while (nextKnode > 0);
0185     }
0186     return repWords;
0187 }
0188 
0189 /* This fills theWord with the next best word and returns the
0190  * next knode or 0 if there is no next node
0191  */
0192 int CRep::nextBestWord(int line, int knode, QString &theWord, QRect &brect)
0193 {
0194 
0195     Kadmos::RelGraph  *relg = getGraphKnode(line, knode);
0196     // kdDebug(28000) << "GraphKnode is " << knode << endl;
0197     int nextKnode = knode;
0198 
0199     while (relg) {
0200         Kadmos::RelResult *relr = getRelResult(line, relg, 0);   // best alternative
0201         if (relr) {
0202             // kdDebug(28000) << "Leading Blanks: " << relg->leading_blanks <<
0203             //    " und Knode " << knode << endl;
0204             char c = relr->rec_char[0][0];
0205             QChar newChar = c;
0206             if (c == 0) {
0207                 kdDebug(28000) << "Undetected char found !" << endl;
0208                 newChar = m_undetectChar;
0209             }
0210 
0211             if ((nextKnode != knode) && (relg->leading_blanks > 0)) {
0212                 /* this means the word ends here. */
0213                 // kdDebug(28000) << "----" << theWord << endl;
0214                 relg = 0L; /* Leave the loop. */
0215             } else {
0216                 /* append the character */
0217                 theWord.append(newChar);
0218 
0219                 /* save the bounding rect */
0220                 // kdDebug(28000) << "LEFT: " << relr->left << " TOP: " << relr->top << endl;
0221                 QRect r(relr->left, relr->top, relr->width, relr->height);
0222 
0223                 if (brect.isNull()) {
0224                     brect = r;
0225                 } else {
0226                     brect = brect.unite(r);
0227                 }
0228 
0229                 /* next knode */
0230                 if (relg->next[0] > 0) {
0231                     nextKnode = relg->next[0];
0232                     relg = getGraphKnode(line, nextKnode);
0233                 } else {
0234                     /* end of the line */
0235                     nextKnode = 0;
0236                     relg = 0L;
0237                 }
0238             }
0239         }
0240     }
0241     return (nextKnode);
0242 }
0243 
0244 void CRep::partStrings(int line, int graphKnode, QString soFar)
0245 {
0246     /* The following knodes after a word break */
0247     Kadmos::RelGraph  *relg = getGraphKnode(line, graphKnode);
0248     // kdDebug(28000) << "GraphKnode is " << graphKnode << endl;
0249 
0250     QString theWord = "";
0251     for (int resNo = 0; resNo < SEG_ALT; resNo++) {
0252         // kdDebug(28000) << "Alternative " << resNo << " is " << relg->result_number[resNo] << endl;
0253         if (relg->result_number[resNo] == -1) {
0254             /* This means that there is no other alternative. Go out here. */
0255             break;
0256         }
0257 
0258         Kadmos::RelResult *relr = getRelResult(line, relg, resNo);
0259         theWord = QChar(relr->rec_char[0][0]);
0260 
0261         if (!soFar.isEmpty() && relg->leading_blanks) {
0262             /* this means the previous words end. */
0263             // TODO: This forgets the alternatives of _this_ first character of the new word.
0264 
0265             kdDebug(28000) << "---- " << soFar << endl;
0266             m_parts << soFar;
0267             break;
0268         } else {
0269             /* make a QString from this single char and append it. */
0270             soFar += theWord;
0271         }
0272 
0273         if (relg->next[resNo] > 0) {
0274             /* There is a follower to this knode. Combine the result list from a recursive call
0275              * to this function with the follower knode.
0276              */
0277             partStrings(line, relg->next[resNo], soFar);
0278         } else {
0279             /* There is no follower */
0280             kdDebug(28000) << "No followers - theWord is " << soFar << endl;
0281             m_parts << soFar;
0282             break;
0283         }
0284     }
0285 }
0286 
0287 void CRep::drawCharBox(QPixmap *pix, const QRect &r)
0288 {
0289     drawBox(pix, r, QColor(Qt::red));
0290 }
0291 
0292 void CRep::drawLineBox(QPixmap *pix, const QRect &r)
0293 {
0294     drawBox(pix, r, QColor(Qt::blue));
0295 }
0296 
0297 void CRep::drawBox(QPixmap *pix, const QRect &r, const QColor &color)
0298 {
0299     QPainter p;
0300     p.begin(pix);
0301 
0302     p.setPen(color);
0303     p.drawRect(r);
0304 }
0305 
0306 KADMOS_ERROR CRep::SetImage(const QString file)
0307 {
0308     ReImageHandle image_handle;
0309     image_handle = re_readimage(file.latin1(), &m_RepData.image);
0310     if (! image_handle) {
0311         kdDebug(28000) << "Can not load input file" << endl;
0312     }
0313     ChecqCritical();
0314     return RE_SUCCESS;
0315 
0316 }
0317 
0318 KADMOS_ERROR CRep::SetImage(QImage *Image)
0319 {
0320     // memcpy(&m_RepData.image, Image.bits(), Image.numBytes());
0321     if (!Image) {
0322         return RE_PARAMETERERROR;
0323     }
0324 
0325     kdDebug(28000) << "Setting image manually." << endl;
0326     m_RepData.image.data    = (void *)Image->bits();
0327     m_RepData.image.imgtype = IMGTYPE_PIXELARRAY;
0328     m_RepData.image.width   = Image->width();
0329     m_RepData.image.height  = Image->height();
0330     m_RepData.image.bitsperpixel = Image->depth();
0331     m_RepData.image.alignment = 1;
0332     m_RepData.image.fillorder = FILLORDER_MSB2LSB;
0333     // color
0334     if (Image->depth() == 1 || (Image->numColors() == 2 && Image->depth() == 8)) {
0335         m_RepData.image.color = COLOR_BINARY;
0336         kdDebug(28000) << "Setting Binary" << endl;
0337     } else if (Image->isGrayscale()) {
0338         m_RepData.image.color = COLOR_GRAY;
0339         kdDebug(28000) << "Setting GRAY" << endl;
0340 
0341     } else {
0342         m_RepData.image.color = COLOR_RGB;
0343         kdDebug(28000) << "Setting Color RGB" << endl;
0344     }
0345     // orientation
0346     m_RepData.image.orientation = ORIENTATION_TOPLEFT;
0347     m_RepData.image.photometric = PHOTOMETRIC_MINISWHITE;
0348     m_RepData.image.resunit = RESUNIT_INCH;
0349     m_RepData.image.xresolution = 200;
0350     m_RepData.image.yresolution = 200;
0351 
0352     ChecqCritical();
0353 
0354     return RE_SUCCESS;
0355 }
0356 
0357 void CRep::SetNoiseReduction(bool bNoiseReduction)
0358 {
0359     if (bNoiseReduction) {
0360         m_RepData.parm.prep |= PREP_AUTO_NOISEREDUCTION;
0361     } else {
0362         m_RepData.parm.prep &= !PREP_AUTO_NOISEREDUCTION;
0363     }
0364 }
0365 
0366 void CRep::SetScaling(bool bScaling)
0367 {
0368     if (bScaling) {
0369         m_RepData.parm.prep |= PREP_SCALING;
0370     } else {
0371         m_RepData.parm.prep &= !PREP_SCALING;
0372     }
0373 }
0374 
0375 void CRep::ChecqCritical()
0376 {
0377     if (kadmosError()) {
0378         kdDebug(28000) << "KADMOS ERROR: " << getErrorText() << endl;
0379     }
0380 }
0381 
0382 /* returns a QString containing the string describing the kadmos error */
0383 QString CRep::getErrorText() const
0384 {
0385     re_ErrorText Err;
0386     re_GetErrorText(&Err);
0387     return QString::fromLocal8Bit(Err.text);
0388 }
0389 
0390 bool CRep::kadmosError()
0391 {
0392     return m_Error != RE_SUCCESS;
0393 }
0394 
0395 #endif /* HAVE_KADMOS */
0396 
0397 // } /* End of Kadmos namespace */