PassportVision — простой способ распознавать документы
Наверняка вам доводилось попадать в такую ситуацию: заходите в какое-нибудь учреждение (почта, банк, больница, кассы и т. п.), где для достижения ваших целей необходимо предъявить паспорт. И вроде очередь-то небольшая, всего 5 человек, но ждать придётся очень долго, ведь тётя Маша тратит по несколько минут на внесение данных с каждого паспорта в компьютер. Вам остаётся только наблюдать, как её указательный палец не спеша планирует над клавиатурой в поисках очередной клавиши.Мы были озадачены такой печальной ситуацией в современном обществе и написали программку PassportVision, которая умеет распознавать данные с разных документов и отдавать результат пользователю в удобной форме. Задача оказалась совсем не такой простой, как может показаться на первый взгляд: в ходе работы над проектом мы узнали очень много нового про отечественные документы, компьютерное зрение и пользовательские интерфейсы. Голова уже полна новыми идеями о дальнейшем развитии программы, но мы решили найти время, чтобы поделиться опытом и полученными знаниями.
Сегодня в выпуске:
Популярные заблуждения о паспортах Немного об используемых технологиях Наш подход к интерфейсу Как лучше всего отдать данные пользователю Казалось бы — что такого сложного, чтобы распознать данные с паспорта? В конце концов, 2014 год на дворе, человечество уже научилось распознавать текст с картинки. Применил пару фильтров, вызвал метод recognize () — и готово! Увы, всё не так просто. Прежде всего, стоит отметить, что паспорт гражданина РФ — это документ с особой спецификой. Мы даже не предполагали, насколько удивительными могут быть паспорта, пока не просмотрели несколько сотен примеров. Итак, вашему вниманию предлагается список заблуждений в лучших традициях заблуждений об именах и времени.
Все эти предположения ошибочны.
Текст в паспортах всегда набран одним шрифтом Есть только два-три шрифта, которыми набирают паспорта Ладно, но шрифт не может быть жирным или курсивным Ну, одновременно жирным и курсивным он точно не будет Все данные паспорта написаны одним шрифтом Никто не заполняет паспорта от руки Каждое поле паспорта находится в строго определённом месте Каждое поле паспорта находится вблизи своего строго определённого места Ну, по крайней мере фамилия не уползёт на три строчки вниз до места под отчество И никогда данные не пишутся поверх надписей бланка Ну, друг на друга-то данные точно наезжать не будут Текст всегда написан строго горизонтально Ладно, но угол наклона текста не превышает 10–15 градусов Все данные находятся под одним и тем же углом Текст всегда чёрного цвета Ну, хотя бы все надписи точно одного и того же цвета Паспорт всегда имеет машиночитаемую зону Машиночитаемая зона всегда присутствует на паспортах, выпущенных после 1 июля 2011 года Машиночитаемая зона всегда корректна и соответствует стандартам Все буквы в паспорте написаны в верхнем регистре Все данные паспорта написаны в одной регистровой стилистике Все даты всегда представлены в одном и том же формате Имя не может быть разбито на две строчки знаком переноса Все паспорта печатаются на одинаковых бланках с фиксированным фоном В месте рождения и в месте выдачи не может быть цифр Личная подпись не может быть поверх данных паспорта Все данные паспорта всегда присутствуют Лишних данных точно нет Место выдачи паспорта всегда укладывается в три строчки Если в поле «Имя» написано «Анна», то пол обязательно женский Данные паспорта со временем не стираются Паспорт не имеет механических повреждений Паспорт не может быть испачкан вареньем Сегодня о технологиях будет действительно немного. По ходу написания нашей программки мы столкнулись с большим количеством интересных задач: как в области компьютерного зрения, так и в области построения архитектуры и организации рабочего окружения. Данную тему мы планируем развернуть в отдельном посте, а сегодня только обозначим стек технологий.Основным языком программирования является C#. Возможно, кому-то такой выбор покажется странным, но он себя полностью оправдал. C# прекрасно подходит для создания масштабной архитектуры, а вёрстка сложного интерфейса даётся достаточно легко (спасибо вам, создатели WPF). Целевая аудитория сидит на Windows, так что с платформой проблем не возникло. Разные внутренние мелкие решаем делаем с помощью Python-скриптов.
Для обработки изображений используется OpenCV, для распознавания текста — Tesseract (а точнее, их обёртки — OpenCvSharp и Tesseract). Критичные по производительности алгоритмы написаны на C++, но таковых немного. Приходится много работать со сканерами, причём поддерживать как WIA, так и Twain (для последнего используем обёртку TwaintDotNet).
Общий workflow: система контроля версий — Git, просмотрщик репозитория — FishEye, continuous integration system — Bamboo, bug tracker — JIRA, code review system — Crucible (да, мы любим Atlassian).
Всё было бы хорошо, если бы мы со стопроцентной уверенностью могли распознать данные с любого паспорта. Но, увы, это не так. Если дать программе на вход скан хорошего паспорта на 300 dpi, то, скорее всего, она распознает его без ошибок. А вот если программа столкнётся с фоточкой паспорта печального качества (и вдобавок шрифт окажется очень бледным и под углом, а надписи — не на своих местах), то у нас возникнут проблемы. Поэтому не остаётся другого выбора, как попросить пользователя проверить распознанные данные. И тут очень важно спроектировать чертовски хороший и удобный интерфейс, который позволит сверхбыстро проверить все данные и поправить ошибки. Ведь если время, затраченное на проверку паспорта, будет сравнимо со временем ручного ввода данных, то вся задумка теряет смысл. Мы не претендуем на то, что нам удалось создать лучший в мире интерфейс для подобной задачи, но можем со всей ответственностью заявить, что он хорош. В конце концов, мы сами едим свою собачью еду используем нашу проверялку данных каждый день уже больше года. Поэтому все косяки и неудобства очень быстро бросались в глаза и просили себя исправить. Итак, на что же мы обратили особое внимание, чтобы жить стало легче: Навигация по полям. В главном окне слева размещается найденное изображение паспорта, а справа — распознанные поля. Для каждого поля на изображении паспорта подрисовывается рамка, при клике на которую мы переходим в нужное нам поле. Если у нас одно и то же поле присутствует на картинке в нескольких местах (например, серия и номер паспорта могут встретиться аж три раза), а результаты распознавания разные — то мы превращаем TextBox в ComboBox, чтобы можно было легко выбрать нужный вариант. Подозрительные символы. В процессе распознавания мы помечаем некоторые символы как подозрительные — это такие символы, в правильности распознавания которых мы не очень уверены. Если ошибки и есть, то они почти наверняка находятся среди подозрительных символов. Поэтому мы раскрашиваем их красненьким и обеспечиваем удобную навигацию: по хоткею можно перейти к следующей или предыдущей группе подозрительных символов. Причём навигация достаточно интеллектуальна: если в поле почти все символы подозрительные, то при переходе к ошибке мы выделяем не только красные буквы, а вообще всё поле целиком. Всплывающие подсказки. Изначально, чтобы проверить какое-нибудь поле, нужно было сначала посмотреть на поле, потом перевести взгляд на картинку с паспортом, найти там это поле. Потом обратно на TextBox, потом обратно на паспорт. Потом подумать и соотнести текст. Это долго и неудобно. Поэтому прямо рядом с TextBox-ом мы делаем всплывающую подсказку с соответствующим фрагментом паспорта. А чтобы искать нужные символы было ещё удобней, мы обводим на картинке выделенный пользователем текст. Если пользователь уже успел написать в поле своих символов, то программа умеет неплохо додумывать, где бы они должны быть на изображении и всё равно обводит. Автогенерация формы. А что, если пользователю не нужны все поля? Скажем, требуется только ФИО. Зачем заставлять пользователя проверять все результаты? К счастью, список полей можно настроить так, чтобы отображались только те из них, которые вам действительно нужны. А знаете, вообще, мы очень долго пилили UI, очень много всего было сделано, кратко не расскажешь. Лучше мы потом сделаем отдельный пост, в котором подробно расскажем про все юзабилити-решения в программке. Если вы занимаетесь проектированием интерфейсов, то вам, наверное, будет интересно почитать не только про конечный результат, но и про процесс — как мы к такому интерфейсу пришли, почему сделали так, а не иначе.
Ну, казалось бы, всё готово: изображение обработано, текст распознан, пользователь всё проверил. Чего ещё для счастья не хватает? Давайте подумаем: раз данные распознаются, значит, это кому-то нужно. И, наверное, этот кто-то планирует их потом использовать. И, надо полагать, использовать он их будет в какой-то своей программке. А значит, распознанные данные нужно как-то в эту программку передать. Встаёт логичный вопрос: как мы будем это делать? PassportVision Office. Увы, программок существует много, и для каждой нужно искать свой подход. Социологический опрос показал, что большая часть целевой аудитории вводит паспортные данные в документы, которые подготавливаются в MS Word. Поэтому мы сделали отдельную редакцию PassportVision для работы с Word:
Идея в следующем: на риббон добавляется специальная вкладка, с помощью которой можно сформировать шаблон со специальными метками. Итак, данные распознались, пользователь их проверил, щёлкнул ОК. И, как по волшебству, данные вставляются в шаблон вместо заранее подготовленных меток. Достаточно часто документ оформляется с участием нескольких действующих лиц, поэтому для каждой метки можно указать, к какому лицу относится данный паспорт. Кладём первый паспорт в сканер, затем второй — и наш документ готов! Маркеры ведут себя достаточно интеллектуально. Например, для даты можно указать формат представления, а окончания отдельных слов могут зависеть от пола человека.
PassportVision Adaptive. Увы, не все используют Word, в мире существует ещё множество программ, в которые можно вводить данные. Для всех писать отдельные редакции не очень целесообразно, поэтому мы написали универсальную редакцию, которую можно приспособить к любому приложению. PassportVision Adaptive эмулирует работу пользователя: где какую клавишу нажать, куда мышкой кликнуть. Нужно только сделать специальный макрос, в котором вы объясните программе, чтобы вы сделали, если бы вам понадобилось использовать результаты распознавания. Да, возможно, макрос для сложного ПО не так просто сделать, но это одноразовая операция. Разок всё настроили, и данные попадут в нужные места вашей целевой программы по нажатию специальных клавиш. А если проблемы с написанием макроса всё-таки возникают — мы помогаем всем клиентам с ними справиться.
PassportVision SDK. А некоторые пользователи хотят использовать результаты распознавания в собственном ПО. Если вы разработчик, то вы можете использовать специальное API, чтобы получить все данные в нужном формате. Если ваше приложение разрабатывается не под .NET, то не волнуйтесь: мы заботливо завернули API в COM-обёртку, так что SDK можно использовать из-под C++ и Delphi.
Другие редакции PassportVision. Разработка идёт полным ходом, мы стараемся сделать много разных редакций программы, чтобы каждый мог подобрать удобное для себя решение. Например, скоро на экранах появится версия под 1С (там тоже часто возникает потребность в вводе паспортных данных), а Adaptive-версия пополнится специальными макросами для веб-форм (нужно будет просто указать, в какие поля что заполнять, а волшебный JavaScript сделает всё остальное).
Если вы хотите использовать нашу программку для того, чтобы избавить людей от ручного ввода паспортных данных и сделать мир лучше, то можете связаться с нами, и мы расскажем про PassportVision подробнее. А если вы не заинтересованы в автоматизации документооборота, но интересуетесь тем, как идёт разработка ПО в разных компаниях, то специально для вас скоро будут посты с подробной информацией про организацию работы, компьютерное зрение и подходы к юзабилити. Разработка активно продолжается, сейчас мы добавляем поддержку разных видов документов (загранпаспорта, свидетельства о рождении и т. д. — они уже работают в альфа-режиме), новые редакции продукта и клёвые фичи. По ходу попадаются очень интересные технические проблемы, для которых приходится придумывать увлекательные пути решения. Если вам будет интересно, то мы также опубликуем посты о решении наиболее любопытных задачек — надеемся, кому-нибудь этот опыт будет полезен.