![счастливая капча](https://habrastorage.org/webt/4z/eb/8b/4zeb8bn8i97b4662ssgxu8x_rgk.jpeg)
Наконец, несколько дней назад я осилил запуск питона и решил, а почему бы и не да и всё такое. Забыв всё, что я прочитал в упомянутой статье, пошёл своим путём.
Вспоминая несметное количество решённых капч, я предположил, что можно решать их банальным сравнением с маской, что и подтвердилось впоследствии.
Во-первых, вручную собрал тестовые капчи (83 штуки) и дал им очевидные имена. Скриптом превратил их в битовые изображения.
![](https://habrastorage.org/webt/ps/kq/ku/pskqkuzoyxdkyh8d4d8ty_pkq_m.png)
Цифры в капчах бывают двух размеров по высоте с разницей в 1 пиксель и трёх-четырёх начертаний по ширине. Базовая линия всех символов во всех капчах одинаковая. Всё это разнообразие, как оказалось, имеет некую общую маску, сравнение с которой однозначно идентифицирует цифру. Вырезал по нескольку (сначала – по 5, потом добавлял ещё по 1-2; с «4» провозился дольше остальных) одинаковых цифр из разных капч. В paint.net наложил их друг на друга и получил общую для всех начертаний каждой цифры маску.
![](https://habrastorage.org/webt/gp/9_/tg/gp9_tggrvacz2jncx6eesiffz7c.png)
Единственную проблему обнаружил позднее, уже при массовой обработке, но успешно её обошёл
Кроме этого небольшого недоразумения шум совершенно не мешает. Итогом этого этапа стал набор из 9 масок. Два вложенных цикла и вуаля! – все мои 83 капчи распознаются на ура!
![](https://habrastorage.org/webt/dc/we/3f/dcwe3fms8fxijery7_mg-s_isfa.png)
Дальше встал вопрос: где взять большой набор капч для проверки. И я скачал «29 000 капч» из упомянутой статьи.
Во-вторых, а на самом деле – во-первых, – это не настоящие капчи. Сайт отдаёт картинку в формате 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()
Дополнение от 13.02.2020.
Ради чего всё затевалось? Не ради же спортивного распознавания сохранённых картинок? Нет, всё это было исключительно в прагматических целях.
Готовое решение для работы. — локальный http-сервер распознавания плюс расширение для Chrome.
Пока единственное, что оно умеет (я надеюсь, что умеет) — автоматически вставлять капчу в нужное место. В планах:
— очистить интерфейс сайта, оставив необходимый минимум;
— автоматизировать обновление капчи при просмотре сведений, т.к. одна капча даёт возможность открыть всего 4 объекта.
— загружать сразу все готовые выписки, а не по одной.
rasperepodvipodvert
Опубликуйте на github, яндекс диск считается плохим тоном!
0617 Автор
Полагаете, 26 строк кода того стоят? Архив с капчами всё равно куда-то нужно выложить, а код в архиве — так, маленький бонус.
istepan
gist.github.com
0617 Автор
Да, спасибо. К сожалению, чтобы код заработал, нужны файлы с масками. Подскажите, пожалуйста, как их туда выложить.