Речь пойдет об относительно новом творении в области капча-производства, новой яндекс-капче. Поищем слабые места, пролезем в эти слабые места и осмотримся там. Также подумаем на тему — помогает ли программа пакету распознавания текста на картинке — Tesseract — стать лучше.
Дано
Сразу необходимо оговориться, что новоявленные капчи имеют разное визуальное представление. В основном, это деформация текста на любой вкус и цвет. Капчи черно-бело-серые, с добавлением фоновых сегментов схожих цветов.
Однако, если проанализировать то, что видно на изображении, то можно прийти к выводу, что в подавляющем большинстве текст на капчах выглядит либо так («змейка»):
либо так («улыбка»):
либо так(«горка»):
Также известно, что на изображениях может присутствовать как русский, так и английский текст, представленный большей частью двумя словами. Данные слова не связаны в какую-либо вменяемую фразу, случайны.
С чего начать
Первичный анализ с помощью пакета opencv показал, что капча устойчива к таким методам как Erosion, Dilation, Harris_corners:
Также ничего не дает попытка «вырезать» пиксели с нужным цветом, так как в капчу добавлены шумы:
Что дальше
Попробуем старый, добрый пакет tesseract, а за основу возьмем код из этой
статьи.
В общем и целом в ней описывается как пакет tesseract распознает текст на изображении. На выходе программы выводится confidence и text. Грубо говоря, степень достоверности определенного текста и сам текст. Также программа рисует прямо на картинке, что она «видит». Этот код нам очень поможет в дальнейшем.
Повыкидываем из него лишнее, например, рисование того, что было прочитано и т.п.
В обновленном виде он выглядит так:
# import the necessary packages
from pytesseract import Output
import pytesseract
import argparse
import cv2
# Путь для подключения tesseract
pytesseract.pytesseract.tesseract_cmd = 'D:\\Tesseract-OCR\\tesseract.exe'
image = cv2.imread('4-.jpg')
rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
config = r'--oem 3 --psm 6'
results = pytesseract.image_to_data(rgb, output_type=Output.DICT,config=config,lang='rus')
# loop over each of the individual text localizations
for i in range(0, len(results["text"])):
# extract the bounding box coordinates of the text region from
# the current result
x = results["left"][i]
y = results["top"][i]
w = results["width"][i]
h = results["height"][i]
# extract the OCR text itself along with the confidence of the
# text localization
text = results["text"][i]
conf = int(results["conf"][i])
if conf > 0:
print("Confidence: {}".format(conf))
print("Text: {}".format(text))
print("")
text = "".join([c if ord(c) < 128 else "" for c in text]).strip()
cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
#cv2.putText(image, text, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX,1.2, (0, 0, 255), 3)
# show the output image
cv2.imshow("Image", image)
cv2.waitKey(0)
*Русский язык надо отдельно добавлять в tesseract, но это несложно, надо закинуть два файла в его директорию.
Посмотрим, что получится на выходе:
Хм, первая капча как-то быстро сдалась, поэтому возьмем другую:
Как видно, что-то определилось, а что-то нет.
Улучшаем tesseract
Не будем утомлять бесконечными безуспешными попытками, которые не принесли результата. Перейдем к сути.
Интересен подход с поворотом изображения. Посмотрим, как реагирует tesseract при повороте изображения, допустим на 10 градусов.
Обновленный код дал следующие результаты:
То есть, работать с этим можно.
Повращаем изображение под разными углами в цикле от -20 до 20 градусов, а также отсечем слова меньше 5 букв (так как в подавляющем большинстве попадающиеся слова длиннее):
from pytesseract import Output
import pytesseract
import argparse
import cv2
pytesseract.pytesseract.tesseract_cmd = 'D:\\Tesseract-OCR\\tesseract.exe'
a=[]
# повернем изображение на x градусов
for x in range (-20,20):
image = cv2.imread('4-.jpg')
(h, w) = image.shape[:2]
center = (w / 2, h / 2)
#print("угол: {}".format(x))
M = cv2.getRotationMatrix2D(center, x, 1.0)
rotated = cv2.warpAffine(image, M, (w, h))
rgb = cv2.cvtColor(rotated, cv2.COLOR_BGR2RGB)
config = r'--oem 3 --psm 6'
results = pytesseract.image_to_data(rgb, output_type=Output.DICT,config=config,lang='rus')
# loop over each of the individual text localizations
for i in range(0, len(results["text"])):
text = results["text"][i]
conf = int(results["conf"][i])
if conf > 0:
if len(text)>5:
a.append(text)
print(a)
На выходе — список того, что получилось:
['величии', 'величии', 'величии', 'величии', 'величии', 'величии', 'еличиил', 'величии', 'величии', 'величии', 'величии', 'величиЧ', 'величии', 'величиЧ', 'величи', 'величи', 'величи', 'лишил!', 'лишал|', 'лищил`']
Как видно, tesseract не так уж и плох, если им покрутить.
Осталось самое сложное
Осталось почистить результаты и понять, какие слова правильные.
Почистим список слов, удалив оттуда слова, имеющие буквы в верхнем регистре, спецсимволы, а также дубли слов:
for i in set(a): #выкинули дубли
if any(char in " .,:;!_*-+()/#¤%&?)" for char in i)==True:#выкинули слова со спецсимволами
pass
else:
if i.islower(): #выкинули с верхним регистром
print(i)
Останется меньше слов:
величи
величии
еличиил
лишил
велич
Дело за малым — выбрать более-менее связные слова.
Здесь поможет пакет pyenchant, который будет проверять правописание.
Для русского языка, как обычно, придется закинуть
языковые пакетыв
директориюпосле установки пакета. Про pyenchant есть неплохая статья
здесь.
На выходе, после обработки в том числе pyenchant, имеем:
Ну и «поверженную» капчу после цикла:
Таким образом, капчи с расположением по типу «змейки» таки могут поглощаться tesserаctом. Печально, что их не так уж и много среди прочих. Что делать с капчами по типу «горок» и «улыбок» пока не ясно.
Скачать готовый
код.
Скачать тушки капч —
здесь.