easyocr_readtext.ipynb

mail@pastecode.io avatar
unknown
python
2 months ago
6.3 kB
3
Indexable
Never
pip install easyocr
pip install pdf2image
conda install -c conda-forge poppler
pip install numpy==1.23.1

import easyocr
import PIL
from PIL import ImageDraw
import re
import numpy
import pandas as pd
import pathlib


cur_path = pathlib.Path().resolve() # текущий путь до папки
name = 'Доп_соглашение_о_мин_объеме_ТМС_от_01_10_2022' # название pdf файла
# name = 'ДС_о_минимальном_объеме_№1_от_01.12.2022'
# name = 'ДС_тест_качество'
img_path = f'{cur_path}/{name}.pdf' # расположение pdf файла
img_path

from pdf2image import convert_from_path
pages = convert_from_path(img_path)

for count, page in enumerate(pages):
    if count == 0:
        page.save(f'{name}_1st_page.jpg', 'JPEG') # сохраняем 1-ую страницу в текущую папку

cur_path

new_folder_path = 'rus_ft'
!mkdir -p {new_folder_path} # создаем папку
!unzip rus_ft.zip -d rus_ft # распаковываем архив с моделью в папку

EXPERIMENT_NAME = 'rus_ft' # название эксперимента
OUT_MODEL_PATH = f'{cur_path}/rus_ft' # путь до папки с моделью
OUT_MODEL_PATH

reader = easyocr.Reader(["ru"], # код языка распознавания (ISO 639) 
                        model_storage_directory=OUT_MODEL_PATH,
                        user_network_directory=OUT_MODEL_PATH,
                        recog_network=EXPERIMENT_NAME)

instance_path = f'{cur_path}/{name}_1st_page.jpg' # путь до jpg файла для распознавания
instance_path

result = reader.readtext(instance_path) # координаты bounding boxes, распознанный текст в них и вероятность
print(result)
txt = "\n".join([elem[1] for elem in result]) # распознанный текст из всех bounding boxes
print(txt)


def draw_boxes(instance_path, result, color='red', width=2):
    '''
    function to draw bounding boxes
    input:
        instance_path - path to jpg file
        result - output of readtext function
    output:
        image with bounding boxes
    '''
    image = PIL.Image.open(instance_path)
    draw = ImageDraw.Draw(image)
    for res in result:
        p0, p1, p2, p3 = res[0]
        draw.line([*p0, *p1, *p2, *p3, *p0], fill=color, width=width)
    return image

draw_boxes(instance_path, result)

txt_n = txt.replace('\n',' ') # распознанный текст без переноса строк
txt_n

cell_value = [] # список с распознанными по шаблонам полями
pattern_agr_num = '№[ ]{0,}С[0-9]{2}-[0-9]{2}/[0-9]{5}/[0-9]{5}/Д' # шаблон для нового номера
pattern_agr_num_old =  '№[ ]{0,}[0-9]{11}' # шаблон для старого номера
try:
    found_agr_num = re.search(pattern_agr_num, txt_n) # новый номер договора по шаблону
    cell_value.append(found_agr_num[0])
except TypeError:
    try:
        found_agr_num_old = re.search(pattern_agr_num_old, txt_n) # старый номер договора по шаблону
        cell_value.append(found_agr_num_old[0])
    except TypeError:
        cell_value.append('-') # если номер не нашелся ни по одному из шаблонов


pattern_agr_date = 'от [0-9][0-9].[0-9][0-9].[0-9][0-9][0-9][0-9][ г.]{0,}' # шаблон для даты договора
try:
    found_agr_date = re.search(pattern_agr_date, txt_n) # дата договора
    cell_value.append(found_agr_date[0])
except TypeError:
    cell_value.append('-') # если дата договора не нашлась по шаблону

pattern_add_date = '[«]{0,}[0-9][0-9][»]{0,} [а-яА-Я]{3,8} [0-9][0-9][0-9][0-9][ года.]{0,}' # шаблон для даты ДС
try:
    found_add_date = re.search(pattern_add_date, txt_n) # дата ДС
    cell_value.append(found_add_date[0])
except TypeError:
    cell_value.append('-') # если дата ДС не нашлась по шаблону

try:
    st_pos = found_agr_date.span()[1] # конечная позиция даты договора
    end_pos = found_add_date.span()[0] # начальная позиция даты ДС
    city = txt_n[st_pos:end_pos-1] # город
    cell_value.append(city)
except AttributeError:
    cell_value.append('-') # если город не нашелся (дата договора и/или дата ДС не нашлись по шаблону)

pattern_part = '[иИ].{0,2}(ООО|Общество.{0,}ограниченной.{0,}ответственностью).{0,}именуемое.{0,}дальнейшем.{0,2}Покупатель' # шаблон контрагента для хорошего качества скана
pattern_part_bad = 'одной.{0,3}стороны.{0,3}[иИ].{3,100},' # шаблон контрагента для плохого качества скана
try:
    found_part = re.search(pattern_part, txt_n) # контрагент для хорошего качества скана
    cell_value.append(found_part[0])
except TypeError:
    try:
        found_part_bad = re.search(pattern_part_bad, txt_n) # контрагент для плохого качества скана
        cell_value.append(found_part_bad[0])
    except TypeError:
        cell_value.append('-') # если контрагент не нашелся по шаблону

pattern_dev = 'не менее.{1,7}объема' # шаблон для процента отклонения
try:
    found_dev = re.search(pattern_dev, txt_n) # процент отклонения
    cell_value.append(found_dev[0])
except TypeError:
    cell_value.append('-') # если процент отклонения не нашелся по шаблону

name_value = ['№ договора',
             'дата договора',
             'дата доп соглашения',
             'город',
             'контрагент',
             'процент оклонения']
# список с названиями полей

cell_value

df = pd.DataFrame({'Поле договора': name_value, 'Текст договора': cell_value})
df.to_csv(f'{name}.csv', encoding='cp1251')
Leave a Comment