Гуляя по просторам интернета, зашёл на один высокопосещаемый древний сайт рунета. Для того, чтобы скачать файлик с этого сайта, нужно угадать вот такую капчу:

В очередной раз видя картинку с цифрами — решился. В голове уже давно проносились мысли, сломать какую-нибудь капчу :)
Ставлю себе задачу: Написать скрипт, который будет расшифровывать показанную капчу и выплевывать драгоценные циферки.
Название сайта специально не привожу — сами догадаетесь :)
Итак, поехали!
Для начала надо просмотреть как можно больше таких капч, чтобы выявить сходства/различия, какие-то закономерности. Для этих целей я скачал порядка 50 капч. Среди них можно выбрать основные, которые содержат максимум различий:

Вообще люблю всматриваться в числа, так как в своё время много времени посвятил изучению математики :)
Рассматриваем, и понимаем:
В голове в течение получаса прокручиваются варианты, понятно одно: картинку желательно обрезать, и поскольку используются шрифты одни и те же, и они никак не меняются, можно использовать "отпечатки". Под этим термином я понимаю то, что цифры у нас уже где-то лежат в базе, и нам нужно сверять их с картинкой.
Пришёл к такому решению:

Для тестирования я скачал 200 таких капч, на моём домашнем ПК скрипт разобрал их ~ за 19 секунд.
Это примерно 10 капч в секунду.
Из этих 200 не было выявлено ни одной ошибки, скрипт отлично отработал :)
Я написал класс CapCrack, который разбирает капчу.
Если есть желание более подробно разобраться в алгоритме, или протестировать на своём ПК, можете взглянуть на код: cap_crack.zip
На этом успехе я не остановился и решил попробовать написать скрипт для скачки файлов с сайта, в автоматическом режиме, но это уже совсем другая история :) достойная отдельной статьи…
P.S. Это мой первый пост на Хабре, так что прошу строго не судить :)

В очередной раз видя картинку с цифрами — решился. В голове уже давно проносились мысли, сломать какую-нибудь капчу :)
Ставлю себе задачу: Написать скрипт, который будет расшифровывать показанную капчу и выплевывать драгоценные циферки.
Название сайта специально не привожу — сами догадаетесь :)
Итак, поехали!
Анализируем картинку
Для начала надо просмотреть как можно больше таких капч, чтобы выявить сходства/различия, какие-то закономерности. Для этих целей я скачал порядка 50 капч. Среди них можно выбрать основные, которые содержат максимум различий:





Вообще люблю всматриваться в числа, так как в своё время много времени посвятил изучению математики :)
Рассматриваем, и понимаем:
- картинка черно-белая, в формате gif
- размер картинки может меняться, но цифры всегда стоят по центру (правда вертикально они выравнены не очень по центру)
- используется градиент, его направление может меняться в 2 стороны
- кроме градиента есть, "угловой градиент" (так я его обозвал, не пинайте :) ), тот который идёт из угла под углом 45 (ещё раз не пинайте :) ) это просто линия-диагональ, в моём понимании
- всего я выявил 6 разных шрифтов написания (точнее 3, другие 3 являются их наклонными версиями)
- пиксели всех цифр не темнее цвета #606060, но не одного цвета
- цифр 3-5 в капче, высотой не выше 14px
Ищем решение
В голове в течение получаса прокручиваются варианты, понятно одно: картинку желательно обрезать, и поскольку используются шрифты одни и те же, и они никак не меняются, можно использовать "отпечатки". Под этим термином я понимаю то, что цифры у нас уже где-то лежат в базе, и нам нужно сверять их с картинкой.
Пришёл к такому решению:
- заводим массив с отпечатками
- обрезаем картинку со всех сторон, лишнее надо выбросить
- удаляем лишние цвета — это градиент и угловой градиент
- проходим по всем пикселям слева-направо сверху-вниз, и если цвет пикселя соответствует цвету цифры (>= #606060), то сверяем с отпечатками, со всеми по порядку
Реализация
- Готовим отпечатки
Всего их получается 6 * 10 = 60 штук, их помещаем в массив. Отпечатки я делал по цифрам из капч, для каждого шрифта. Это просто массив строчек, где в каждой строчке буквой "x" отмечен пиксель цифры.
Например, вот так выглядит цифра 2 первого шрифта:
- Открываем картинку
Это делается просто, черезimagecreatefromgif($filename);
- Определяем направление градиента
Надо определить, в какую сторону смотрит градиент, это потребуется в следующих пунктах.
Это сделать просто, достаточно определить цвет первого пикселя (0, 0)
$color = imagecolorat($image, 0, 0) < 0x20 ? 'black' : 'white' ;
- Вычищаем угловые градиенты
Здесь нужно почистить угловые линии-градиенты, причём это лучше cделать до обрезания капчи.
Вот тут как раз нам нужно знать направление градиента, чтобы вычистить с нужной стороны.
Путём анализа выявляем, что перепад цвета с пикселя (1, 1) на (2, 2) и т.д. не может быть больше #202020.
Вычистить — это значит закрасить черным цветом, т.к. все цифры у нас не ниже цвета #606060.
Получаем такую картинку:
php-код вы можете просмотреть в аттаче (см. ссылку ниже)
- Режем капчу
На этом этапе отрезаем слева и справа по 12px.
Т.к. высота цифры не выше 14px, то снизу и сверху обрезаем лишнее, в зависимости от высоты всей капчи.
Получаем:
- Чистим градиент
Со всех сторон всё же остаются лишние полоски градиента. Их надо так же вычистить.
Проходим сперва сверху-вниз, потом слева-направо, берём цвет полоски, и если она сплошная (длина > 10px) и одного цвета — то считаем что это полоска градиента, и вычищаем её.
Итого получаем:
Но в некоторых случаях (~ 5%) всё же могут оставаться вот такие шумы:
Правда они нам всё равно не помешают :) Т.к. их цвет уже не подходит под цвет цифр.
- Сверяем с отпечатками
Проходим по всем пикселям сверху-вниз слева-направо, цвет которых подходит под цвет цифр и сверяем со всеми отпечатками по-порядочку.
Результаты

Тестирование
Для тестирования я скачал 200 таких капч, на моём домашнем ПК скрипт разобрал их ~ за 19 секунд.
Это примерно 10 капч в секунду.
Из этих 200 не было выявлено ни одной ошибки, скрипт отлично отработал :)
Итоги
Я написал класс CapCrack, который разбирает капчу.
Если есть желание более подробно разобраться в алгоритме, или протестировать на своём ПК, можете взглянуть на код: cap_crack.zip
На этом успехе я не остановился и решил попробовать написать скрипт для скачки файлов с сайта, в автоматическом режиме, но это уже совсем другая история :) достойная отдельной статьи…
P.S. Это мой первый пост на Хабре, так что прошу строго не судить :)