mirror of https://github.com/NaN-tic/nanscan.git
- Fixed doxygen file.
- Added invoice recognition module. Still missing block detection.
This commit is contained in:
parent
2cbba682f0
commit
0eb944c512
|
@ -0,0 +1,153 @@
|
||||||
|
# Copyright (C) 2009 by Albert Cervera i Areny
|
||||||
|
# albert@nan-tic.com
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the
|
||||||
|
# Free Software Foundation, Inc.,
|
||||||
|
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
|
|
||||||
|
from NanScan.LevenshteinDistance import *
|
||||||
|
from NanScan.Range import *
|
||||||
|
from NanScan.TextPatterns import *
|
||||||
|
|
||||||
|
class InvoiceRecognizer:
|
||||||
|
Tags = {
|
||||||
|
'number': {
|
||||||
|
'tag': [
|
||||||
|
u'factura',
|
||||||
|
u'numero factura',
|
||||||
|
u'factura numero',
|
||||||
|
u'num. de factura',
|
||||||
|
u'factura num.'
|
||||||
|
],
|
||||||
|
'type': 'mostly-numeric'
|
||||||
|
},
|
||||||
|
'date': {
|
||||||
|
'tag': [
|
||||||
|
u'fecha',
|
||||||
|
u'fecha factura',
|
||||||
|
u'fecha emision',
|
||||||
|
u'data:',
|
||||||
|
u'data',
|
||||||
|
u'data factura'
|
||||||
|
],
|
||||||
|
'type': 'date'
|
||||||
|
# With dates we need to be able to find a date with
|
||||||
|
# the format '1 Sep. 2009'. Also we need to find the
|
||||||
|
# date without a tag. Something like:
|
||||||
|
#
|
||||||
|
# 'fallback': functionName,
|
||||||
|
#
|
||||||
|
# might be appropiate for those cases in which the
|
||||||
|
# tag can't be found.
|
||||||
|
},
|
||||||
|
'amount': {
|
||||||
|
'tag': [
|
||||||
|
u'total',
|
||||||
|
u'total factura',
|
||||||
|
u'total a pagar (euros)'
|
||||||
|
],
|
||||||
|
'type': 'numeric'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def recognize(self, recognizer):
|
||||||
|
#text = recognizer.textInRegion('text')
|
||||||
|
analyzer = recognizer.analyzers['text']
|
||||||
|
self.textLines = analyzer.textLinesWithSpaces()
|
||||||
|
result = ''
|
||||||
|
for tag in InvoiceRecognizer.Tags:
|
||||||
|
result += 'Tag: %s, Value: %s\n' % ( tag, self.findTagValue( tag ) )
|
||||||
|
return result
|
||||||
|
|
||||||
|
def formatedLine(self, line):
|
||||||
|
text = u''
|
||||||
|
for c in line:
|
||||||
|
text += c.character
|
||||||
|
return text
|
||||||
|
|
||||||
|
def findText(self, textToFind):
|
||||||
|
ranges = Range.extractAllRangesFromDocument( self.textLines, len(textToFind) )
|
||||||
|
for ran in ranges:
|
||||||
|
text = ran.text()
|
||||||
|
value = Levenshtein.levenshtein( text, textToFind )
|
||||||
|
ran.distance = value
|
||||||
|
ranges.sort( rangeDistanceComparison )
|
||||||
|
if ranges:
|
||||||
|
return ranges[0]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def findTagValue(self, tag):
|
||||||
|
ranges = []
|
||||||
|
for tagData in InvoiceRecognizer.Tags[tag]['tag']:
|
||||||
|
ran = self.findText( tagData )
|
||||||
|
if ran:
|
||||||
|
ranges.append( ran )
|
||||||
|
ranges.sort( rangeDistanceComparison )
|
||||||
|
#ran = ranges[0]
|
||||||
|
distance = ranges[0].distance
|
||||||
|
sameDistance = [x for x in ranges if x.distance == distance]
|
||||||
|
sameDistance.sort( rangeLengthComparison )
|
||||||
|
#print "SECOND 5: ", [x.text().encode('ascii','ignore') for x in sameDistance[:5]]
|
||||||
|
ran = sameDistance[-1]
|
||||||
|
|
||||||
|
print "RANGE FOR TAG %s: %s" % ( tag, ran.text().encode('ascii','ignore') )
|
||||||
|
|
||||||
|
# Extract text on the right
|
||||||
|
line = self.formatedLine( self.textLines[ ran.line ] )
|
||||||
|
rightValue = line[ran.pos+ran.length+1:].strip().split(' ')[0]
|
||||||
|
print "R: ", line[ran.pos+ran.length+1:].strip().encode('ascii','ignore')
|
||||||
|
print "rightValue: ", rightValue.encode('ascii','ignore')
|
||||||
|
print "SAME LINE: ", line.encode('ascii','ignore')
|
||||||
|
|
||||||
|
# Extract text on the bottom
|
||||||
|
if ran.line < len(self.textLines)-1:
|
||||||
|
line = self.textLines[ran.line+1]
|
||||||
|
print "NEXT LINE: ", self.formatedLine( self.textLines[ran.line+1] ).encode('ascii','ignore')
|
||||||
|
boxBottom = ran.rect()
|
||||||
|
boxBottom.moveTop( line[0].box.y() )
|
||||||
|
bottomValue = u''
|
||||||
|
for c in line:
|
||||||
|
if c.box.intersects( boxBottom ):
|
||||||
|
bottomValue += c.character
|
||||||
|
else:
|
||||||
|
bottomValue = u''
|
||||||
|
|
||||||
|
# Decide which of both values match the given tag type
|
||||||
|
type = InvoiceRecognizer.Tags[ tag ][ 'type' ]
|
||||||
|
if type == 'numeric':
|
||||||
|
if isFloat( rightValue ):
|
||||||
|
return textToFloat( rightValue )
|
||||||
|
elif isFloat( bottomValue ):
|
||||||
|
return textToFloat( bottomValue )
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
elif type == 'date':
|
||||||
|
if isDate( rightValue ):
|
||||||
|
return textToDate( rightValue )
|
||||||
|
elif isDate( bottomValue ):
|
||||||
|
return textToDate( bottomValue )
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
elif type == 'mostly-numeric':
|
||||||
|
if isMostlyNumeric( rightValue ):
|
||||||
|
return rightValue
|
||||||
|
elif isMostlyNumeric( bottomValue ):
|
||||||
|
return bottomValue
|
||||||
|
else:
|
||||||
|
return rightValue
|
||||||
|
else:
|
||||||
|
return rightValue
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Copyright (C) 2009 by Albert Cervera i Areny
|
||||||
|
# albert@nan-tic.com
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the
|
||||||
|
# Free Software Foundation, Inc.,
|
||||||
|
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ def boxComparison(x, y):
|
||||||
else:
|
else:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
## @breif This class allows using an OCR and provides several convenient functions
|
## @brief This class allows using an OCR and provides several convenient functions
|
||||||
# regarding text and image processing such as deskewing or obtaining formated text.
|
# regarding text and image processing such as deskewing or obtaining formated text.
|
||||||
class Ocr(Analyzer):
|
class Ocr(Analyzer):
|
||||||
file = ""
|
file = ""
|
||||||
|
@ -132,12 +132,12 @@ class Ocr(Analyzer):
|
||||||
|
|
||||||
## @brief Returns the text of a given region of the image.
|
## @brief Returns the text of a given region of the image.
|
||||||
# It's the same as calling formatedText().
|
# It's the same as calling formatedText().
|
||||||
def textInRegion(self, region):
|
def textInRegion(self, region=None):
|
||||||
return self.formatedText( region )
|
return self.formatedText( region )
|
||||||
|
|
||||||
## @brief Returns the bounding rectangle of the text returned by textInRegion for
|
## @brief Returns the bounding rectangle of the text returned by textInRegion for
|
||||||
# the given region.
|
# the given region.
|
||||||
def featureRectInRegion(self, region):
|
def featureRectInRegion(self, region=None):
|
||||||
lines = self.textLinesWithSpaces( region )
|
lines = self.textLinesWithSpaces( region )
|
||||||
rect = QRectF()
|
rect = QRectF()
|
||||||
for line in lines:
|
for line in lines:
|
||||||
|
@ -242,21 +242,8 @@ class Ocr(Analyzer):
|
||||||
line.sort( boxComparison )
|
line.sort( boxComparison )
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
## @brief This function is similar to textLines() but adds spaces between words.
|
## @brief This function adds spaces between words of a single line of boxes.
|
||||||
# The result is also a list of lines each line being a list of Character objects.
|
def textLineWithSpaces(self, line):
|
||||||
def textLinesWithSpaces(self, region=None):
|
|
||||||
|
|
||||||
lines = self.textLines( region )
|
|
||||||
|
|
||||||
# Now we have all lines with their characters in their positions.
|
|
||||||
# Here we write and add spaces appropiately.
|
|
||||||
# In order not to be distracted with character widths of letters
|
|
||||||
# like 'm' or 'i' (which are very wide and narrow), we average
|
|
||||||
# width of the letters on a per line basis. This shows good
|
|
||||||
# results, by now, on text with the same char size in the line,
|
|
||||||
# which is quite usual.
|
|
||||||
|
|
||||||
for line in lines:
|
|
||||||
width = 0
|
width = 0
|
||||||
count = 0
|
count = 0
|
||||||
left = None
|
left = None
|
||||||
|
@ -305,6 +292,24 @@ class Ocr(Analyzer):
|
||||||
c.box.setLeft( line[idx - 1].box.right() )
|
c.box.setLeft( line[idx - 1].box.right() )
|
||||||
c.box.setRight( line[idx].box.left() )
|
c.box.setRight( line[idx].box.left() )
|
||||||
line.insert( idx, c )
|
line.insert( idx, c )
|
||||||
|
|
||||||
|
|
||||||
|
## @brief This function is similar to textLines() but adds spaces between words.
|
||||||
|
# The result is also a list of lines each line being a list of Character objects.
|
||||||
|
def textLinesWithSpaces(self, region=None):
|
||||||
|
|
||||||
|
lines = self.textLines( region )
|
||||||
|
|
||||||
|
# Now we have all lines with their characters in their positions.
|
||||||
|
# Here we write and add spaces appropiately.
|
||||||
|
# In order not to be distracted with character widths of letters
|
||||||
|
# like 'm' or 'i' (which are very wide and narrow), we average
|
||||||
|
# width of the letters on a per line basis. This shows good
|
||||||
|
# results, by now, on text with the same char size in the line,
|
||||||
|
# which is quite usual.
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
self.textLineWithSpaces( line )
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ from Trigram import *
|
||||||
from Hamming import *
|
from Hamming import *
|
||||||
from LevenshteinDistance import *
|
from LevenshteinDistance import *
|
||||||
from Translator import *
|
from Translator import *
|
||||||
|
from Range import *
|
||||||
|
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
|
@ -70,7 +71,7 @@ class Recognizer(QObject):
|
||||||
if type in self.analyzers:
|
if type in self.analyzers:
|
||||||
return self.analyzers[type].boxes
|
return self.analyzers[type].boxes
|
||||||
else:
|
else:
|
||||||
return None
|
return []
|
||||||
|
|
||||||
def analyzersAvailable(self):
|
def analyzersAvailable(self):
|
||||||
return self.analyzers.keys()
|
return self.analyzers.keys()
|
||||||
|
@ -148,11 +149,9 @@ class Recognizer(QObject):
|
||||||
# 5 (the default) will make the template move 5 millimeter to the right,
|
# 5 (the default) will make the template move 5 millimeter to the right,
|
||||||
# 5 to the left, 5 to the top and 5 to the bottom. This means 121 positions
|
# 5 to the left, 5 to the top and 5 to the bottom. This means 121 positions
|
||||||
# per template.
|
# per template.
|
||||||
|
#
|
||||||
# Note that the image must have been scanned (using scan() or startScan())
|
# Note that the image must have been scanned (using scan() or startScan())
|
||||||
# before using this function.
|
# before using this function.
|
||||||
#
|
|
||||||
# TODO: Using offsets to find the best template is easy but highly inefficient.
|
|
||||||
# a smarter solution should be implemented.
|
|
||||||
def findMatchingTemplateByOffset( self, templates, offset = 5 ):
|
def findMatchingTemplateByOffset( self, templates, offset = 5 ):
|
||||||
max = 0
|
max = 0
|
||||||
best = {
|
best = {
|
||||||
|
@ -200,9 +199,6 @@ class Recognizer(QObject):
|
||||||
#
|
#
|
||||||
# Note that the image must have been scanned (using scan() or startScan())
|
# Note that the image must have been scanned (using scan() or startScan())
|
||||||
# before using this function.
|
# before using this function.
|
||||||
#
|
|
||||||
# TODO: Using offsets to find the best template is easy but highly inefficient.
|
|
||||||
# a smarter solution should be implemented.
|
|
||||||
def findMatchingTemplateByText( self, templates ):
|
def findMatchingTemplateByText( self, templates ):
|
||||||
max = 0
|
max = 0
|
||||||
best = {
|
best = {
|
||||||
|
@ -224,7 +220,6 @@ class Recognizer(QObject):
|
||||||
# Apply template with offset found
|
# Apply template with offset found
|
||||||
currentDocument = self.extractWithTemplate( template, offset.x(), offset.y() )
|
currentDocument = self.extractWithTemplate( template, offset.x(), offset.y() )
|
||||||
for documentBox in currentDocument.boxes:
|
for documentBox in currentDocument.boxes:
|
||||||
print "Applying..."
|
|
||||||
if documentBox.templateBox.type != 'matcher':
|
if documentBox.templateBox.type != 'matcher':
|
||||||
continue
|
continue
|
||||||
templateBox = documentBox.templateBox
|
templateBox = documentBox.templateBox
|
||||||
|
@ -373,65 +368,3 @@ class TemplateBoxRangeIterator:
|
||||||
break
|
break
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def rangeDistanceComparison(x, y):
|
|
||||||
if x.distance > y.distance:
|
|
||||||
return 1
|
|
||||||
elif x.distance < y.distance:
|
|
||||||
return -1
|
|
||||||
else:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
## @brief This class represents a group of characters in a document.
|
|
||||||
class Range:
|
|
||||||
def __init__(self):
|
|
||||||
self.line = 0
|
|
||||||
self.pos = 0
|
|
||||||
self.length = 0
|
|
||||||
self.document = None
|
|
||||||
|
|
||||||
## @brief Returns a unicode string with the text of the current range
|
|
||||||
def text(self):
|
|
||||||
line = self.document[self.line]
|
|
||||||
chars = line[self.pos:self.pos + self.length]
|
|
||||||
return u''.join( [x.character for x in chars] )
|
|
||||||
|
|
||||||
## @brief Returns the bounding rectangle of the text in the range
|
|
||||||
def rect(self):
|
|
||||||
line = self.document[self.line]
|
|
||||||
chars = line[self.pos:self.pos + self.length]
|
|
||||||
rect = QRectF()
|
|
||||||
for c in chars:
|
|
||||||
rect = rect.united( c.box )
|
|
||||||
return rect
|
|
||||||
|
|
||||||
## @brief Returns a list with all possible ranges of size length of the
|
|
||||||
# given document
|
|
||||||
@staticmethod
|
|
||||||
def extractAllRangesFromDocument(lines, length, width=0):
|
|
||||||
if length <= 0:
|
|
||||||
return []
|
|
||||||
ranges = []
|
|
||||||
for line in range(len(lines)):
|
|
||||||
if length >= len(lines[line]):
|
|
||||||
ran = Range()
|
|
||||||
ran.line = line
|
|
||||||
ran.pos = 0
|
|
||||||
ran.length = len(lines[line])
|
|
||||||
ran.document = lines
|
|
||||||
#if width:
|
|
||||||
# while ran.rect().width() > width:
|
|
||||||
# ran.length -= 1
|
|
||||||
ranges.append( ran )
|
|
||||||
continue
|
|
||||||
for pos in range(len(lines[line]) - length + 1):
|
|
||||||
ran = Range()
|
|
||||||
ran.line = line
|
|
||||||
ran.pos = pos
|
|
||||||
ran.length = length
|
|
||||||
ran.document = lines
|
|
||||||
#if width:
|
|
||||||
# while ran.rect().width() > width:
|
|
||||||
# ran.length -= 1
|
|
||||||
ranges.append( ran )
|
|
||||||
return ranges
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from PyQt4.QtGui import *
|
from PyQt4.QtGui import *
|
||||||
from scandialog import *
|
from ScanDialog import *
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ dialog = ScanDialog()
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
FileSaveThreaded.directory = 'c:\\images'
|
FileSaveThreaded.directory = 'c:\\images'
|
||||||
else:
|
else:
|
||||||
FileSaveThreaded.directory = '/tmp'
|
FileSaveThreaded.directory = '/tmp/scan'
|
||||||
|
|
||||||
dialog.exec_()
|
dialog.exec_()
|
||||||
|
|
||||||
|
|
|
@ -454,6 +454,7 @@ class MainWindow(QMainWindow):
|
||||||
self.connect( self.actionUnzoom, SIGNAL('triggered()'), self.unzoom )
|
self.connect( self.actionUnzoom, SIGNAL('triggered()'), self.unzoom )
|
||||||
self.connect( self.actionFindMatchingTemplateByOffset, SIGNAL('triggered()'), self.findMatchingTemplateByOffset )
|
self.connect( self.actionFindMatchingTemplateByOffset, SIGNAL('triggered()'), self.findMatchingTemplateByOffset )
|
||||||
self.connect( self.actionFindMatchingTemplateByText, SIGNAL('triggered()'), self.findMatchingTemplateByText )
|
self.connect( self.actionFindMatchingTemplateByText, SIGNAL('triggered()'), self.findMatchingTemplateByText )
|
||||||
|
self.connect( self.actionRecognizeInvoice, SIGNAL('triggered()'), self.recognizeInvoice )
|
||||||
self.toggleImageBoxes()
|
self.toggleImageBoxes()
|
||||||
QTimer.singleShot( 1000, self.setup )
|
QTimer.singleShot( 1000, self.setup )
|
||||||
self.updateTitle()
|
self.updateTitle()
|
||||||
|
@ -486,6 +487,12 @@ class MainWindow(QMainWindow):
|
||||||
def findMatchingTemplateByText(self):
|
def findMatchingTemplateByText(self):
|
||||||
self.findMatchingTemplate( 'text' )
|
self.findMatchingTemplate( 'text' )
|
||||||
|
|
||||||
|
def recognizeInvoice(self):
|
||||||
|
from NanScan.Generics.InvoiceRecognizer import InvoiceRecognizer
|
||||||
|
p = InvoiceRecognizer()
|
||||||
|
result = p.recognize( self.recognizer )
|
||||||
|
QMessageBox.information( self, _('Invoice Recognition'), result )
|
||||||
|
|
||||||
def findMatchingTemplate(self, type):
|
def findMatchingTemplate(self, type):
|
||||||
if type == 'offset':
|
if type == 'offset':
|
||||||
title = _('Template search by offset')
|
title = _('Template search by offset')
|
||||||
|
|
|
@ -13,14 +13,6 @@
|
||||||
<string>Planta</string>
|
<string>Planta</string>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="centralwidget" >
|
<widget class="QWidget" name="centralwidget" >
|
||||||
<property name="geometry" >
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>48</y>
|
|
||||||
<width>709</width>
|
|
||||||
<height>439</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2" >
|
<layout class="QHBoxLayout" name="horizontalLayout_2" >
|
||||||
<item>
|
<item>
|
||||||
<layout class="QVBoxLayout" >
|
<layout class="QVBoxLayout" >
|
||||||
|
@ -35,16 +27,7 @@
|
||||||
<property name="windowTitle" >
|
<property name="windowTitle" >
|
||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="dockWidgetContents" >
|
<widget class="QWidget" name="dockWidgetContents" />
|
||||||
<property name="geometry" >
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>20</y>
|
|
||||||
<width>70</width>
|
|
||||||
<height>399</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
@ -111,7 +94,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>709</width>
|
<width>709</width>
|
||||||
<height>22</height>
|
<height>25</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QMenu" name="menuFile" >
|
<widget class="QMenu" name="menuFile" >
|
||||||
|
@ -150,6 +133,7 @@
|
||||||
<addaction name="actionFindMatchingTemplateByOffset" />
|
<addaction name="actionFindMatchingTemplateByOffset" />
|
||||||
<addaction name="actionFindMatchingTemplateByText" />
|
<addaction name="actionFindMatchingTemplateByText" />
|
||||||
<addaction name="actionDeskew" />
|
<addaction name="actionDeskew" />
|
||||||
|
<addaction name="actionRecognizeInvoice" />
|
||||||
</widget>
|
</widget>
|
||||||
<addaction name="menuFile" />
|
<addaction name="menuFile" />
|
||||||
<addaction name="menuEdit" />
|
<addaction name="menuEdit" />
|
||||||
|
@ -157,14 +141,6 @@
|
||||||
<addaction name="menuView" />
|
<addaction name="menuView" />
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QToolBar" name="toolBar" >
|
<widget class="QToolBar" name="toolBar" >
|
||||||
<property name="geometry" >
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>22</y>
|
|
||||||
<width>709</width>
|
|
||||||
<height>26</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle" >
|
<property name="windowTitle" >
|
||||||
<string>toolBar</string>
|
<string>toolBar</string>
|
||||||
</property>
|
</property>
|
||||||
|
@ -297,6 +273,11 @@
|
||||||
<string>Deskew</string>
|
<string>Deskew</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionRecognizeInvoice" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Recognize Invoice</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
|
|
|
@ -4,4 +4,5 @@
|
||||||
#export PYTHONPATH=/home/albert/python/lib/python:../../bin:../../..
|
#export PYTHONPATH=/home/albert/python/lib/python:../../bin:../../..
|
||||||
# NanScan
|
# NanScan
|
||||||
export PYTHONPATH=..:/home/albert/d/koo
|
export PYTHONPATH=..:/home/albert/d/koo
|
||||||
|
export LD_LIBRARY_PATH=/usr/lib
|
||||||
./planta.py $1
|
./planta.py $1
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
# Project related configuration options
|
# Project related configuration options
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
DOXYFILE_ENCODING = UTF-8
|
DOXYFILE_ENCODING = UTF-8
|
||||||
PROJECT_NAME = NaNScaN
|
PROJECT_NAME = NanScan
|
||||||
PROJECT_NUMBER = 1.0
|
PROJECT_NUMBER = 1.0
|
||||||
OUTPUT_DIRECTORY = .
|
OUTPUT_DIRECTORY = .
|
||||||
CREATE_SUBDIRS = NO
|
CREATE_SUBDIRS = NO
|
||||||
|
@ -87,7 +87,7 @@ WARN_LOGFILE =
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# configuration options related to the input files
|
# configuration options related to the input files
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
INPUT = ../../NaNScaN
|
INPUT = ../../NanScan
|
||||||
INPUT_ENCODING = UTF-8
|
INPUT_ENCODING = UTF-8
|
||||||
FILE_PATTERNS = *.c \
|
FILE_PATTERNS = *.c \
|
||||||
*.cc \
|
*.cc \
|
||||||
|
|
Loading…
Reference in New Issue