Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Идентификация бланков психологического тестирования с нуля

Anna | 18.06.2014 | нет комментариев
Три месяца назад ко мне обратился отличный товарищ и сотрудник по работе с просьбой написать небольшую программу для проведения психологического тестирования. Я, до этого писавший экстраординарно для мелких нужд офисной автоматизации на vba, vb, vb.net, решил воспользоваться моментом и за время плана подучить C#. К слову, план примитивный, каждого 5 психодиагностических методологий. Позднее оказалось, что мечта его — система распознавания бланков этих методологий. Обстановка усложнилась. Стало ясно, что основное число времени я потрачу на идентификация.

Безусловно же, я не имел навыка работы с изображениями, и распознаванием и начал поиск библиотек для распознавания бланков. К сожалению обнаружить чего-либо бесплатного не удалось. Следственно я засучил рукава и принялся писать самосильно.Я не буду писать код тут, так как считаю, что основная задача при создании сходственной системы заключается в алгорифме работы.
Итак…
Для начала были сделаны бланки. Для всякой методологии свой, но отличаются они только числом вопросов и числом результатов в вопросах.
image

Бланки с моих слов сотворил отличный товарищ и сотрудник по работе. Первоначально они были сделаны в Excel и сохранены в формат PDF.
Самая значимая деталь в бланке — черные квадраты (я назвал их маркеры). Верхний центральный маркер необходим для определения где верх, а где низ бланка. При психодиагностике испытуемому предлагается нарисовать диагональный крестик в требуемой ячейке. При этом предполагается, что:
1. ?рус образования испытуемого может быть низким.
2. Это не экзамен, и испытуемый заблуждается, много раз перечеркивает.
3. Испытуемый пользуется карандашами, шариковыми, гелевыми ручками различного цвета чернил.
4. Испытуемый нехорошо поддается инструктированию и взамен крестиков ставит галочки.

Сейчас поэтапная формализация самой задачи работы с системой распознавания бланков тестирования:
1. Снять изображение бланка с устройства ввода.
2. Привести изображение в некоторый типовой вид.
3. Обнаружить на изображении ячейки, которые нужно распознать.
4. Распознать ячейки.
5. Сберечь результаты.

Сейчас обо каждому по порядку.
1. Приобретение изображения для обработки.
Я предпочел планшетный сканер как особенно недорогое и распространенное средство приобретения изображения. В родной для C# операционной системе существуют два основных API для работы со сканерами:TWAIN и WIA. С WIA задач не появилось. Спецтехнология отменно поддерживается в Windows, отлично документирована и в сети имеется много примеров. Самое трудное было задать параметры сканирования.

Неприятная вещь спецтехнологии WIA это список поддерживаемых устройств. Их немного. Следственно пришлось добавить вероятность работы с TWAIN сканерами. Я применял бесплатную библиотеку TwainDotNet. Исключительный ее недочет — проверка сканера на совместимость в начале сканирования. Ветхие сканера, скажем не проходят проверку из-за отсутствия функций автоповорота изображения. Рассматривая открытость начальных кодов, я стремительно поправил расположение дел.

При применении обоих API, я отключал их типовые GUI. Задавал размер изображения A4 и разрешение 100 DPI. Для полноты вероятностей я инкапсулировал в свой класс Scanner вероятность выбора изображения из файла.

2. Нормализация изображения.
Приведение изображения к универсальному виду поделена на этапы:
1. Приведение изображения к разрешению 100 DPI.
2. Бинаризация изображения.
3. Нахождение маркеров.
4. Поворот изображения.
Для работы с изображениями я применял AForge.NET Framework. Это даром и комфортно, так как не необходимо писать бесчисленные алгорифмы работы с изображениями, тем больше, что для скорости работы писать бы пришлось опасный код, а я новичок в C#. В последующем я буду ссылаться на классы именно этой библиотеки.
Выходит, в начале входящее изображение приводится к 100 DPI. Меньшее разрешение грозится задачами при бинаризации, а большее загвоздками скорости обработки. После этого переводим изображение в цветовой режим «Градации серого». Для этой операции используем класс GrayScale. Для бинаризации изображения я применял BradleyLocalThresholding. Алгорифм отменно справляется с небольшими завалами яркости.
Одним из трудных нюансов удачного распознавания является положительная ориентация изображения. Поворот на 3-4 градуса, и все пропало. Потоковой подачи нет, сканер планшетный, бланки мятые. В всеобщем, для определения угла поворота бланка я применял DocumentSkewChecker. А для поворота изображения RotateBilinear, потому что он стремительный. Такой поворот выравнивал изображение в диапазоне 0-45 градусов, но оно могло оставаться опрокинутым. Следственно нужно обнаружить маркеры и по центральному определить верх бланка.
Для поиска объектов на изображении я удачно применил BlobCounter. Для определения маркеров я отфильтровал все обнаруженные объекты по размерам и по свойству Fullness, установив порог 0.8. И если не находил сверху 3 маркеров — переворачивал изображение на 180 градусов.
Такими нехитрыми манипуляциями все изображения приводятся к цельному виду и формату.

3.Нахождение ячеек результатов для распознавания
Для нахождения ячеек результатов был использован самый примитивный метод. Я взял эталонный пустой бланк всякой методологии и сберег в базе данных центр первой (левой) ячейки всякого вопроса. Так же сберег расстояние между центрами ячеек всякого вопроса и размеры ячеек. Таким образом, для определения областей распознавания я легко брал данные из базы. Тут необходимо сделать два дюже значимых примечания. Если сканируемый бланк мятый, то области распознавания будут неверны, так как эталонный бланк ровный. Процент ошибок при этом будет слишком крупен. Вот что получается, если это игнорировать:

Решается достаточно легко. Область первой ячейки расширяется от центра. После этого в этой области я ищу объект с поддержкой BlobCounter. Позже нахождения ячейки внутри расширенной области, область сжимается касательно обнаруженного центра. Выглядит все приблизительно так:

Эти манипуляции производятся только с первой ячейкой всякого вопроса, координаты остальных ячеек пересчитываются касательно ее.
Так же размеры изображения (области распознавания) могут незначительно изменяться, следственно данные о ячейках сберегать необходимо не в безусловных координатах на начальном изображении а их позицию касательно маркеров. Это вторая значимая функция маркеров.
Стоит подметить, что находить области распознавания дозволено и не зная их координаты. Это делается на основе вертикальных и горизонтальных гистограмм яркости. Впрочем я не применял данный алгорифм, и описывать его не буду.

4. Идентификация ячеек
Вот тут я и завязнул. Идентификация, по сути это задача систематизации. С учетом стоящей задачи имеется 3 класса ячеек:
1. Пустая (free).
2. Подмеченная испытуемым (cross).
3. Ложно подмеченная испытуемым (miss).
С классом free все ясно. Это безусловно пустая ячейка, не тронутая пером испытуемого. Но у класса cross теснее есть задачи: в ячейке может находится что желательно. Не смотря на чудесный инструктаж, лица, проходящие тестирование не слишком рачительно выписывают диагональные крестики. Добавочно испытуемые заинструктированы заштриховывать ячейку, если они ошиблись и хотят поправить вариант своего результата. Это и есть класс miss.
По огромному счету у меня было два варианта подхода к систематизации: распределение ячеек по ярусу яркости и применение способов машинного обучения. Как ветхий поклонник нейронных сетей (писал как-то наvba) я взял библиотеку Encog и обучил многослойный персептрон на 20 заполненных бланках тестирования. И получил ошибку 15-35% ложных результатов. Стало ясно, что нужно применять больше тонкие алгорифмы (сверточные сети, ансамбли сетей, комбинация алгорифмов обучения). При этом нужно было предъявить сети разные варианты классов ячеек, скажем такие:

В результате всех проб и ошибок я возвратился к систематизации по яркости. Только не по сумме яркостей всех пикселей ячейки, так как получается не слишком Эмоционально. Я применял классVerticalIntensityStatistics для вертикальной гистограммы сумм яркостей пикселей ячейки. Ниже гистограмма класса cross и гистограмма класса free:

Я брал значения гистограммы для вертикальных пикселей с 8 по 17 (обрезал минимумы) и применял формулу: порог = 1 — среднее(значение гистограммы для яркости) / максимальная яркость. По значению порога я определял класс ячейки. Как правило, классы разделялись так:
от 0 до 0.18 класс free,
от 0.18 до 0.6 класс cross,
от 0.6 до 1 класс miss.

5. Сохранение результатов.
Так как система не механическая, а автоматизированная возникающие при распознавании ошибки допускается исправлять вручную. Позже этого ID ячейки класса cross отправляется в базу.
Наружно интерфейс распознавания выглядит так:

В результате:
За три месяца постижения языка C# я сделал бесплатное приложение для распознавания бланков психологического тестирования. Заблаговременное применение показало пропускную способность приблизительно 1 бланк за полторы минуты. Это дюже недурно, рассматривая ручной ввод личных данных перед распознаванием.
Теперь я с удовольствием правлю свой ужас код, и даже, что проступка таить, пишу документацию с целью выдать продукт людям. А заодно оптимизирую процесс систематизации.
А может быть эта статья подстегнет какого-либо профи на написание хорошего бесплатного фреймворка для распознавания бланков, правда бы для таких примитивных нужд как у моего отменного товарища и сотрудники по работе…

 

Источник: programmingmaster.ru

 

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB