Tesseract vs tablas. Reconocimiento de documentos

A pesar de la digitalización de todo y de todos, en un momento en que la humanidad está a punto de crear una neurointerfaz, cuando la IA se ha convertido en algo común, la tarea clásica de obtener datos de un escaneo / imagen sigue siendo relevante.





Buen día. Mi nombre es Aleksey. Trabajo como programador en una empresa de venta de equipos. Tenía mis propias mejores prácticas para reconocer y cargar datos en un programa de contabilidad, y solo los gerentes ingresaban manualmente docenas de páginas de documentos PDF que no podían transferirse fácilmente a EDF. Los invité a probar mi solución.





Inicialmente, ABBYY Cloud se utilizó para el reconocimiento, pero no es gratuito y el modo de prueba no es lo suficientemente largo. Decidí escribir mi API en Python, donde se usa todo el poder de tesseracta gratuito. El problema es que tesseract es un reconocimiento de texto, y no define una tabla, resulta de poca utilidad. Justo el día anterior leí el artículo https://vc.ru/ml/139816-povyshenie-kachestva-raspoznavaniya-skanov-dokumentov-s-tablicami-s-pomoshchyu-vychisleniya-koordinat-yacheek, donde se obtienen todas las celdas de la tabla utilizando openCV, cada celda se ejecuta a través de tesseract y, por lo tanto, se pueden obtener los datos correctos. Decidí probar este método. La publicación será sobre lo que sucedió.





Para la prueba, tomé de la base de demostración 1c TORG-12. Este formulario tiene una estructura bastante compleja, muchas tablas, mucho texto, muchos datos. Justo lo que necesitas.





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 . .





PD: Hay muchos comentarios en los archivos, muchas cosas innecesarias y, en general, el código de mierda es un desastre creativo. Todo fue para uso interno, no hubo tiempo para disfrazarse =)








All Articles