Разгадываем капчу в qt — 3 (метод дырки)

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

Сегодня я расскажу о алгоритме который я назвал метод дырки, данный метод позволит нам распознавать такие цифры как 0, 6, 9, 8,4 без шаблонов, без выравнивания, со средним качеством изображения.

Число 8 угадывается в 99% случаях, 0, 6 и 9 — в 95%, а вот с 4 проблемы, примерно 70% шанса на угадывание, процентное соотношение зависит от качества и наклонности изображения под небольшой градус.

Сначала также как и во всех перед идущих статьях, картинку нужно отфильтровать чтобы остались белые и чёрные пиксели, как это делать я повторять не буду.

Для начала немного наглядной теории, открываем paint и рисуем числа.

1-6  1-7

Далее делаем заливку.

2-6     2-7

Что у нас осталось в случае с 6кой? — белая дырка.

Думаю вы суть уловили, делаем условие таким

1) ищем белый пиксель — заливаем красным.

2) Делаем поиск по картинке, если  есть хоть один белый пиксель, значит на картинке одно число из нашего списка — 0 8 6 9 4

Идем дальше, как нам узнать какое именно число из списка у нас на картинке?
===================== 8 ===================
Начнем с 8, самое простое и идеальное условие,
1-8

Ищем первый попавшийся белый пиксель и делаем заливку
2-8


Снова ищем первый попавшийся белый пиксель и делаем заливку

3-8

И снова ищем первый попавшийся белый пиксель, если такой нашелся — значит число — 8

===================== 8 ===================
===================== 0 ===================
Дальше ноль, чем ноль отличается от остальных цифр? - тем что он постой по середине, тоесть достаточно проверить немного пикселей по середине на наличие белого цвета, и если если нет чёрных, значит у нас ноль

1-0
==================== 0 ===================
==================== 6 9 4 ===================
Если у нас не 8 и не 0, значит у нас 6 или 9 или 4
2-6 1-9
чем отличаются эти 2 числа? у одного больше белых пикселей внизу, у второго в верху, что идеально подходит для их различия.

А вот с четверкой нелады... так как по условию сравнения  пикселей код приймет 4 за 9(чаще всего), поэтому я сделал еще одну проверку, она на 100% проблему не решает, но хоть метод не будет всегда принимать 4 за 9,

1-49
если поделить их пополам то видно что, у четверки красных пикселей в верхней половине больше чем у девятки, это и будет нашим различием.
UPD:06/08/2016
Алгоритм распознавания четверки описанный выше не дал положительных результатов, я нашел более точную формулу, у четверки количество белых пикселей составляет не более 25% от черных, в то время как у 9 и 6 в основном их от 30 - 40%
==================== 6 9 4 ===================
==================== 6 9 4 =================== Теория закончена, ниже коды и результат.

Метод который делает заливку.( за код спасибо DrOffset)

void CapMonster::FillNextWhite(QImage& img, const QPoint& size,const QRgb& rgbWhite,const QRgb& rgbRed){

 QStack<QPoint> spt;

 spt.push(size);

 while(!spt.empty())
 {
 QPoint const tmp = spt.top();
 spt.pop();

 img.setPixel(tmp, rgbRed);

 if((tmp.x() + 1) < img.width())
 {
 QPoint npt(tmp.x() + 1, tmp.y());

 if(img.pixel(npt) == rgbWhite)
 {
 spt.push(npt);
 }
 }
 if((tmp.x() - 1) > -1)
 {
 QPoint npt(tmp.x() - 1, tmp.y());

 if(img.pixel(npt) == rgbWhite)
 {
 spt.push(npt);
 }
 }
 if((tmp.y() + 1) < img.height())
 {
 QPoint npt(tmp.x(), tmp.y() + 1);

 if(img.pixel(npt) == rgbWhite)
 {
 spt.push(npt);
 }
 }
 if((tmp.y() - 1) > -1)
 {
 QPoint npt(tmp.x(), tmp.y() - 1);

 if(img.pixel(npt) == rgbWhite)
 {
 spt.push(npt);
 }
 }
 }

}

И метод с нашими алгоритмами определения изображения

int CapMonster::HoleMethod(const QImage& img ){


 //-----------------------------подготовка холста-----------------------
 int Big = 0;
 Big = img.rect().height();
 if(img.rect().width() > Big){
 Big = img.rect().width();
 }
 QImage canvas(Big*3,Big*3,img.format());
 canvas.fill(Qt::white);
 CopyImage(canvas,Big*1,Big*1,img);
 //-----------------------------подготовка холста-----------------------

 QRgb rgbRed;
 QColor color;
 color.setRgb(255, 0, 0);
 rgbRed = color.rgb();
 QRgb rgbWhite;
 color.setRgb(255, 255, 255);
 rgbWhite = color.rgb();

 QPoint FirstFind;

 FirstFind.setX(0);
 FirstFind.setY(0);

 FillNextWhite(canvas,FirstFind,rgbWhite,rgbRed);
 canvas = CropImage(canvas);

 if(!FindPixelByColor(canvas,rgbWhite,FirstFind)){
 return -1;
 }


 //=====================проверяем на 8 ================================//
 QImage tempCanvas = canvas;
 FillNextWhite(tempCanvas,FirstFind,rgbWhite,rgbRed);
 if(FindPixelByColor(tempCanvas,rgbWhite,FirstFind)){
 return 8;
 }
 //===================== проверяем на 8 ================================//
 //=====================проверяем на 0 ================================//
 int MiddleX = 0;
 int MiddleY = 0;

 MiddleX = canvas.width()/2;
 MiddleY = canvas.height()/3;
 bool AllPixelIsWhite = 1;


 for(int x = MiddleX;x<MiddleX+1;x++){
 for(int y = MiddleY;y<canvas.height() - canvas.height()/3;y++){
 if( canvas.pixel(x,y) != rgbWhite ){
 AllPixelIsWhite = 0;
 break;
 }
 }
 }

 if(AllPixelIsWhite){
 return 0;
 }

 //=====================проверяем на 0 ================================//
 //===================== проверяем на 6 4 9 ================================//
 int CountUp = 0,CountDown = 0;
 int CountRedPixtelInTop = 0,CountRedPixtel = 0;
 for(int x= 0;x<canvas.width();x++){
 for( int y = 0;y<canvas.height();y++){
 if( canvas.pixel(x,y) == rgbWhite){
 if( y > canvas.height()/2){
 CountDown++;
 }else{
 CountUp++;
 }
 }else{
 if(canvas.pixel(x,y) == rgbRed){
 if( y < canvas.height()/2){
 CountRedPixtelInTop++;
 }
 CountRedPixtel++;
 }

 }
 }
 }

if( ((CountUp+CountDown) * 100/CountBlack) < 25){
 return 4;
 }

 if(CountUp > CountDown){
 return 9;
 }else{
 return 6;
 }
 //===================== проверяем на 6 4 9 ================================//


 return -1;
}

Результат:
1result
Как видно из изображения, везде где на капче есть 0 8 6 9 - результат 100% верный.

Испытаем в бою.
ura-rewbux
В принципе неплохо)


 

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *