Tesseract vs tabelas. Reconhecimento de documentos

Apesar da digitalização de tudo e de todos, em um momento em que a humanidade está prestes a criar uma neurointerface, quando a IA se tornou comum, a clássica tarefa de obter dados de uma varredura / imagem ainda é relevante.





Bom Dia. Meu nome é Aleksey. Trabalho como programador em uma empresa que vende equipamentos. Eu tinha minhas próprias melhores práticas para reconhecer e carregar dados em um programa de contabilidade, e eram apenas os gerentes que inseriam manualmente dezenas de páginas de documentos PDF que não podiam ser facilmente transferidos para o EDF. Eu os convidei para tentar minha solução.





Inicialmente, o ABBYY Cloud foi usado para reconhecimento, mas não é gratuito e o modo de teste não é longo o suficiente. Resolvi escrever minha API em python, onde todo o poder da tesseracta grátis é usado. O problema é que tesseract é um reconhecimento de texto, e não define uma tabela, acaba sendo de pouca utilidade. Um dia antes, li o artigo https://vc.ru/ml/139816-povyshenie-kachestva-raspoznavaniya-skanov-dokumentov-s-tablicami-s-pomoshchyu-vychisleniya-koordinat-yacheek, onde todas as células da tabela são obtidas usando openCV, cada célula é executada por meio de tesseract e, portanto, os dados corretos podem ser obtidos. Decidi tentar este método. A postagem será sobre o que aconteceu.





Para o teste, tirei da base de demonstração 1c TORG-12. Este formulário tem uma estrutura bastante complexa, muitas tabelas, muito texto, muitos dados. Exatamente o que você precisa.





pdf , gostscript . ImageMagick, - . cmd , gostscript .





, openCV , QR-. pyzbar.





, . , . , , . - .





clahe = cv2.createCLAHE(clipLimit=50, tileGridSize=(50, 50))
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)  
l, a, b = cv2.split(lab) 
l2 = clahe.apply(l)  
lab = cv2.merge((l2, a, b))  
img2 = cv2.cvtColor(lab, cv2.COLOR_LAB2BGR) 

gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 75, 255, cv2.THRESH_BINARY_INV )

kernel = np.ones((2, 2), np.uint8)
obr_img = cv2.erode(thresh, kernel, iterations=1)

obr_img = cv2.GaussianBlur(obr_img, (3,3), 0)
      
      



, . , . 5 , delta.





contours, hierarchy = cv2.findContours(obr_img, cv2.RETR_TREE, cv2.CHAIN_APPROX_TC89_L1)
coordinates = []
ogr = round(max(img.shape[0], img.shape[1]) * 0.005)
delta = round(ogr/2 +0.5)
ind = 1;
for i in range(0, len(contours)):
	l, t, w, h = cv2.boundingRect(contours[i])
	if (h > ogr and w > ogr):
    # 
    # 
    # 
    #
    #
    #
    #
    #
  	coordinates.append((0, ind, 0, l, t, w, h, ''))
    ind = ind + 1
      
      



, . sqlite3 coordinates. . , hierarchy, , . .





, . - . , .





, , - . , , . . , , . , , , , , , .





2 :













. , . , . . , , , , . - . . , , . . . . / 2*. . , - , . .





. . 4 . , , "". "" , , . - , 4 , .









. . tesseract , 3 , . , "-". "-", "---00", . .





text1 = pytesseract.image_to_string(image[t1:t2,l1:l2], lang=lang, config='--psm 6')
text2 = pytesseract.image_to_string(image[t1:t2,l1:l2], lang=lang, config='')
text3 = pytesseract.image_to_string(image[t1+round(delta/2):t2-round(delta/2),l1+round(delta/2):l2-round(delta/2)], lang=lang, config='--psm 7')
text1 = text1.replace("\n", " ")
text2 = text2.replace("\n", " ")
text3 = text3.replace("\n", " ")
text1 = re.sub(' *[^ \(\)--\d\w\/\\\.\-,:; ]+ *', ' ', text1)
text2 = re.sub(' *[^ \(\)--\d\w\/\\\.\-,:; ]+ *', ' ', text2)
text3 = re.sub(' *[^ \(\)--\d\w\/\\\.\-,:; ]+ *', ' ', text3)

while text1.find('  ')!=-1:
    text1 = text1.replace('  ',' ')
while text2.find('  ') != -1:
    text2 = text2.replace('  ', ' ')
while text3.find('  ') != -1:
    text3 = text3.replace('  ', ' ')
      
      



. , . , . , -, , , . , , . , , , . , , ? , 2 , . . , , , . , ; ; , . .





. . 4 . "". , , . .





, , . , . API JSON, 1 . , . . . 1 pdf 20 , . , Tesserocr Pytesseract, .





https://github.com/Trim891/API. PyCharm "", GitHub, *.py requirements.txt. , , , , , ; " , ", , , - ; , , 2 . .





PS Há muitos comentários nos arquivos, muitas coisas desnecessárias e, em geral, um código de merda é uma bagunça criativa. Foi tudo para uso interno, não deu tempo de se arrumar =)








All Articles