Example #1
0
	def analyzeDocumentWithTemplate(self, cr, uid, documentId, templateId, context):

		# Whether templateId is valid or not
		# Remove previous properties
		ids = self.pool.get('nan.document.property').search( cr, uid, [('document_id','=',documentId)], context=context )
		self.pool.get('nan.document.property').unlink( cr, uid, ids, context )

		if templateId:
			template = self.pool.get('nan.template').getTemplateFromId( cr, uid, templateId, context )  

			documents = self.read(cr, uid, [documentId], context=context)
			if not documents:
				return 
			document = documents[0]

			fp, image = tempfile.mkstemp()
			fp = os.fdopen( fp, 'wb+' )
			try:
				fp.write( base64.decodestring( document['datas'] ) )
			finally:
				fp.close()

			recognizer = Recognizer()
			recognizer.recognize( QImage( image ) )
			doc = recognizer.extractWithTemplate( image, template )

			for box in doc.boxes:
				obj.create(cr, uid, {
					'name': box.templateBox.name, 
					'value': box.text, 
					'document_id': document['id'],
					'template_box_id': box.templateBox.id
				}, context)
		self.executeAttachs( cr, uid, [documentId], context )
		self.executeActions( cr, uid, [documentId], True, context )
Example #2
0
    def scanDocumentWithTemplate(self, cr, uid, documentId, templateId):

        # Whether templateId is valid or not
        # Remove previous properties
        obj = self.pool.get('nan.document.property')
        ids = obj.search(cr, uid, [('document', '=', documentId)])
        obj.unlink(cr, uid, ids)

        if templateId:
            # Initialize Ocr System (Gamera)
            initOcrSystem()

            template = self.pool.get('nan.template').getTemplateFromId(
                cr, uid, templateId)

            documents = self.read(cr, uid, [documentId])
            if not documents:
                return
            document = documents[0]

            fp, image = tempfile.mkstemp()
            fp = os.fdopen(fp, 'wb+')
            fp.write(base64.decodestring(document['datas']))
            fp.close()

            recognizer = Recognizer()
            recognizer.recognize(QImage(image))
            doc = recognizer.extractWithTemplate(image, template)

            for box in doc.boxes:
                obj.create(
                    cr, uid, {
                        'name': box.templateBox.name,
                        'value': box.text,
                        'document': document['id'],
                        'template_box': box.templateBox.id
                    })
        self.executeAttachs(cr, uid, [documentId])
        self.executeActions(cr, uid, [documentId], True)
        cr.commit()
Example #3
0
    def scan_document(self, cr, uid, imageIds, notify=False):
        print "Scan_documentcalled"
        # Load templates into 'templates' list
        templates = self.pool.get('nan.template').getAllTemplates(cr, uid)

        # Initialize Ocr System (Gamera)
        initOcrSystem()
        recognizer = Recognizer()

        # Iterate over all images and try to find the most similar template
        for document in self.browse(cr, uid, imageIds):
            if document.state not in ('pending', 'scanning'):
                continue
            fp, image = tempfile.mkstemp()
            fp = os.fdopen(fp, 'wb+')
            fp.write(base64.decodestring(document.datas))
            fp.close()
            recognizer.recognize(QImage(image))

            result = recognizer.findMatchingTemplateByOffset(templates)
            template = result['template']
            doc = result['document']
            if not template:
                print "No template found for document %s." % document.name
            else:
                print "The best template found for document %s is %s." % (
                    document.name, template.name)

            if template:
                template_id = template.id
            else:
                template_id = False
            self.write(cr, uid, [document.id], {
                'template': template_id,
                'state': 'scanned'
            })
            if doc:
                obj = self.pool.get('nan.document.property')
                for box in doc.boxes:
                    obj.create(
                        cr, uid, {
                            'name': box.templateBox.name,
                            'value': box.text,
                            'document': document.id,
                            'template_box': box.templateBox.id
                        })

            if notify:
                self.pool.get('res.request').create(
                    cr, uid, {
                        'act_from': uid,
                        'act_to': uid,
                        'name': 'Finished scanning document',
                        'body':
                        'The auto_attach system has finished scanning the document you requested. A reference to the document can be found in field Document Ref 1.',
                        'ref_doc1': 'nan.document,%d' % document.id,
                    })

        self.executeAttachs(cr, uid, imageIds)
        self.executeActions(cr, uid, imageIds, True)

        cr.commit()
Example #4
0
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        loadUi('mainwindow.ui', self)
        self.scene = DocumentScene()
        self.uiView.setScene(self.scene)
        self.uiView.setRenderHints(QPainter.Antialiasing
                                   | QPainter.TextAntialiasing
                                   | QPainter.SmoothPixmapTransform)
        self.uiView.setCacheMode(QGraphicsView.CacheBackground)

        self._template = Template(self.Unnamed)
        self.scene.setTemplate(self._template)

        self.uiTool = ToolWidget(self.uiToolDock)

        self.undoGroup = QUndoGroup(self)
        stack = QUndoStack(self.undoGroup)
        self.undoGroup.setActiveStack(stack)

        # Let default Qt Undo and Redo Actions handle the Undo/Redo actions
        # And put them at the very beggining of the Edit menu
        undoAction = self.undoGroup.createUndoAction(self.menuEdit)
        undoAction.setShortcut("Ctrl+Z")
        redoAction = self.undoGroup.createRedoAction(self.menuEdit)
        redoAction.setShortcut("Ctrl+Shift+Z")
        if self.menuEdit.actions():
            firstAction = self.menuEdit.actions()[0]
        else:
            firstAction = None
        self.menuEdit.insertAction(firstAction, undoAction)
        self.menuEdit.insertAction(firstAction, redoAction)

        self.connect(self.scene, SIGNAL('newTemplateBox(QRectF)'),
                     self.newTemplateBox)
        self.connect(
            self.scene,
            SIGNAL('currentTemplateBoxChanged(PyQt_PyObject,PyQt_PyObject)'),
            self.currentTemplateBoxChanged)
        self.connect(self.scene, SIGNAL('mouseMoved'), self.sceneMouseMoved)
        self.connect(self.actionExit, SIGNAL('triggered()'), self.close)
        self.connect(self.actionOpenImage, SIGNAL('triggered()'),
                     self.openImage)
        self.connect(self.actionOpenTemplate, SIGNAL('triggered()'),
                     self.openTemplate)
        self.connect(self.actionToggleImageBoxes, SIGNAL('triggered()'),
                     self.toggleImageBoxes)
        self.connect(self.actionToggleTemplateBoxes, SIGNAL('triggered()'),
                     self.toggleTemplateBoxes)
        self.connect(self.actionToggleFeatureBoxes, SIGNAL('triggered()'),
                     self.toggleFeatureBoxes)
        self.connect(self.actionToggleBinarized, SIGNAL('triggered()'),
                     self.toggleBinarized)
        self.connect(self.actionLogin, SIGNAL('triggered()'), self.login)
        self.connect(self.actionSaveTemplate, SIGNAL('triggered()'),
                     self.saveTemplate)
        self.connect(self.actionSaveTemplateAs, SIGNAL('triggered()'),
                     self.saveTemplateAs)
        self.connect(self.actionNewTemplate, SIGNAL('triggered()'),
                     self.newTemplate)
        self.connect(self.actionDelete, SIGNAL('triggered()'),
                     self.removeTemplateBox)
        self.connect(self.actionZoom, SIGNAL('triggered()'), self.zoom)
        self.connect(self.actionUnzoom, SIGNAL('triggered()'), self.unzoom)
        self.connect(self.actionFindMatchingTemplateByOffset,
                     SIGNAL('triggered()'), self.findMatchingTemplateByOffset)
        self.connect(self.actionFindMatchingTemplateByText,
                     SIGNAL('triggered()'), self.findMatchingTemplateByText)
        self.connect(self.actionRecognizeInvoice, SIGNAL('triggered()'),
                     self.recognizeInvoice)
        self.toggleImageBoxes()
        QTimer.singleShot(1000, self.setup)
        self.updateTitle()
        self.updateActions()

        # Login defaults
        LoginDialog.defaultHost = 'localhost'
        LoginDialog.defaultPort = 8070
        LoginDialog.defaultProtocol = 'socket://'
        LoginDialog.defaultUserName = '******'

        self.recognizer = Recognizer()
        self.connect(self.recognizer, SIGNAL('finished()'), self.recognized)
Example #5
0
class MainWindow(QMainWindow):
    Unnamed = _('unnamed')

    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        loadUi('mainwindow.ui', self)
        self.scene = DocumentScene()
        self.uiView.setScene(self.scene)
        self.uiView.setRenderHints(QPainter.Antialiasing
                                   | QPainter.TextAntialiasing
                                   | QPainter.SmoothPixmapTransform)
        self.uiView.setCacheMode(QGraphicsView.CacheBackground)

        self._template = Template(self.Unnamed)
        self.scene.setTemplate(self._template)

        self.uiTool = ToolWidget(self.uiToolDock)

        self.undoGroup = QUndoGroup(self)
        stack = QUndoStack(self.undoGroup)
        self.undoGroup.setActiveStack(stack)

        # Let default Qt Undo and Redo Actions handle the Undo/Redo actions
        # And put them at the very beggining of the Edit menu
        undoAction = self.undoGroup.createUndoAction(self.menuEdit)
        undoAction.setShortcut("Ctrl+Z")
        redoAction = self.undoGroup.createRedoAction(self.menuEdit)
        redoAction.setShortcut("Ctrl+Shift+Z")
        if self.menuEdit.actions():
            firstAction = self.menuEdit.actions()[0]
        else:
            firstAction = None
        self.menuEdit.insertAction(firstAction, undoAction)
        self.menuEdit.insertAction(firstAction, redoAction)

        self.connect(self.scene, SIGNAL('newTemplateBox(QRectF)'),
                     self.newTemplateBox)
        self.connect(
            self.scene,
            SIGNAL('currentTemplateBoxChanged(PyQt_PyObject,PyQt_PyObject)'),
            self.currentTemplateBoxChanged)
        self.connect(self.scene, SIGNAL('mouseMoved'), self.sceneMouseMoved)
        self.connect(self.actionExit, SIGNAL('triggered()'), self.close)
        self.connect(self.actionOpenImage, SIGNAL('triggered()'),
                     self.openImage)
        self.connect(self.actionOpenTemplate, SIGNAL('triggered()'),
                     self.openTemplate)
        self.connect(self.actionToggleImageBoxes, SIGNAL('triggered()'),
                     self.toggleImageBoxes)
        self.connect(self.actionToggleTemplateBoxes, SIGNAL('triggered()'),
                     self.toggleTemplateBoxes)
        self.connect(self.actionToggleFeatureBoxes, SIGNAL('triggered()'),
                     self.toggleFeatureBoxes)
        self.connect(self.actionToggleBinarized, SIGNAL('triggered()'),
                     self.toggleBinarized)
        self.connect(self.actionLogin, SIGNAL('triggered()'), self.login)
        self.connect(self.actionSaveTemplate, SIGNAL('triggered()'),
                     self.saveTemplate)
        self.connect(self.actionSaveTemplateAs, SIGNAL('triggered()'),
                     self.saveTemplateAs)
        self.connect(self.actionNewTemplate, SIGNAL('triggered()'),
                     self.newTemplate)
        self.connect(self.actionDelete, SIGNAL('triggered()'),
                     self.removeTemplateBox)
        self.connect(self.actionZoom, SIGNAL('triggered()'), self.zoom)
        self.connect(self.actionUnzoom, SIGNAL('triggered()'), self.unzoom)
        self.connect(self.actionFindMatchingTemplateByOffset,
                     SIGNAL('triggered()'), self.findMatchingTemplateByOffset)
        self.connect(self.actionFindMatchingTemplateByText,
                     SIGNAL('triggered()'), self.findMatchingTemplateByText)
        self.connect(self.actionRecognizeInvoice, SIGNAL('triggered()'),
                     self.recognizeInvoice)
        self.toggleImageBoxes()
        QTimer.singleShot(1000, self.setup)
        self.updateTitle()
        self.updateActions()

        # Login defaults
        LoginDialog.defaultHost = 'localhost'
        LoginDialog.defaultPort = 8070
        LoginDialog.defaultProtocol = 'socket://'
        LoginDialog.defaultUserName = '******'

        self.recognizer = Recognizer()
        self.connect(self.recognizer, SIGNAL('finished()'), self.recognized)

    def setup(self):
        #initOcrSystem()
        #self.scene.setDocument( 'c-0.tif' )

        self.connect(self.uiTool, SIGNAL('recognizerChanged(QString)'),
                     self.recognizerChanged)
        self.uiTool.show()
        self.uiToolDock.setWidget(self.uiTool)

        #Rpc.session.login( 'http://*****:*****@127.0.0.1:8069', 'g1' )
    def sceneMouseMoved(self, pos):
        self.updatePosition(pos)

    def findMatchingTemplateByOffset(self):
        self.findMatchingTemplate('offset')

    def findMatchingTemplateByText(self):
        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):
        if type == 'offset':
            title = _('Template search by offset')
        else:
            title = _('Template search by text')

        if not self.recognizer.image:
            QMessageBox.information(
                self, title,
                _('No image opened. Please open an image to find a matching template.'
                  ))
            return

        if not Rpc.session.logged():
            if not self.login():
                return
        templates = TemplateStorageManager.loadAll()
        time = QTime()
        time.start()
        if type == 'offset':
            result = self.recognizer.findMatchingTemplateByOffset(templates)
        else:
            result = self.recognizer.findMatchingTemplateByText(templates)
        elapsed = time.elapsed()
        if not result['template']:
            QMessageBox.information(
                self, title,
                _('No template found for the current image. Took %d milliseconds'
                  ) % elapsed)
            return
        self._template = result['template']
        self.scene.setTemplate(self._template)
        self.updateTitle()
        QMessageBox.information(
            self, title,
            _('Template found with offset (%.2f, %.2f) in %d milliseconds') %
            (result['xOffset'], result['yOffset'], elapsed))

    def recognizerChanged(self, recognizer):
        rect = self.uiTool.box.rect
        self.uiTool.setText(
            self.scene.recognizer.textInRegion(rect, unicode(recognizer)))

    def newTemplateBox(self, rect):
        # Creating and adding the box to the template
        # will automatically create the Rect in the Scene
        box = TemplateBox()
        box.rect = rect
        box.text = self.scene.recognizer.textInRegion(rect, 'text')
        box.featureRect = self.scene.recognizer.featureRectInRegion(
            rect, 'text')
        add = AddTemplateBoxUndoCommand(self._template, box)
        self.undoGroup.activeStack().push(add)

    #def setCurrentTemplateBox(self, box):
    #if self.uiTool.box:
    #self.uiTool.store()
    #self.uiTool.box = box
    def currentTemplateBoxChanged(self, current, previous):
        if self.uiTool.box:
            self.uiTool.store()
        self.uiTool.box = current
        self.actionDelete.setEnabled(bool(current))

    def openImage(self):
        self.fileName = QFileDialog.getOpenFileName(self)
        if self.fileName.isNull():
            return

        QApplication.setOverrideCursor(Qt.BusyCursor)
        self.recognizer.startRecognition(QImage(self.fileName))

    def recognized(self):
        self.scene.setDocument(self.recognizer)
        QApplication.restoreOverrideCursor()

    def toggleImageBoxes(self):
        self.scene.setImageBoxesVisible(
            self.actionToggleImageBoxes.isChecked())

    def toggleTemplateBoxes(self):
        self.scene.setTemplateBoxesVisible(
            self.actionToggleTemplateBoxes.isChecked())

    def toggleFeatureBoxes(self):
        self.scene.setFeatureBoxesVisible(
            self.actionToggleFeatureBoxes.isChecked())

    def toggleBinarized(self):
        self.scene.setBinarizedVisible(self.actionToggleBinarized.isChecked())

    def removeTemplateBox(self):
        if not self.uiTool.box:
            return
        delete = DeleteUndoCommand(self._template, self.uiTool.box)
        self.undoGroup.activeStack().push(delete)

    def zoom(self):
        self.uiView.scale(1.2, 1.2)

    def unzoom(self):
        self.uiView.scale(0.8, 0.8)

    def login(self):
        dialog = LoginDialog(self)
        if dialog.exec_() == QDialog.Rejected:
            return False
        if Rpc.session.login(dialog.url, dialog.databaseName) > 0:
            self.updateTitle()
            return True
        else:
            self.updateTitle()
            return False

    def newTemplate(self):
        answer = QMessageBox.question(
            self, _('New Template'),
            _('Do you want to save changes to the current template?'),
            QMessageBox.Save | QMessageBox.No | QMessageBox.Cancel)
        if answer == QMessageBox.Cancel:
            return
        elif answer == QMessageBox.Save:
            if not self.saveTemplate():
                return
        self._template = Template(self.Unnamed)
        self.scene.setTemplate(self._template)
        self.updateTitle()

    def saveTemplate(self):
        self.uiTool.store()
        if not Rpc.session.logged():
            if not self.login():
                return False

        if not self._template.id:
            (name, ok) = QInputDialog.getText(self, _('Save template'),
                                              _('Template name:'))
            if not ok:
                return False
            self._template.name = unicode(name)

        if self._template.id:
            Rpc.session.call('/object', 'execute', 'nan.template', 'write',
                             [self._template.id],
                             {'name': self._template.name})
            ids = Rpc.session.call('/object', 'execute', 'nan.template.box',
                                   'search',
                                   [('template', '=', self._template.id)])
            Rpc.session.call('/object', 'execute', 'nan.template.box',
                             'unlink', ids)
        else:
            self._template.id = Rpc.session.call('/object', 'execute',
                                                 'nan.template', 'create',
                                                 {'name': self._template.name})
        for x in self._template.boxes:
            values = {
                'x': x.rect.x(),
                'y': x.rect.y(),
                'width': x.rect.width(),
                'height': x.rect.height(),
                'feature_x': x.featureRect.x(),
                'feature_y': x.featureRect.y(),
                'feature_width': x.featureRect.width(),
                'feature_height': x.featureRect.height(),
                'template': self._template.id,
                'name': x.name,
                'text': x.text,
                'recognizer': x.recognizer,
                'type': x.type,
                'filter': x.filter
            }
            Rpc.session.call('/object', 'execute', 'nan.template.box',
                             'create', values)
        self.updateTitle()
        return True

    def saveTemplateAs(self):
        id = self._template.id
        self._template.id = 0
        if not self.saveTemplate():
            self._template.id = id
        self.updateTitle()

    def openTemplate(self):
        if not Rpc.session.logged():
            if not self.login():
                return

        dialog = OpenTemplateDialog(self)
        if dialog.exec_() == QDialog.Rejected:
            return
        model = dialog.group[dialog.id]
        self._template = Template(model.value('name'))
        self._template.id = model.id

        fields = Rpc.session.execute('/object', 'execute', 'nan.template.box',
                                     'fields_get')
        model.value('boxes').addFields(fields)
        for x in model.value('boxes'):
            box = TemplateBox()
            box.rect = QRectF(x.value('x'), x.value('y'), x.value('width'),
                              x.value('height'))
            box.featureRect = QRectF(x.value('feature_x'),
                                     x.value('feature_y'),
                                     x.value('feature_width'),
                                     x.value('feature_height'))
            box.name = x.value('name')
            box.text = x.value('text')
            box.recognizer = x.value('recognizer')
            box.type = x.value('type')
            box.filter = x.value('filter')
            self._template.addBox(box)

        self.scene.setTemplate(self._template)
        self.updateTitle()

    def updateTitle(self):
        self.setWindowTitle("Planta - [%s]" % self._template.name)

        if Rpc.session.logged():
            server = '%s [%s]' % (Rpc.session.url, Rpc.session.databaseName)
        else:
            shortcut = unicode(self.actionLogin.shortcut().toString())
            if shortcut:
                server = _('Press %s to login') % shortcut
            else:
                server = 'not logged in'
        self.uiServer.setText(server)

    def updatePosition(self, pos):
        pos = self.uiView.mapToScene(self.uiView.mapFromGlobal(QCursor.pos()))
        pos = self.scene.mapPointToRecognizer(pos)
        position = _('(%.2f, %.2f)') % (pos.x(), pos.y())
        self.uiPosition.setText(position)

    def updateActions(self):
        # Allow deleting if there's a TemplateBox selected
        self.actionDelete.setEnabled(bool(self.uiTool.box))
Example #6
0
	def analyze_document(self, cr, uid, imageIds, context=None):
		# Load templates into 'templates' list
		templates = self.pool.get('nan.template').getAllTemplates( cr, uid, context )

		templatesWithAnalysis = [x for x in templates if x.analysisFunction]
		templatesWithoutAnalysis = [x for x in templates if not x.analysisFunction]

		# Search what recognizers are used so we do not execute unnecessary processes.
		recognizers = set()
		for template in templates:
			for box in template.boxes:
				recognizers.add( box.recognizer )
		recognizers = list(recognizers)

		recognizer = Recognizer()

		# Iterate over all images and try to find the most similar template
		for document in self.browse(cr, uid, imageIds, context):
			if document.state not in ('pending','analyzing'):
				continue
			if not document.datas:
				continue
			fp, image = tempfile.mkstemp()
			fp = os.fdopen( fp, 'wb+' )
			try:
				fp.write( base64.decodestring(document.datas) )
			finally:
				fp.close()
			recognizer.recognize( QImage( image ), recognizers )
			
			template = False
			doc = False
			for template in templatesWithAnalysis:
				function = re.sub( ' *', '', template.analysisFunction )
				if function.endswith('()'):
					function = function[:-2]
				doc = eval( 'self.%s(cr, uid, document, template, recognizer, context)' % function )
				if doc:
					break

			if not doc:
				result = recognizer.findMatchingTemplateByOffset( templatesWithoutAnalysis )
				template = result['template']
				doc = result['document']

			if not template:
				print("No template found for document %s." % document.name)
			else:
				print("The best template found for document %s is %s." % (document.name, template.name))

			if template:
				template_id = template.id
			else:
				template_id = False
			self.write(cr, uid, [document.id], {
				'template_id': template_id, 
				'state': 'analyzed'
			}, context=context)
			if doc:
				for box in doc.boxes:
					self.pool.get('nan.document.property').create(cr, uid, { 
						'name': box.name, 
						'value': box.text, 
						'document_id': document.id,
						'template_box_id': box.templateBox and box.templateBox.id or False
					}, context)

			if document.state == 'analyzing':
				self.pool.get('res.request').create( cr, uid, {
					'act_from': uid,
					'act_to': uid,
					'name': 'Finished analyzing document',
					'body': 'The auto_attach system has finished analyzing the document you requested. A reference to the document can be found in field Document Ref 1.',
					'ref_doc1': 'nan.document,%d' % document.id,
				}, context)

		self.executeAttachs( cr, uid, imageIds, context )
		self.executeActions( cr, uid, imageIds, True, context )
Example #7
0
	def __init__(self, parent=None):
		QMainWindow.__init__(self, parent)
		loadUi( 'mainwindow.ui', self )
		self.scene = DocumentScene()
		self.uiView.setScene( self.scene )
		self.uiView.setRenderHints( QPainter.Antialiasing | QPainter.TextAntialiasing | QPainter.SmoothPixmapTransform )
		self.uiView.setCacheMode( QGraphicsView.CacheBackground )

		self._template = Template( self.Unnamed )
		self.scene.setTemplate(self._template)

		self.uiTool = ToolWidget( self.uiToolDock )

		self.undoGroup = QUndoGroup( self )
		stack = QUndoStack( self.undoGroup )
		self.undoGroup.setActiveStack( stack )

		# Let default Qt Undo and Redo Actions handle the Undo/Redo actions
		# And put them at the very beggining of the Edit menu
		undoAction = self.undoGroup.createUndoAction( self.menuEdit )
		undoAction.setShortcut( "Ctrl+Z" )
		redoAction = self.undoGroup.createRedoAction( self.menuEdit )
		redoAction.setShortcut( "Ctrl+Shift+Z" )
		if self.menuEdit.actions():
			firstAction = self.menuEdit.actions()[0]
		else:
			firstAction = None
		self.menuEdit.insertAction( firstAction, undoAction )
		self.menuEdit.insertAction( firstAction, redoAction )

		self.connect( self.scene, SIGNAL('newTemplateBox(QRectF)'), self.newTemplateBox )
		self.connect( self.scene, SIGNAL('currentTemplateBoxChanged(PyQt_PyObject,PyQt_PyObject)'), self.currentTemplateBoxChanged)
		self.connect( self.scene, SIGNAL('mouseMoved'), self.sceneMouseMoved )
		self.connect( self.actionExit, SIGNAL('triggered()'), self.close )
		self.connect( self.actionOpenImage, SIGNAL('triggered()'), self.openImage )
		self.connect( self.actionOpenTemplate, SIGNAL('triggered()'), self.openTemplate )
		self.connect( self.actionToggleImageBoxes, SIGNAL('triggered()'), self.toggleImageBoxes )
		self.connect( self.actionToggleTemplateBoxes, SIGNAL('triggered()'), self.toggleTemplateBoxes )
		self.connect( self.actionToggleFeatureBoxes, SIGNAL('triggered()'), self.toggleFeatureBoxes )
		self.connect( self.actionToggleBinarized, SIGNAL('triggered()'), self.toggleBinarized )
		self.connect( self.actionLogin, SIGNAL('triggered()'), self.login )
		self.connect( self.actionSaveTemplate, SIGNAL('triggered()'), self.saveTemplate )
		self.connect( self.actionSaveTemplateAs, SIGNAL('triggered()'), self.saveTemplateAs )
		self.connect( self.actionNewTemplate, SIGNAL('triggered()'), self.newTemplate )
		self.connect( self.actionDelete, SIGNAL('triggered()'), self.removeTemplateBox )
		self.connect( self.actionZoom, SIGNAL('triggered()'), self.zoom )
		self.connect( self.actionUnzoom, SIGNAL('triggered()'), self.unzoom )
		self.connect( self.actionFindMatchingTemplateByOffset, SIGNAL('triggered()'), self.findMatchingTemplateByOffset )
		self.connect( self.actionFindMatchingTemplateByText, SIGNAL('triggered()'), self.findMatchingTemplateByText )
		self.connect( self.actionRecognizeInvoice, SIGNAL('triggered()'), self.recognizeInvoice )
		self.toggleImageBoxes()
		QTimer.singleShot( 1000, self.setup )
		self.updateTitle()
		self.updateActions()

		# Login defaults
		LoginDialog.defaultHost = 'localhost'
		LoginDialog.defaultPort = 8070
		LoginDialog.defaultProtocol = 'socket://'
		LoginDialog.defaultUserName = '******'

		self.recognizer = Recognizer()
		self.connect( self.recognizer, SIGNAL('finished()'), self.recognized )
Example #8
0
class MainWindow(QMainWindow):
	Unnamed = _('unnamed')

	def __init__(self, parent=None):
		QMainWindow.__init__(self, parent)
		loadUi( 'mainwindow.ui', self )
		self.scene = DocumentScene()
		self.uiView.setScene( self.scene )
		self.uiView.setRenderHints( QPainter.Antialiasing | QPainter.TextAntialiasing | QPainter.SmoothPixmapTransform )
		self.uiView.setCacheMode( QGraphicsView.CacheBackground )

		self._template = Template( self.Unnamed )
		self.scene.setTemplate(self._template)

		self.uiTool = ToolWidget( self.uiToolDock )

		self.undoGroup = QUndoGroup( self )
		stack = QUndoStack( self.undoGroup )
		self.undoGroup.setActiveStack( stack )

		# Let default Qt Undo and Redo Actions handle the Undo/Redo actions
		# And put them at the very beggining of the Edit menu
		undoAction = self.undoGroup.createUndoAction( self.menuEdit )
		undoAction.setShortcut( "Ctrl+Z" )
		redoAction = self.undoGroup.createRedoAction( self.menuEdit )
		redoAction.setShortcut( "Ctrl+Shift+Z" )
		if self.menuEdit.actions():
			firstAction = self.menuEdit.actions()[0]
		else:
			firstAction = None
		self.menuEdit.insertAction( firstAction, undoAction )
		self.menuEdit.insertAction( firstAction, redoAction )

		self.connect( self.scene, SIGNAL('newTemplateBox(QRectF)'), self.newTemplateBox )
		self.connect( self.scene, SIGNAL('currentTemplateBoxChanged(PyQt_PyObject,PyQt_PyObject)'), self.currentTemplateBoxChanged)
		self.connect( self.scene, SIGNAL('mouseMoved'), self.sceneMouseMoved )
		self.connect( self.actionExit, SIGNAL('triggered()'), self.close )
		self.connect( self.actionOpenImage, SIGNAL('triggered()'), self.openImage )
		self.connect( self.actionOpenTemplate, SIGNAL('triggered()'), self.openTemplate )
		self.connect( self.actionToggleImageBoxes, SIGNAL('triggered()'), self.toggleImageBoxes )
		self.connect( self.actionToggleTemplateBoxes, SIGNAL('triggered()'), self.toggleTemplateBoxes )
		self.connect( self.actionToggleFeatureBoxes, SIGNAL('triggered()'), self.toggleFeatureBoxes )
		self.connect( self.actionToggleBinarized, SIGNAL('triggered()'), self.toggleBinarized )
		self.connect( self.actionLogin, SIGNAL('triggered()'), self.login )
		self.connect( self.actionSaveTemplate, SIGNAL('triggered()'), self.saveTemplate )
		self.connect( self.actionSaveTemplateAs, SIGNAL('triggered()'), self.saveTemplateAs )
		self.connect( self.actionNewTemplate, SIGNAL('triggered()'), self.newTemplate )
		self.connect( self.actionDelete, SIGNAL('triggered()'), self.removeTemplateBox )
		self.connect( self.actionZoom, SIGNAL('triggered()'), self.zoom )
		self.connect( self.actionUnzoom, SIGNAL('triggered()'), self.unzoom )
		self.connect( self.actionFindMatchingTemplateByOffset, SIGNAL('triggered()'), self.findMatchingTemplateByOffset )
		self.connect( self.actionFindMatchingTemplateByText, SIGNAL('triggered()'), self.findMatchingTemplateByText )
		self.connect( self.actionRecognizeInvoice, SIGNAL('triggered()'), self.recognizeInvoice )
		self.toggleImageBoxes()
		QTimer.singleShot( 1000, self.setup )
		self.updateTitle()
		self.updateActions()

		# Login defaults
		LoginDialog.defaultHost = 'localhost'
		LoginDialog.defaultPort = 8070
		LoginDialog.defaultProtocol = 'socket://'
		LoginDialog.defaultUserName = '******'

		self.recognizer = Recognizer()
		self.connect( self.recognizer, SIGNAL('finished()'), self.recognized )

	def setup(self):
		#initOcrSystem()	
		#self.scene.setDocument( 'c-0.tif' )

		self.connect( self.uiTool, SIGNAL('recognizerChanged(QString)'), self.recognizerChanged )
		self.uiTool.show()
		self.uiToolDock.setWidget( self.uiTool )

		#Rpc.session.login( 'http://*****:*****@127.0.0.1:8069', 'g1' )
	def sceneMouseMoved(self, pos):
		self.updatePosition( pos )

	def findMatchingTemplateByOffset(self):
		self.findMatchingTemplate( 'offset' )

	def findMatchingTemplateByText(self):
		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):
		if type == 'offset':
			title = _('Template search by offset')
		else:
			title = _('Template search by text')

		if not self.recognizer.image:
			QMessageBox.information( self, title, _('No image opened. Please open an image to find a matching template.') )
			return

		if not Rpc.session.logged():
			if not self.login():
				return 
		templates = TemplateStorageManager.loadAll()
		time = QTime()
		time.start()
		if type == 'offset':
			result = self.recognizer.findMatchingTemplateByOffset( templates )
		else:
			result = self.recognizer.findMatchingTemplateByText( templates )
		elapsed = time.elapsed()
		if not result['template']:
			QMessageBox.information( self, title, _('No template found for the current image. Took %d milliseconds') % elapsed )
			return
		self._template = result['template'] 
		self.scene.setTemplate(self._template)
		self.updateTitle()
		QMessageBox.information( self, title, _('Template found with offset (%.2f, %.2f) in %d milliseconds') % (result['xOffset'], result['yOffset'], elapsed) )
		

	def recognizerChanged(self, recognizer):
		rect = self.uiTool.box.rect 
		self.uiTool.setText( self.scene.recognizer.textInRegion( rect, unicode(recognizer) ) )

	def newTemplateBox(self, rect):
		# Creating and adding the box to the template
		# will automatically create the Rect in the Scene
		box = TemplateBox()
		box.rect = rect
		box.text = self.scene.recognizer.textInRegion( rect, 'text' )
		box.featureRect = self.scene.recognizer.featureRectInRegion( rect, 'text' )
		add = AddTemplateBoxUndoCommand( self._template, box )
		self.undoGroup.activeStack().push( add )
		
	#def setCurrentTemplateBox(self, box):
		#if self.uiTool.box:
			#self.uiTool.store()
		#self.uiTool.box = box
	def currentTemplateBoxChanged(self, current, previous):
		if self.uiTool.box:
			self.uiTool.store()
		self.uiTool.box = current
		self.actionDelete.setEnabled( bool(current) )

	def openImage(self):
		self.fileName = QFileDialog.getOpenFileName( self )	
		if self.fileName.isNull():
			return

		QApplication.setOverrideCursor( Qt.BusyCursor )
		self.recognizer.startRecognition( QImage(self.fileName) )

	def recognized(self):
		self.scene.setDocument( self.recognizer )
		QApplication.restoreOverrideCursor()

	def toggleImageBoxes(self):
		self.scene.setImageBoxesVisible( self.actionToggleImageBoxes.isChecked() )	

	def toggleTemplateBoxes(self):
		self.scene.setTemplateBoxesVisible( self.actionToggleTemplateBoxes.isChecked() )

	def toggleFeatureBoxes(self):
		self.scene.setFeatureBoxesVisible( self.actionToggleFeatureBoxes.isChecked() )

	def toggleBinarized(self):
		self.scene.setBinarizedVisible( self.actionToggleBinarized.isChecked() )

	def removeTemplateBox(self):
		if not self.uiTool.box:
			return
		delete = DeleteUndoCommand( self._template, self.uiTool.box )
		self.undoGroup.activeStack().push( delete )

	def zoom(self):
		self.uiView.scale( 1.2, 1.2 )

	def unzoom(self):
		self.uiView.scale( 0.8, 0.8 )

	def login(self):
		dialog = LoginDialog( self )
		if dialog.exec_() == QDialog.Rejected:
			return False
		if Rpc.session.login( dialog.url, dialog.databaseName ) > 0:
			self.updateTitle()
			return True
		else:
			self.updateTitle()
			return False

	def newTemplate(self):
		answer = QMessageBox.question(self, _('New Template'), _('Do you want to save changes to the current template?'), QMessageBox.Save | QMessageBox.No | QMessageBox.Cancel )
		if answer == QMessageBox.Cancel:
			return
		elif answer == QMessageBox.Save:
			if not self.saveTemplate():
				return
		self._template = Template( self.Unnamed )	
		self.scene.setTemplate( self._template )
		self.updateTitle()

	def saveTemplate(self):
		self.uiTool.store()
		if not Rpc.session.logged():
			if not self.login():
				return False

		if not self._template.id:
			(name, ok) = QInputDialog.getText( self, _('Save template'), _('Template name:') )
			if not ok:
				return False
			self._template.name = unicode(name)
				

		if self._template.id:
			Rpc.session.call( '/object', 'execute', 'nan.template', 'write', [self._template.id], {'name': self._template.name } )
			ids = Rpc.session.call( '/object', 'execute', 'nan.template.box', 'search', [('template','=',self._template.id)] )
			Rpc.session.call( '/object', 'execute', 'nan.template.box', 'unlink', ids )
		else:
			self._template.id = Rpc.session.call( '/object', 'execute', 'nan.template', 'create', {'name': self._template.name } )
		for x in self._template.boxes:
			values = { 
				'x': x.rect.x(), 
				'y': x.rect.y(), 
				'width': x.rect.width(), 
				'height': x.rect.height(), 
				'feature_x' : x.featureRect.x(),
				'feature_y' : x.featureRect.y(),
				'feature_width' : x.featureRect.width(),
				'feature_height' : x.featureRect.height(),
				'template': self._template.id, 
				'name': x.name, 
				'text': x.text, 
				'recognizer': x.recognizer, 
				'type': x.type, 
				'filter': x.filter 
			}
			Rpc.session.call( '/object', 'execute', 'nan.template.box', 'create', values )
		self.updateTitle()
		return True

	def saveTemplateAs(self):
		id = self._template.id
		self._template.id = 0
		if not self.saveTemplate():
			self._template.id = id
		self.updateTitle()

	def openTemplate(self):
		if not Rpc.session.logged():
			if not self.login():
				return

		dialog = OpenTemplateDialog(self)
		if dialog.exec_() == QDialog.Rejected:
			return
		model = dialog.group[dialog.id]
		self._template = Template( model.value('name') )
		self._template.id = model.id

		fields = Rpc.session.execute('/object', 'execute', 'nan.template.box', 'fields_get')
		model.value('boxes').addFields( fields )
		for x in model.value('boxes'):
			box = TemplateBox()
			box.rect = QRectF( x.value('x'), x.value('y'), x.value('width'), x.value('height') )
			box.featureRect = QRectF( x.value('feature_x'), x.value('feature_y'), 
						  x.value('feature_width'), x.value('feature_height') )
			box.name = x.value('name')
			box.text = x.value('text')
			box.recognizer = x.value('recognizer')
			box.type = x.value('type')
			box.filter = x.value('filter')
			self._template.addBox( box )

		self.scene.setTemplate(self._template)
		self.updateTitle()

	def updateTitle(self):
		self.setWindowTitle( "Planta - [%s]" % self._template.name )
		
		if Rpc.session.logged():
			server = '%s [%s]' % (Rpc.session.url, Rpc.session.databaseName)
		else:
			shortcut = unicode( self.actionLogin.shortcut().toString() )
			if shortcut:
				server = _('Press %s to login') % shortcut
			else:
				server = 'not logged in'
		self.uiServer.setText( server )

	def updatePosition(self, pos):
		pos = self.uiView.mapToScene( self.uiView.mapFromGlobal( QCursor.pos() ) )
		pos = self.scene.mapPointToRecognizer( pos )
		position = _('(%.2f, %.2f)') % (pos.x(), pos.y())
 		self.uiPosition.setText( position )

	def updateActions(self):
		# Allow deleting if there's a TemplateBox selected
		self.actionDelete.setEnabled( bool(self.uiTool.box) )