mirror of
https://gitlab.os-k.eu/neox/CNIRevelator.git
synced 2023-08-25 14:03:10 +02:00
Detection of document works
This commit is contained in:
parent
0241b7c69a
commit
ea3bd9fb80
@ -36,6 +36,7 @@ import globs # globs.py
|
|||||||
import pytesseract # pytesseract.py
|
import pytesseract # pytesseract.py
|
||||||
import logger # logger.py
|
import logger # logger.py
|
||||||
|
|
||||||
|
|
||||||
from main import * # main.py
|
from main import * # main.py
|
||||||
|
|
||||||
# Global handler
|
# Global handler
|
||||||
|
36
src/ihm.py
36
src/ihm.py
@ -31,6 +31,42 @@ from tkinter import ttk
|
|||||||
import logger # logger.py
|
import logger # logger.py
|
||||||
import globs # globs.py
|
import globs # globs.py
|
||||||
|
|
||||||
|
|
||||||
|
controlKeys = ["Return", "Right", "Left", "Up", "Down", "Home", "End", "Delete", "BackSpace", "Inser", "Shift_L", "Shift_R", "Control_R", "Control_L"]
|
||||||
|
|
||||||
|
class DocumentAsk(Toplevel):
|
||||||
|
|
||||||
|
def __init__(self, parent, choices):
|
||||||
|
self.choice = 0
|
||||||
|
vals = [0, 1]
|
||||||
|
super().__init__(parent)
|
||||||
|
self.title("Choisir le document d'identité :")
|
||||||
|
|
||||||
|
ttk.Radiobutton(self, text=choices[0], command=self.register0, value=vals[0]).pack()
|
||||||
|
ttk.Radiobutton(self, text=choices[1], command=self.register1, value=vals[1]).pack()
|
||||||
|
|
||||||
|
self.button = Button(self, text='OK', command=(self.ok)).pack()
|
||||||
|
self.resizable(width=False, height=False)
|
||||||
|
ws = self.winfo_screenwidth()
|
||||||
|
hs = self.winfo_screenheight()
|
||||||
|
w = hs / 3
|
||||||
|
h = ws / 20
|
||||||
|
self.update()
|
||||||
|
if getattr(sys, 'frozen', False):
|
||||||
|
self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
|
||||||
|
else:
|
||||||
|
self.iconbitmap('id-card.ico')
|
||||||
|
x = ws / 2 - w / 2
|
||||||
|
y = hs / 2 - h / 2
|
||||||
|
self.geometry('%dx%d+%d+%d' % (w, h, x, y))
|
||||||
|
|
||||||
|
def register0(self):
|
||||||
|
self.choice = 0
|
||||||
|
def register1(self):
|
||||||
|
self.choice = 1
|
||||||
|
def ok(self):
|
||||||
|
self.destroy()
|
||||||
|
|
||||||
class LoginDialog(Toplevel):
|
class LoginDialog(Toplevel):
|
||||||
|
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
|
58
src/main.py
58
src/main.py
@ -33,6 +33,7 @@ import threading
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
import ihm # ihm.py
|
||||||
import logger # logger.py
|
import logger # logger.py
|
||||||
import mrz # mrz.py
|
import mrz # mrz.py
|
||||||
import globs # globs.py
|
import globs # globs.py
|
||||||
@ -51,6 +52,7 @@ class mainWindow(Tk):
|
|||||||
def initialize(self):
|
def initialize(self):
|
||||||
self.mrzChar = ''
|
self.mrzChar = ''
|
||||||
self.mrzDecided = False
|
self.mrzDecided = False
|
||||||
|
self.Tags = []
|
||||||
|
|
||||||
# Get the screen size
|
# Get the screen size
|
||||||
ws = self.winfo_screenwidth()
|
ws = self.winfo_screenwidth()
|
||||||
@ -198,9 +200,37 @@ class mainWindow(Tk):
|
|||||||
logfile.printdbg('Initialization successful')
|
logfile.printdbg('Initialization successful')
|
||||||
|
|
||||||
def onTabPressed(self, event):
|
def onTabPressed(self, event):
|
||||||
|
|
||||||
return 'break'
|
return 'break'
|
||||||
|
|
||||||
|
def stringValidation(self):
|
||||||
|
# analysis
|
||||||
|
# If we must decide the type of the document
|
||||||
|
if not self.mrzDecided:
|
||||||
|
# Get the candidates
|
||||||
|
candidates = mrz.allDocMatch(self.mrzChar.split("\n"))
|
||||||
|
|
||||||
|
if len(candidates) == 2 and len(self.mrzChar) >= 8:
|
||||||
|
# Parameters for the choice invite
|
||||||
|
invite = ihm.DocumentAsk(self, [candidates[0][2], candidates[1][2]])
|
||||||
|
invite.transient(self)
|
||||||
|
invite.grab_set()
|
||||||
|
invite.focus_force()
|
||||||
|
|
||||||
|
self.wait_window(invite)
|
||||||
|
|
||||||
|
self.logOnTerm("Document detecté : {}".format(candidates[invite.choice][2]))
|
||||||
|
self.mrzDecided = candidates[invite.choice]
|
||||||
|
|
||||||
|
elif len(candidates) == 1:
|
||||||
|
self.logOnTerm("Document detecté : {}".format(candidates[0][2]))
|
||||||
|
self.mrzDecided = candidates[0]
|
||||||
|
else:
|
||||||
|
print("LEN mrzChar {} VS {}".format(len(self.mrzChar) - 2, len(self.mrzDecided[0][0])))
|
||||||
|
# break the line
|
||||||
|
if len(self.mrzChar) - 2 == len(self.mrzDecided[0][0]):
|
||||||
|
self.termtext.delete("1.0","end")
|
||||||
|
self.termtext.insert("1.0", self.mrzChar)
|
||||||
|
|
||||||
def entryValidation(self, event):
|
def entryValidation(self, event):
|
||||||
"""
|
"""
|
||||||
On the fly validation with regex
|
On the fly validation with regex
|
||||||
@ -216,7 +246,7 @@ class mainWindow(Tk):
|
|||||||
controlled = True
|
controlled = True
|
||||||
|
|
||||||
# If not a control char
|
# If not a control char
|
||||||
if not controlled and not event.keysym in ["Return", "Right", "Left", "Home", "End", "Delete", "BackSpace", "Inser", "Shift", "Control"]:
|
if not controlled and not event.keysym in ihm.controlKeys:
|
||||||
# the regex
|
# the regex
|
||||||
regex = re.compile("[A-Z]|<|[0-9]")
|
regex = re.compile("[A-Z]|<|[0-9]")
|
||||||
# match !
|
# match !
|
||||||
@ -224,21 +254,12 @@ class mainWindow(Tk):
|
|||||||
self.logOnTerm("Caractère non accepté !\n")
|
self.logOnTerm("Caractère non accepté !\n")
|
||||||
return "break"
|
return "break"
|
||||||
|
|
||||||
# analysis
|
# Adds the entry
|
||||||
self.mrzChar = self.termtext.get("1.0", "end")[:-1] + event.char + '\n'
|
self.mrzChar = self.termtext.get("1.0", "end")[:-1] + event.char + '\n'
|
||||||
|
|
||||||
# If we must decide the type of the document
|
self.stringValidation()
|
||||||
if not self.mrzDecided:
|
|
||||||
# Get the candidates
|
|
||||||
candidates = mrz.allDocMatch(self.mrzChar.split("\n"))
|
|
||||||
|
|
||||||
if len(candidates) == 2:
|
|
||||||
# XXX demander !
|
|
||||||
elif len(candidates) == 1:
|
|
||||||
self.logOnTerm("Document detecté : {}".format(candidates[0]))
|
|
||||||
self.mrzDecided = candidates[0]
|
|
||||||
else:
|
|
||||||
# Work with the document decided
|
|
||||||
|
|
||||||
|
|
||||||
def pasteValidation(self, event):
|
def pasteValidation(self, event):
|
||||||
@ -250,14 +271,19 @@ class mainWindow(Tk):
|
|||||||
|
|
||||||
# get the clipboard content
|
# get the clipboard content
|
||||||
lines = self.clipboard_get()
|
lines = self.clipboard_get()
|
||||||
|
self.mrzChar = ""
|
||||||
|
|
||||||
# the regex
|
# the regex
|
||||||
regex = re.compile("[^A-Z0-9<]")
|
regex = re.compile("[^A-Z0-9<]")
|
||||||
|
|
||||||
lines = re.sub(regex, '', lines)
|
lines = re.sub(regex, '', lines)
|
||||||
|
|
||||||
# breaking the lines
|
# Get that
|
||||||
self.termtext.insert("1.0", lines[:mrz.longest] + '\n' + lines[mrz.longest:mrz.longest*2] )
|
for char in lines:
|
||||||
|
self.termtext.insert("1.0", self.mrzChar)
|
||||||
|
self.mrzChar = self.mrzChar + char
|
||||||
|
self.stringValidation()
|
||||||
|
|
||||||
return "break"
|
return "break"
|
||||||
|
|
||||||
|
|
||||||
|
42
src/mrz.py
42
src/mrz.py
@ -639,7 +639,7 @@ AC = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
## XXXXXXXXXXX
|
## XXXXXXXXXXX
|
||||||
# VA = [
|
# VB = [
|
||||||
# ["11222333333333333333333333333333333333333333", "444444444566677777789AAAAAABCCCCCCCCCCCCCCCDE"],
|
# ["11222333333333333333333333333333333333333333", "444444444566677777789AAAAAABCCCCCCCCCCCCCCCDE"],
|
||||||
# {
|
# {
|
||||||
# "1": ["2", "CODE", "V."],
|
# "1": ["2", "CODE", "V."],
|
||||||
@ -655,10 +655,10 @@ AC = [
|
|||||||
# "B": ["1", "CTRL", "[0-9]", "A"],
|
# "B": ["1", "CTRL", "[0-9]", "A"],
|
||||||
# "C": ["14", "FACULT", ".+"]
|
# "C": ["14", "FACULT", ".+"]
|
||||||
# },
|
# },
|
||||||
# "Visa de type A"
|
# "Visa de type B"
|
||||||
# ]
|
# ]
|
||||||
|
|
||||||
VB = [
|
VA = [
|
||||||
["112223333333333333333333333333333333", "444444444566677777789AAAAAABCCCCCC"],
|
["112223333333333333333333333333333333", "444444444566677777789AAAAAABCCCCCC"],
|
||||||
{
|
{
|
||||||
"1": ["2", "CODE", "V."],
|
"1": ["2", "CODE", "V."],
|
||||||
@ -674,7 +674,26 @@ VB = [
|
|||||||
"B": ["1", "CTRL", "[0-9]", "A"],
|
"B": ["1", "CTRL", "[0-9]", "A"],
|
||||||
"C": ["8", "FACULT", ".+"]
|
"C": ["8", "FACULT", ".+"]
|
||||||
},
|
},
|
||||||
"Visa de type B"
|
"Visa de type A"
|
||||||
|
]
|
||||||
|
|
||||||
|
TSF = [
|
||||||
|
["112223333333333333333333333333333333", "444444444566677777789AAAAAABCCCCCC"],
|
||||||
|
{
|
||||||
|
"1": ["2", "CODE", "TS"],
|
||||||
|
"2": ["3", "PAYS", "[A-Z]+"],
|
||||||
|
"3": ["31", "NOM", "([A-Z]|<)+"],
|
||||||
|
"4": ["9", "NO", ".+"],
|
||||||
|
"5": ["1", "CTRL", "[0-9]","4"],
|
||||||
|
"6": ["3", "NAT", "[A-Z]+"],
|
||||||
|
"7": ["6", "BDATE", "[0-9]+"],
|
||||||
|
"8": ["1", "CTRL", "[0-9]", "7"],
|
||||||
|
"9": ["1", "SEX", "[A-Z]"],
|
||||||
|
"A": ["6", "EDATE", "[0-9]+"],
|
||||||
|
"B": ["1", "CTRL", "[0-9]", "A"],
|
||||||
|
"C": ["8", "FACULT", ".+"]
|
||||||
|
},
|
||||||
|
"Titre de séjour"
|
||||||
]
|
]
|
||||||
|
|
||||||
I__ = [
|
I__ = [
|
||||||
@ -732,7 +751,7 @@ DL = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
#TYPES = [ID, I__, VB, VA, AC, I_, IP, P, DL]
|
#TYPES = [ID, I__, VB, VA, AC, I_, IP, P, DL]
|
||||||
TYPES = [IDFR, I__, VB, AC, I_, IP, P, DL]
|
TYPES = [IDFR, I__, VA, AC, I_, IP, P, DL, TSF]
|
||||||
|
|
||||||
# longest document MRZ line
|
# longest document MRZ line
|
||||||
longest = max([len(x[0][0]) for x in TYPES])
|
longest = max([len(x[0][0]) for x in TYPES])
|
||||||
@ -745,7 +764,6 @@ def limits(line, fieldtype):
|
|||||||
b = line.rfind(fieldtype)
|
b = line.rfind(fieldtype)
|
||||||
return (a,b+1)
|
return (a,b+1)
|
||||||
|
|
||||||
|
|
||||||
def docMatch(doc, strs):
|
def docMatch(doc, strs):
|
||||||
# Global handler
|
# Global handler
|
||||||
logfile = logger.logCur
|
logfile = logger.logCur
|
||||||
@ -782,8 +800,8 @@ def docMatch(doc, strs):
|
|||||||
|
|
||||||
# Print for debug
|
# Print for debug
|
||||||
|
|
||||||
#print("Field : {}, type = {}, on str : {}".format(field, fieldtype, fstr))
|
# print("Field : {}, type = {}, on str : {}".format(field, fieldtype, fstr))
|
||||||
#logfile.printdbg(" REGEX : {}, match : {}".format(regex, matching))
|
# logfile.printdbg(" REGEX : {}, match : {}".format(regex, matching))
|
||||||
# exit the loop
|
# exit the loop
|
||||||
|
|
||||||
logfile.printdbg("{} level : {}/{} (+{})".format(doc[2], level, nchar, bonus))
|
logfile.printdbg("{} level : {}/{} (+{})".format(doc[2], level, nchar, bonus))
|
||||||
@ -793,7 +811,7 @@ def allDocMatch(strs, final=False):
|
|||||||
# Global handler
|
# Global handler
|
||||||
logfile = logger.logCur
|
logfile = logger.logCur
|
||||||
|
|
||||||
print(strs)
|
#print(strs)
|
||||||
|
|
||||||
SCORES = []
|
SCORES = []
|
||||||
for doc in TYPES:
|
for doc in TYPES:
|
||||||
@ -815,11 +833,11 @@ def allDocMatch(strs, final=False):
|
|||||||
candidates += [TYPES[i]]
|
candidates += [TYPES[i]]
|
||||||
canditxt += [TYPES[i][2]]
|
canditxt += [TYPES[i][2]]
|
||||||
# Return the candidates
|
# Return the candidates
|
||||||
logfile.printdbg("Scores : {}".format(SCORES))
|
#logfile.printdbg("Scores : {}".format(SCORES))
|
||||||
logfile.printdbg("Candidates : {}".format(canditxt))
|
#logfile.printdbg("Candidates : {}".format(canditxt))
|
||||||
return candidates
|
return candidates
|
||||||
|
|
||||||
def MRZ(code):
|
def computeControlSum(code):
|
||||||
"""
|
"""
|
||||||
This function computes a control sum for the given characters
|
This function computes a control sum for the given characters
|
||||||
"""
|
"""
|
||||||
|
Loading…
Reference in New Issue
Block a user