Уже не помню, как я наткнулся на статью habr.com/ru/post/464337, но она запала мне в мозг и не давала покоя вплоть до минувшего дня. Несколько раз я пытался понять происходящее, пару раз пытался заставить это работать, но безрезультатно: я совершенно ничего не понимаю в нейронных сетях и даже программирую не как настоящий программист.
Наконец, несколько дней назад я осилил запуск питона и решил, а почему бы и не да и всё такое. Забыв всё, что я прочитал в упомянутой статье, пошёл своим путём.
Вспоминая несметное количество решённых капч, я предположил, что можно решать их банальным сравнением с маской, что и подтвердилось впоследствии.
Во-первых, вручную собрал тестовые капчи (83 штуки) и дал им очевидные имена. Скриптом превратил их в битовые изображения.
Цифры в капчах бывают двух размеров по высоте с разницей в 1 пиксель и трёх-четырёх начертаний по ширине. Базовая линия всех символов во всех капчах одинаковая. Всё это разнообразие, как оказалось, имеет некую общую маску, сравнение с которой однозначно идентифицирует цифру. Вырезал по нескольку (сначала – по 5, потом добавлял ещё по 1-2; с «4» провозился дольше остальных) одинаковых цифр из разных капч. В paint.net наложил их друг на друга и получил общую для всех начертаний каждой цифры маску.
Единственную проблему обнаружил позднее, уже при массовой обработке, но успешно её обошёл
Кроме этого небольшого недоразумения шум совершенно не мешает. Итогом этого этапа стал набор из 9 масок. Два вложенных цикла и вуаля! – все мои 83 капчи распознаются на ура!
Дальше встал вопрос: где взять большой набор капч для проверки. И я скачал «29 000 капч» из упомянутой статьи.
Так что пришлось расчехлить гугл и самостоятельно намайнить идеальных капч: за ночь набралось 3224 файла, в том числе 49 абсолютно пустых, как выяснилось позднее. Cпасибо Ганеше за код.
Собственно распознавание капчи укладывается в 26 строк скучного кода на питоне. Из внешних модулей нужен только PIL. Скорость работы – примерно 1000 капч в минуту (одна тысяча капч в минуту) на стареньком Core 2 «четыре ядра четыре гига». На более приличном восьмипоточном i5 заметно быстрее, хотя дело, конечно, не в потоках. Распознавание 100% или очень к тому близко: выборочная проверка не показала ошибок.
Конечно, всё это не интересно в смысле нейронных сетей и прочих блокчейнов, но имеет совершенно определённое преимущество перед предложенным ранее вариантом: скорость и точность. Так же верно и то, что любое изменение параметров капчи – гарнитуры или размера шрифта, вид шума и т.д. – приведёт к полной неработоспособности моего решения.
Скачать архив с капчами с Яндекс.Диска (14МБ).
Наконец, несколько дней назад я осилил запуск питона и решил, а почему бы и не да и всё такое. Забыв всё, что я прочитал в упомянутой статье, пошёл своим путём.
Вспоминая несметное количество решённых капч, я предположил, что можно решать их банальным сравнением с маской, что и подтвердилось впоследствии.
Во-первых, вручную собрал тестовые капчи (83 штуки) и дал им очевидные имена. Скриптом превратил их в битовые изображения.
Цифры в капчах бывают двух размеров по высоте с разницей в 1 пиксель и трёх-четырёх начертаний по ширине. Базовая линия всех символов во всех капчах одинаковая. Всё это разнообразие, как оказалось, имеет некую общую маску, сравнение с которой однозначно идентифицирует цифру. Вырезал по нескольку (сначала – по 5, потом добавлял ещё по 1-2; с «4» провозился дольше остальных) одинаковых цифр из разных капч. В paint.net наложил их друг на друга и получил общую для всех начертаний каждой цифры маску.
Единственную проблему обнаружил позднее, уже при массовой обработке, но успешно её обошёл
при помощи костыля
Первоначально, распознавание шло по порядку — по исходному образу прогонялась маска «1», потом «2» и т.д. до «9». Оказалось, что в некоторых случаях, когда толстая линия шума накладывается на ножку «4», то одинаково успешно распознаются и «4», и «1». Пришлось, во-первых, изменить порядок применения масок с «123456789» на «423156789» и во-вторых, при успешном распознавании «4» заливать это место белым, чтобы гарантированно исключить «1».
Кроме этого небольшого недоразумения шум совершенно не мешает. Итогом этого этапа стал набор из 9 масок. Два вложенных цикла и вуаля! – все мои 83 капчи распознаются на ура!
Дальше встал вопрос: где взять большой набор капч для проверки. И я скачал «29 000 капч» из упомянутой статьи.
Однако, это оказалось пустой тратой времени.
Во-первых (точнее, во-вторых, т.к. я обнаружил уже позднее), там присутствуют идентичные файлы: один и тот же файл сохранён под разными именами: 6503 раза, 5420 раз, 760 и т.д. – т.е. всего уникальных файлов 14882, что, впрочем, тоже немало.
Во-вторых, а на самом деле – во-первых, – это не настоящие капчи. Сайт отдаёт картинку в формате PNG, а в наборе – JPG, причём крайне плохого качества, причём со сдвигом. Могу предположить, что именно такова была цель автора – статья же недаром называется «”зашумленная” капча».
Во-вторых, а на самом деле – во-первых, – это не настоящие капчи. Сайт отдаёт картинку в формате PNG, а в наборе – JPG, причём крайне плохого качества, причём со сдвигом. Могу предположить, что именно такова была цель автора – статья же недаром называется «”зашумленная” капча».
Так что пришлось расчехлить гугл и самостоятельно намайнить идеальных капч: за ночь набралось 3224 файла, в том числе 49 абсолютно пустых, как выяснилось позднее. Cпасибо Ганеше за код.
Собственно распознавание капчи укладывается в 26 строк скучного кода на питоне. Из внешних модулей нужен только PIL. Скорость работы – примерно 1000 капч в минуту (одна тысяча капч в минуту) на стареньком Core 2 «четыре ядра четыре гига». На более приличном восьмипоточном i5 заметно быстрее, хотя дело, конечно, не в потоках. Распознавание 100% или очень к тому близко: выборочная проверка не показала ошибок.
Конечно, всё это не интересно в смысле нейронных сетей и прочих блокчейнов, но имеет совершенно определённое преимущество перед предложенным ранее вариантом: скорость и точность. Так же верно и то, что любое изменение параметров капчи – гарнитуры или размера шрифта, вид шума и т.д. – приведёт к полной неработоспособности моего решения.
Скачать архив с капчами с Яндекс.Диска (14МБ).
Исходный код
from PIL import Image, ImageTk
def recognize(filepath):
Zlist = [] # [(x1, z1), (x2, z2), (x3, z3), etc.] - position and digit
captcha = ""
originalimage = Image.open(filepath).convert('L').point(lambda x : 255 if x > 20 else 0, mode='1').convert('1').convert('RGBA')
if originalimage.getextrema() == ((0, 0), (0, 0), (0, 0), (255, 255)):
return("empty image")
for z in [4, 2, 3, 1, 5, 6, 7, 8, 9]: # reorder to exclude false 1 on 4
mask = Image.open('mask' + str(z) + '.png').convert('RGBA')
previ = 0
for i in range(15, 120): # no digit in left part
resultimage = Image.alpha_composite(originalimage.crop((i, 0, i + 30, 0 + 50)), mask)
if resultimage.getextrema() == ((0, 0), (0, 0), (0, 0), (255, 255)):
if z == 4: # delete 4 to exclude false 1 on 4
maskx = Image.open('mask4x.png').convert('RGBA')
originalimage.paste(Image.alpha_composite(originalimage.crop((i, 0, i + 30, 0 + 50)), maskx), (i, 0))
if previ == 0 or i > previ + 15: #no digit closer then 15 px
Zlist.append((i, z))
if len(Zlist) == 5:
Zlist.sort()
for z in Zlist:
captcha = captcha + str(z[1])
return(captcha)
previ = i
i = i + 15 #skip a little
Zlist.sort()
return(str(Zlist)) #if less then 5 digits recognized
def main():
captcha = recognize(entry.path)
#----------------------------------------------#
# в архиве полный код для массовой обработки #
#----------------------------------------------#
main()