Наконец то у меня нашлось время подумать над новыми алгоритмами распознания капчи. В прошлой статье я писал а шаблонном сравнении изображений, вроде был и не плохой результат, но как оказалось на практике, ошибок 50 на 50.
Сегодня я расскажу о алгоритме который я назвал метод дырки, данный метод позволит нам распознавать такие цифры как 0, 6, 9, 8,4 без шаблонов, без выравнивания, со средним качеством изображения.
Число 8 угадывается в 99% случаях, 0, 6 и 9 — в 95%, а вот с 4 проблемы, примерно 70% шанса на угадывание, процентное соотношение зависит от качества и наклонности изображения под небольшой градус.
Сначала также как и во всех перед идущих статьях, картинку нужно отфильтровать чтобы остались белые и чёрные пиксели, как это делать я повторять не буду.
Для начала немного наглядной теории, открываем paint и рисуем числа.
Далее делаем заливку.
Что у нас осталось в случае с 6кой? — белая дырка.
Думаю вы суть уловили, делаем условие таким
1) ищем белый пиксель — заливаем красным.
2) Делаем поиск по картинке, если есть хоть один белый пиксель, значит на картинке одно число из нашего списка — 0 8 6 9 4
Идем дальше, как нам узнать какое именно число из списка у нас на картинке?
===================== 8 ===================
Начнем с 8, самое простое и идеальное условие,
Ищем первый попавшийся белый пиксель и делаем заливку
Снова ищем первый попавшийся белый пиксель и делаем заливку
И снова ищем первый попавшийся белый пиксель, если такой нашелся — значит число — 8
===================== 8 ===================
===================== 0 =================== Дальше ноль, чем ноль отличается от остальных цифр? - тем что он постой по середине, тоесть достаточно проверить немного пикселей по середине на наличие белого цвета, и если если нет чёрных, значит у нас ноль==================== 0 ===================
==================== 6 9 4 =================== Если у нас не 8 и не 0, значит у нас 6 или 9 или 4![]()
чем отличаются эти 2 числа? у одного больше белых пикселей внизу, у второго в верху, что идеально подходит для их различия. А вот с четверкой нелады... так как по условию сравнения пикселей код приймет 4 за 9(чаще всего), поэтому я сделал еще одну проверку, она на 100% проблему не решает, но хоть метод не будет всегда принимать 4 за 9,
если поделить их пополам то видно что, у четверки красных пикселей в верхней половине больше чем у девятки, это и будет нашим различием.
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; }
Результат:Как видно из изображения, везде где на капче есть 0 8 6 9 - результат 100% верный. Испытаем в бою.
В принципе неплохо)
забавно, что нам декаптчерам, одни и те же идеи приходят