Читаем капчу

6 Дек
2011

В данном отчете я хотел бы продемонстрировать мой структурный метод распознавания образов на примере капч одного сайта.
Ниже представлены примеры капчи.
image
image
image
image
image
image

Анализируем картинку


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

Алгоритм чтения капчи


Анализируя картинку был разработан следующий алгоритм:
  1. определить цвет символов;
  2. выделить и сохранить отдельно каждый символ капчи;
  3. привести все символы к единому размеру;
  4. сохранить большое количество символов, приведенных к одному размеру;
  5. для входного символа выполнить сравнение с каждым паттерном из базы и выявить наиболее схожий.


Реализация


  1. Первым делом что нам предстоит выяснить это цвет символов. Для этого можно вырезать фрагмент символа и выяснить его значение ARGB. ARGB используется для числового представления цвета и вычисляется по формуле
    ARGB = 255^3 * A + 255^2 * R + 255 * G + B,
    где A, R, G, B – прозрачность, значение красного, зеленого и синего каналов соответственно.
    #define ALPHA_SHIFT 24
    #define RED_SHIFT 16
    #define GREEN_SHIFT 8
    #define BLUE_SHIFT 0
    #define ALPHA_MASK ((ARGB) 0xff << ALPHA_SHIFT)
    #define MAKEARGB(a, r, g, b) \
    (((ARGB) ((a) & 0xff) << ALPHA_SHIFT)| \
    ((ARGB) (® & 0xff) << RED_SHIFT) | \
    ((ARGB) ((g) & 0xff) << GREEN_SHIFT)| \
    ((ARGB) ((b) & 0xff) << BLUE_SHIFT))
  2. Итак, после того как мы выяснили значение цвета символов следующей задачей является окаймление прямоугольником каждого символа и приведение его к единому размеру. Алгоритм заключается в следующем: считываем картинку по столбцам, как только мы обнаружили пикслель с нужным значением ARGB (+- delta) считаем данный столбец (назовем его leftSide) левой стороной окаймляющего прямоугольника, далее продолжаем считывать картину по столбцам до тех пор пока не дойдем до столбца не содержащего ни одного пикселя с нужным значением ARGB – найденный столбец (назовем его rightSide) считаем правой стороной окаймляющего прямоугольника. После этого считываем пиксели картинки построчно от столбца leftSide до столбца rightSide. После того как мы нашли первую строку содержащую пиксель с нужным значением ARGB (+- delta) считаем эту строку верхней стороной окаймляющего прямоугольника (назовем ее topSide), после чего продолжаем считывать картинку построчно до тех пор, пока на найдем строку не содержащую ни одного пикселя с нужным значением ARGB (+- delta) – эту строку считаем нижней стороной окаймляющего прямоугольника (назовем ее bottomSide).
  3. Вышеприведенный алгоритм применяем для всех символов капчи. После того как у нас имеются координаты окаймляющих прямоугольников каждого символа необходимо скопировать символы в отдельные картинки и привести их к единому размеру.
    На рисунке 2 изображены примеры символов, приведенных к единому размеру.

    Рисунок 2 – примеры выделенных символов
  4. Следующим шагом реализации является создание базы знаний. Для этого необходимо загрузить большое количество капч. После чего нужно выделить каждый символ из капчи и сохранить отдельно. Следующий фрагмент кода на языке C# загружает с сайта капчи:
    for (int i = 0; i < 200; i++)
    {

    //create instance of HttpRequest class to make a request to the server
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);

    //indicate method
    request.Method = "Get";

    //get the response from the server
    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
    Stream stream = response.GetResponseStream();
    StreamReader responseStream = new StreamReader(stream);

    //write the html code into variable
    String responseString = responseStream.ReadToEnd();

    //get session id using regexp in order to download the image
    Regex regex = new Regex("securePicture/[-a-zA-Z0-9]+");
    Match match = regex.Match(responseString);
    string sessionID = match.Value;
    sessionID = sessionID.Substring(@"securePicture/".Length);

    //when I know sessionID I can send request to get the image
    HttpWebRequest req = (HttpWebRequest)WebRequest.Create(urlname + @"/securePicture/" + sessionID);
    req.Method = "Get";

    //get the response and save the image
    HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
    Stream stream2 = resp.GetResponseStream();
    Bitmap bm = new Bitmap(stream2);
    bm.Save(path);
    }

    Посылаем get запрос на сервер, узнаем идентификатор сессии, который будем использовать для формирования url картинки.
  5. После того, как мы получили большое количество картинок, в каждой картинке выделяем символы и сохраняем их в отдельных файлах. Затем вручную распределяем картинки по категориям. В итоге мы получим папки, в каждой из которых содержатся экземпляры символов из капчи.
    Основная идея распознавания символа заключается в наложении входного символа на все имеющиеся и выявлении наиболее схожего. Для определения наиболее схожего символа максимизируем f, где f — это количество совпадающих пикселей минус количество отличающихся пикселей.

Тестирование
В итоге мною было обработано около 200 капч. Скорость чтения капчи приблизительно 1.5 секунды. Некоторые символы распознаются неверно из-за сильного искажения. Правильность распознавания символов около 90%.

P.S.: проект можно скачать по ссылке www.megaupload.com/?d=JTD8VDUF. Класс Captcha реализует логику распознавания.
По материалам Хабрахабр.



загрузка...

Комментарии:

Наверх