Среди поставщиков цифровых услуг популярен набивший оскомину корпоративный штамп: «Решаем задачи бизнеса с помощью разработки программного обеспечения». Подобная формулировка лишена конкретики и оставляет после себя много вопросов, на которые быстро не ответить.
Лучше всего подробности проектной работы раскрываются в кейсах. Поэтому мы подготовили этот материал, чтобы показать, как на практике справились с нетривиальной задачей для компании из финансового сектора. Публикация будет интересна представителям бизнеса и программистам.
Краткие сведения о клиенте и проекте
Консалтинговая компания «Госгарант» помогает банкам оперативно рассматривать сделки клиентов, проводить скоринг и принимать решения о представлении безотзывной гарантии победителям государственных тендеров. Взаимодействие с банками происходит в информационной системе FCS, которую разработала и семь лет сопровождает команда Work Solutions. За эти годы мы отгрузили 35000 коммерческих часов и выпустили 6 глобальных обновлений системы, а значит разбираемся в проекте как никто другой.
Цель: расширить функционал существующей системы, чтобы повысить ее ценность в глазах клиентов. Чем больше операций автоматизировано, тем выше вероятность, что банк захочет внедрить FCS у себя.
Задача: втоматизировать процесс обработки форм налоговой отчетности и снизить нагрузку на менеджеров банка. Увеличить таким образом скорость обработки заявок и, как следствие, повысить конверсию по выпуску банковских гарантий победителям гостендеров.
Как было раньше: в FCS интегрирована разработанная другим подрядчиком система распознавания документов. Она не распознавала формы бухгалтерской отчетности нового образца, работала медленно и давала высокий процент погрешности. Клиент решил не возобновлять сотрудничество с предыдущим исполнителем, и поручил нам разработку полной замены приложения.
Аналитика
Прежде чем приступать к выполнению и начать расходовать деньги заказчика, нужно сперва понять, как решать поставленную задачу. На любом проекте по созданию ПО приходится сталкиваться с неизвестными факторами. Этап первичной аналитики позволяет рассмотреть несколько вариантов решения, а следовательно учесть ряд рисков на старте.
Даже обращаясь в продакшн, который специализируется исключительно на компьютерном зрении нужно быть готовым к тому, что разработчики запросят время на R&D (Research and development). Это связано с тем, что существует несколько подходов к решению, среди которых желательно выбрать оптимальный.
За это время разработчик проводит «спайк» (spike) — жестко ограниченное по времени исследование, на основе которого оценивает предстоящий объем работ. Результатом исследования также может быть мини проект, для подтверждения концепта (Proof of concept). Это позволяет убедиться, что обнаруженные в ходе исследования подходы жизнеспособны, и дает уверенность, что идея сработает.
Мы запросили у клиента три дня на анализ задачи. Для исследования нам предоставили набор реальных документов, которые нужно распознавать. Изучив десятки файлов, мы выделили три уникальные формы, которые требовали разного подхода при распознавании:
- Форма бухгалтерской отчетности старого образца;
- Машиночитаемая форма нового образца;
- Упрощенная форма сдвухмерным штрихкодом PDF417.
![Изображение статьи](/uploads/Uj6_Dox_Ov37j_Tk_Yy_V_Uh_HRF_5e_Rt2m9_Z2y_Vh_Ub_Vqee_O_c27bdd33d0.jpeg)
Ожидаемые проблемы
Рассмотрев реальные документы мы также определили факторы, которые будут влиять на качество распознавания. На сканах часто встречаются артефакты — следы перфорации, пятна тонера, заломы, сгибы, подписи и печати, которые перекрывают текст. К тому же сами формы отсканированы неровно, в результате чего границы таблиц часто «обрезаны», а содержащийся в них текст наклонен.
Мы проверили возможность распознавания документа табличного типа и определили, с помощью каких инструментов можно это сделать. Далее изучили доступные решения, среди которых выделили опенсорсные инструменты и платные облачные сервисы, которые подходили для решения поставленной задачи. Затем провели небольшой бенчмарк и сравнили результаты их работы.
Полученную информацию в форме отчета предоставили заказчику, чтобы тот решил, стоит ли приступать к разработке. В итоге тарифные планы SaaS-сервиса оказались нерентабельными, поэтому заказчик попросил продолжить разработку.
![Изображение статьи](/uploads/Um_MC_9_Rf2p3dt9f_Nb_P_Jyf_XR_5_Eu_X_Zsr_J_Qqh_R_Od_L_Kp_G_6e067e7194.jpeg)
Планирование
Так как на руках у нас было готовое исследование, этап планирования прошел легко. Для разработки выбрали следующий стек технологий:
- Python — язык программирования, который благодаря обилию доступных библиотек и поддержке многопоточности идеально подходит для решения подобных задач;
- Tesseract OCR — библиотека для оптического распознавания текстов, основанная на алгоритмах машинного обучения;
- OpenCV — библиотека алгоритмов компьютерного зрения;
- Django — фреймворк для создания веб-приложений.
Дорожную карту проекта привязали к типам документов и разделили на четыре двухнедельные итерации.
При подготовке к старту работ мы подняли инфраструктуру приложения, подготовили образы для Docker, настроили среду для разработки и развернули площадку на сервере заказчика для демонстрации. Таким образом мы сразу предоставили заказчику веб-интерфейс, чтобы видеть результаты работы в конце каждого этапа, а также доступ к таск-трекеру, чтобы отслеживать весь процесс.
Разработка
Чтобы упростить предстоящую работу по распознаванию, начали с настройки предпроцессинга. Так как OpenCV работает только с растровыми изображениями мы настроили конвертацию многостраничных PDF в наборы JPEG-изображений. Для сканированных печатных документов настроили выравнивание структуры изображения по горизонтали, удаление шумов, дорисовку прерванных линий таблицы. Чем больше нежелательных артефактов удастся устранить, тем точнее система распознает текст.
![Изображение статьи](/uploads/c_M04_Pp_XGOC_Qf_W_Cy_Oa_G_No9_Q6_RB_02yqoz_Sf_Hbz_LAXA_680886d3ff.png)
После этого приступили к распознаванию формы КНД старого образца. Проведенное ранее исследование показало, что линейность табличной структуры поможет распознать содержимое документа. Чтобы определить контуры таблицы преобразовывали входное изображение в двоичное и инвертировали цвет, получив черный фон и белые контуры.
Определив вертикальные и горизонтальные линии, накладываем их друг на друга. На получившемся изображении определяем контуры структуры таблицы. Все поля сортируем слева направо, и по координатам одну к другой подставляем ячейки. Таким образом, удается восстановить столбцы и строки.
![Изображение статьи](/uploads/CH_12u_Zf_S7_Mo_SC_4_Sz8kqs_Wqw_Tkngawv_Qy_CU_41_P8_SE_3ac437c0b3.jpeg)
Остается распознать содержимое отдельных ячеек. Для этого требуется найти отправную точку для X- и Y-осей. Находим ячейку, которая присутствует на всех документах, а что находится за её пределами — отбрасываем. Фильтрация выделенных контуров позволяет сэкономить процессорное время на распознавание текста. Дальше сгруппированные ячейки нарезаем по координатам и передаем в Tesseract для распознавания текста.
Дополнительная сложность связана с тем, что числа представлены в разных форматах — где-то между цифрами стоят пробелы, а где-то запятые. Это как и артефакты нужно отсеять и предоставить в едином формате.
В результате генерируется JSON-файл с ID и хешем документа, которые хранятся в базе данных, чтобы можно было получить результата повторно. Внутри него также содержаться данные с координатами каждой ячейки, распознанные значения, прогноз погрешности (на основе того, как много дефектов было устранено во время препроцессинга) и изображение с этой областью. Оригинальное изображение ячейки нужно, чтобы человек мог проверить, не ошиблась ли машина.
В конце уже первой итерации было видно, что новая система работает эффективнее старой.
Второй спринт был нацелен на распознавание документа с двухмерным штрихкодом PDF417. Так как документ содержит несколько штрихкодов, а распознавать требовалось только нижний внизу страницы, решили верхнюю половину документа не учитывать. У обычных штрихкодов много вертикальных линий, которые расположены плотно друг к другу. Такие контуры обнаружить гораздо проще, чем контуры штрихкода PDF417.
![Изображение статьи](/uploads/h_OMQ_9_Yy0m2_VRP_Adm1_E_Gwx_O25_N_Lag0_W84i_Em_V4zyb_d591035a3a.png)
Для этого мы используем другой алгоритм: также сначала инвертируем цвета в градацию серого, а далее с помощью морфологических операций рассеиваем контуры, чтобы они не «прилипали» друг к другу. После рассчитываем периметр контуров и отбираем среди них самые крупные. Определив контуры штрих кодов, нарезаем их на изображения и отправляем на распознавание библиотеке Zxing.
На этом этапе поступило дополнительное требование от заказчика, которое ранее не обсуждалось — потребовалось учитывать единицы измерений документов. К счастью, на каждой форме было отдельное поле с кодом, который отвечал за эту информацию. Мы точно знали, что есть два варианта: 384 для значений представленных в тысячах, а 385 — в миллионах.
К счастью это требование не существенно повлияло на ход разработки, и даже помогло при работе с последним типом документа — машиночитаемым. В начале новой итерации приступили к распознаванию отчетности нового образца.
![Изображение статьи](/uploads/cq5l_LI_Kemt_Rsr_X39_FDPI_75_Vtok_LZ_Md_H7_AID_Az9_XN_19f751fc4f.png)
Новый тип КНД не содержит таблиц, поэтому алгоритм поиска линейно структурированных столбцов уже не подходил. Такие документы знакомы, каждому кто сдавал ЕГЭ: на них нет четких линий, только пунктирные.
Решили отталкиваться от слова «Код», которое послужило точкой начала координат. Для этого учли все варианты написания слова. Далее с помощью морфологической операции отсекаем тексты, размытые ячейки, штампы, крупные штрихкоды. Все контуры отсекаем по оси X и Y, как и при работе с табличными документами. Далее оставшиеся контуры собираем в блоки по координатам, таким образом восстанавливаем линейную структуру с подобием строк и столбцов. Нарезанные участки распознаваем через Tesseract.
В итоге удалось распознать все формы и сервис был почти готов — оставалось только оптимизировать работу.
Оптимизация производительности
Приложение работало последовательно и очень медленно. Было много вычислений, которые зависели от скорости центрального процессора (CPU-bound). В итоге библиотеки OpenCV и Tesseract потребляли много ресурсов.
Чтобы ускорить систему вынесли обработку документа в отдельные параллельные процессы с многопоточностью, которую поддерживает Python.
Текущая реализация работает так, что предпроцессинг в первую очередь определяет, что перед ним — текст или изображение. После этого убирает шумы и запускает распознавание единиц измерения и тип документа, после чего понятно, какой алгоритм следует запустить. Таким образом документы стали распознаваться в десятки раз быстрее.
Сервис предстоит интегрировать с существующей CRM-системой, создать для него полноценное фронтенд-приложение с удобным пользовательским интерфейсом. Но конкретная цель проекта уже достигнута. Всего за полтора месяца работы одного программиста заказчик получил MVP-версию продукта, которую уже купил крупный федеральный банк.
Надеемся, этот материал послужит понятной иллюстрацией наших принципов и подходов к проектной работе и наглядно покажет, как достигаются цели бизнеса с помощью разработки программного обеспечения. Спасибо за внимание!