IITG-Captcha-Solver-OpenCV-TensorFlow
Решение капчи веб-почты IITG с помощью простой нейронной сети прямого распространения
Вы можете полностью воссоздать мою среду conda, используя файл конфигурации среды conda_env_pyopencv.yml.
Создать среду можно следующим образом: conda env create -f conda_env_pyopencv.yml
Этот проект пытается обучить контролируемую модель, которая может взломать систему капчи веб-почты IIT Guwahati. Ниже приведён пример изображения капчи:
Предварительный результат с использованием базовой FFNN (регрессия Softmax + перекрестная энтропия) с 12000 обучающими входами и 3000 тестовыми входами даёт точность около 95%. Аналогичные NNets с одним или несколькими скрытыми слоями могли бы работать значительно лучше.
Проект был полностью реализован на Python.
Как видно из примера, капча пытается скрыть своё содержимое, добавляя много случайных «солевых и перечных» шумов к отображаемым символам. Символы дополнительно затемняются неполным рендерингом. Только тень символа (с воображаемым источником света в верхнем левом углу изображения) отображается на капчу, что делает немного сложным чёткое выделение отдельных символов.
Первым шагом было очистить изображение от шума, чтобы сделать сегментацию изображения на символы намного проще. Сначала изображение было преобразовано в оттенки серого, а затем применён порог, так что результирующее изображение имеет только чёрные или белые пиксели. Некоторые исследования в интернете и тестовые прогоны показали, что medianBlur хорошо справляется с удалением случайных пикселей на изображении.
Ниже представлен образец вывода изображения после пороговой обработки.
Ниже представлен образец вывода изображения после применения medianBlur.
Чтобы сделать окончательный результат ещё более чистым, был применён раунд эрозии и расширения. Ниже показан результат применения одной итерации эрозии, за которой следует расширение с использованием ядра 2x2.
К счастью, капча всегда содержит ровно 5 символов (алфавиты всегда заглавные), что помогает нам сделать некоторые первоначальные предположения о сегментации. В качестве начального теста я подсчитал количество белых пикселей в изображении на столбец и построил график, где ось X обозначает столбец на изображении, а ось Y — количество белых пикселей в этом столбце. Ниже приведён упомянутый выше график для образца изображения:
Было ясно, что простой алгоритм кластеризации должен эффективно группировать символы в отдельные кластеры. Я преобразовал вывод предыдущей операции medianBlur в двоичную матрицу того же размера, что и изображение, где 0 обозначает чёрный пиксель, а 1 — белый пиксель. Затем я применил k-means с K=5 для всех пар (i,j) матрицы, значение которой было равно 1 (т. е. белые пиксели). Результаты были положительными, почти все символы всегда сегментировались в отдельные кластеры.
Ниже приведён результат цветовой кодировки кластеров, идентифицированных k-средствами. Белая вертикальная полоса проведена по координате x центра соответствующего кластера.
После того как пиксели символа были идентифицированы, вокруг центра его кластера была определена ограничивающая рамка размером 65x45 пикселей, и символ был извлечён из капчи. Эти изображения размером 65x45 стали основой обучения и тестирования модели.
Было необходимо собрать большое количество обучающих данных. Данные собирались для надлежащего обучения модели (с учителем), и поэтому я создал страницу PHP, которая отображает случайные капчи и позволяет пользователю ввести полученный результат в текстовое поле. Затем изображение и результаты были сохранены в систематизированном виде.
Ниже приведён скриншот страницы сбора данных на PHP.
… | … |
---|---|
Всего собрано капч | 3016 |
Всего символов собрано (по 5 на капчу) | 15080 |
Далее приведены статистические данные о собранных символах по отдельности.
… | … | … | … |
---|---|---|---|
2 | 559 | g | 578 |
3 | 575 | h | 526 |
4 | 517 | k | 536 |
5 | 553 | m | 539 |
6 | 535 | n | 538 |
7 | 512 | p | 559 |
8 | 489 | r | 520 |
9 | 548 | s | 553 |
a | 570 | t | 535 |
b | 534 | v | 526 |
c | 515 | w | 517 |
d | 536 | x | 555 |
e | 504 | y | 565 |
f | 527 | z | 559 |
В качестве предварительного шага я разработал простую FFNNet без скрытых слоёв. Эти шаги были выполнены на основе примера MNIST из документации TensorFlow.
Каждое входное изображение должно было быть полностью введено в нейронную сеть. Следовательно, общее количество нейронов, необходимых во входном слое, составляло 64 * 45 = 2925
.
После изучения собранных данных выяснилось, что в капчах использовались не все символы и цифры английского алфавита. Всего в капче появилось только 28 различных символов и цифр. Поэтому выходной слой NNet был создан с 28 нейронами.
Веса должны были быть изучены для каждого пикселя и каждого выходного класса, поэтому требовалась матрица весов размером 2925 x 28
вместе с матрицей смещения 28 x 1
.
Выходной y будет представлять собой матрицу 28x1
, где каждая строка сопоставляется с одним из 28 ожидаемых символов в капче. Вектор y в идеале должен содержать 1 для правильного выходного символа и 0 для всех остальных. Для фактических выходных данных мы пропускаем их через слой softmax, чтобы преобразовать выходные данные в распределение вероятностей и выбрать наиболее вероятный выходной сигнал.
В целом шаг вперёд будет выглядеть примерно так:
y = Wx + b
Функция ошибки была определена с использованием меры кросс-энтропии.
Для обратного распространения использовался градиентный спуск со скоростью обучения 0,5.
Из 15 000 собранных отдельных символов для обучения NNet использовалось 12 000 случайных символов.
Каждый символ изображения был преобразован в вектор 2925x1
, а его ожидаемый вывод — в вектор 28x1
. Tensor Flow автоматизирует шаг обратного распространения, поэтому требовалось только выбрать случайные пакеты по 100 из 12 000 входных данных и повторить шаг обучения в течение 1000 итераций.
Результатом стала обученная матрица веса и смещения, которую TensorFlow разрешил сохранить в файле для последующего восстановления.
Примечание: Я также установил библиотеки CUDA, которые хорошо работали с TensorFlow, значительно сокращая время обучения. Моя видеокарта — NVidia GTX-950m.
Оставшиеся 3000 символов из собранных данных были использованы для тестирования обученной модели. Точность составила около 95%, что неплохо для базовой модели, но, безусловно, может быть улучшено в дальнейшем.
Ниже приведён снимок экрана с результатом работы модели при получении образца капчи для веб-почты. Результаты точны в большинстве случаев.
Модель имеет тенденцию к сбою в распознавании разницы между 2 и z. Хотя количество собранных 2 и z во время сбора данных было равным, возможно, случайные выборки, выбранные для обучения NNet, имели больше z, чем 2, что привело к смещённому результату. Создание более глубокой NNet действительно обещает более высокую точность. Однако у меня нет интуитивного или математического объяснения этому. Добавление... Будущей целью этого проекта станет скрытый слой для повышения точности. Любые вклады и PR приветствуются, если они сначала будут подробно обсуждены со мной.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )