验证码识别技术

来源:互联网 发布:思迅软件好不好 编辑:程序博客网 时间:2024/04/28 01:23

原创  验证码识别技术 收藏

程序实现分样本下载器、用户交互程序、MLP建构程序三块,使用OpenCV,喜欢的可以留意下AnnMLP的使用方法,国内这方面的资料还是比较少的,欢迎交流QQ:13895354。

 

预处理技术是专门针对某种特定验证码设计的,其特点有:英文+数字,彩色,倾斜,无粘连,有不规则噪声,有删除线,至于具体哪家网站的验证码,我就不方便透露了

(用户交互程序)

view plaincopy to clipboardprint?
  1. #include <cv.h>  
  2. #include <highgui.h>  
  3. #include <ml.h>  
  4. #include <iostream>  
  5. using namespace std;  
  6.   
  7.   
  8. int main( int argc, char** argv )  
  9. {  
  10.     cvNamedWindow("1");  
  11.     cvNamedWindow("2");  
  12.     IplConvKernel* se = cvCreateStructuringElementEx(2, 2, 1, 1, CV_SHAPE_CROSS);  
  13.   
  14.     CvANN_MLP mlp;  
  15.     mlp.load( "mpl.xml" );  
  16.       
  17.     for(int i=1; i<=100; i++)  
  18.     {  
  19.         // 产生文件名  
  20.         char fn[1024];  
  21.         sprintf(fn, ".//sample//%d.jpg", i);  
  22.           
  23.         // 读取图片  
  24.         IplImage* gray = cvLoadImage(fn, CV_LOAD_IMAGE_GRAYSCALE);  
  25.           
  26.         // 二值化  
  27.         cvThreshold(gray, gray, 180, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);  
  28.         // 去边框  
  29.         cvRectangle(gray, cvPoint(0, 0), cvPoint(gray->width-1, gray->height-1), CV_RGB(255, 255, 255));  
  30.         // 去噪  
  31.         cvDilate(gray, gray, se);  
  32.           
  33.         /* 
  34.         // 调整角度 
  35.         cvShowImage("1", gray); 
  36.         IplImage* rote = cvCreateImage( cvGetSize(gray), IPL_DEPTH_8U, 1 ); 
  37.         double t = tan(10.0 / 180.0 * CV_PI); 
  38.         int w = gray->width; 
  39.         int h = gray->height; 
  40.         for(int i = 0; i<h; i++) 
  41.         { 
  42.         unsigned char* lineGray = (unsigned char*)gray->imageData + gray->widthStep * i; 
  43.         unsigned char* lineRote = (unsigned char*)rote->imageData + rote->widthStep * i; 
  44.         for(int j = 0; j<w; j++) 
  45.         { 
  46.         int j2 = j - ((int)(i*t+0.5)); 
  47.         if (j2<0) 
  48.         j2+=w; 
  49.         *(lineRote+j) = *(lineGray+j2); 
  50.         } 
  51.         } 
  52.         cvCopy(rote, gray); 
  53.         cvReleaseImage(&rote); 
  54.         */  
  55.           
  56.         // 计算连通域contour  
  57.         cvXorS(gray, cvScalarAll(255), gray, 0);  
  58.         cvShowImage("1", gray);  
  59.         CvMemStorage* storage = cvCreateMemStorage();  
  60.         CvSeq* contour = NULL;  
  61.         cvFindContours(gray, storage, &contour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);  
  62.           
  63.         // 分析连通域  
  64.         CvSeq* p = contour;  
  65.         while(p)  
  66.         {  
  67.             CvRect rect = cvBoundingRect(p, 0);  
  68.             if( rect.height>=10 )// 文字需要有10像素高度  
  69.             {  
  70.                 // 绘制该连通区域到character  
  71.                 cvZero(gray);  
  72.                 IplImage* character = cvCreateImage(cvSize(rect.width, rect.height), IPL_DEPTH_8U, 1);  
  73.                 cvZero(character);  
  74.                 cvDrawContours(character, p, CV_RGB(255, 255, 255), CV_RGB(0, 0, 0), -1, -1, 8, cvPoint(-rect.x, -rect.y));  
  75.                   
  76.                 // 归一化  
  77.                 IplImage* normal = cvCreateImage(cvSize(16, 16), IPL_DEPTH_8U, 1);  
  78.                 cvResize(character, normal, CV_INTER_AREA);  
  79.                 cvThreshold(normal, normal, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);// 修正  
  80.                   
  81.                 // 计算输入向量  
  82.                 float input[256];  
  83.                 for(int i=0; i<256; i++)  
  84.                     input[i] = (normal->imageData[i]==-1);  
  85.                   
  86. #if 0  
  87.                 // 用户输入结果  
  88.                 cvShowImage("2", normal);  
  89.                 char c = cvWaitKey(0);  
  90.                 if(c==27)  
  91.                     return 0;  
  92.                   
  93.                 // 编码0-9:0-9 a-z:10-35  
  94.                 unsigned char cc = 255;  
  95.                 if(c>='A'&&c<='Z')  
  96.                     cc=c-'A'+10;  
  97.                 else if(c>='a'&&c<='z')  
  98.                     cc=c-'a'+10;  
  99.                 else if(c>='0'&&c<='9')  
  100.                     cc=c-'0';  
  101.                   
  102.                 if(cc!=255)  
  103.                 {  
  104.                     // 转换成输出向量  
  105.                     float output[36];  
  106.                     for(int i=0; i<36; i++)  
  107.                         output[i] = 0.0f;  
  108.                     output[cc] = 1.0f;  
  109.                       
  110.                     // 存储到批处理文件  
  111.                     static FILE* batch = fopen("batch""wb");  
  112.                     fwrite(output, 4*36, 1, batch);  
  113.                     fwrite(input, 4*256, 1, batch);  
  114.   
  115.                     static int count = 0;  
  116.                     cout<<count++<<endl;  
  117.                 }  
  118.                   
  119. #else  
  120.                 // 识别  
  121.                 CvMat* output = cvCreateMat( 1, 36, CV_32F );  
  122.                 CvMat inputMat = cvMat( 1, 256, CV_32F, input);  
  123.                 mlp.predict( &inputMat, output );  
  124.                 CvPoint max_loc = {0,0};  
  125.                 cvMinMaxLoc( output, NULL, NULL, NULL, &max_loc, NULL );  
  126.                 int best = max_loc.x;// 识别结果  
  127.                 char c = (char)( best<10 ? '0'+best : 'A'+best-10 );  
  128.                 cout<<c<<"("<<rect.x<<")"<<" ";  
  129.                 cvReleaseMat( &output );  
  130.   
  131. #endif  
  132.                 cvReleaseImage(&character);  
  133.                 cvReleaseImage(&normal);  
  134.             }  
  135.             p = p->h_next;  
  136.         }  
  137.         cout<<endl;  
  138.         cvWaitKey(0);  
  139.         cvReleaseMemStorage(&storage);  
  140.         cvReleaseImage(&gray);  
  141.     }  
  142.       
  143.     cvReleaseStructuringElement(&se);  
  144.     cvDestroyAllWindows();  
  145.       
  146.     return 0;  
  147. }  

事实上更有价值的是OpenCV中的AnnMLP,其技术很成熟,参考了letter_recg范例程序

 (MLP建构程序)

view plaincopy to clipboardprint?
  1. #include <iostream>  
  2. #include <ml.h>  
  3. using namespace std;  
  4.   
  5. void print_mat(CvMat& mat)  
  6. {  
  7.     int count = 0;  
  8.     for(int i=0; i<4/*mat.rows*/; i++)  
  9.     {  
  10.         for(int j=0; j<mat.cols; j++)  
  11.         {  
  12.             cout<<mat.data.fl[i*(mat.step/4)+j]/*<<" "*/;  
  13.         }  
  14.         cout<<endl<<endl;  
  15.     }  
  16. }  
  17.   
  18. int main( int argc, char *argv[] )  
  19. {  
  20.     // 读入结果responses 特征data  
  21.     FILE* f = fopen( "batch""rb" );  
  22.     fseek(f, 0l, SEEK_END);  
  23.     long size = ftell(f);  
  24.     fseek(f, 0l, SEEK_SET);  
  25.     int count = size/4/(36+256);  
  26.     CvMat* batch = cvCreateMat( count, 36+256, CV_32F );  
  27.     fread(batch->data.fl, size-1, 1, f);  
  28.     CvMat outputs, inputs;  
  29.     cvGetCols(batch, &outputs, 0, 36);  
  30.     cvGetCols(batch, &inputs, 36, 36+256);  
  31.       
  32.     // 新建MPL  
  33.     CvANN_MLP mlp;  
  34.     int layer_sz[] = { 256, 20, 36 };  
  35.     CvMat layer_sizes = cvMat( 1, 3, CV_32S, layer_sz );  
  36.     mlp.create( &layer_sizes );  
  37.       
  38.     // 训练  
  39.     system( "time" );  
  40.     mlp.train( &inputs, &outputs, NULL, NULL,  
  41.         CvANN_MLP_TrainParams(cvTermCriteria(CV_TERMCRIT_ITER,300,0.01), CvANN_MLP_TrainParams::RPROP, 0.01)  
  42.         );  
  43.     system( "time" );  
  44.       
  45.     // 存储MPL  
  46.     mlp.save( "mpl.xml" );  
  47.       
  48.     // 测试  
  49.     int right = 0;  
  50.     CvMat* output = cvCreateMat( 1, 36, CV_32F );  
  51.     for(int i=0; i<count; i++)  
  52.     {  
  53.         CvMat input;  
  54.         cvGetRow( &inputs, &input, i );  
  55.           
  56.         mlp.predict( &input, output );  
  57.         CvPoint max_loc = {0,0};  
  58.         cvMinMaxLoc( output, NULL, NULL, NULL, &max_loc, NULL );  
  59.         int best = max_loc.x;// 识别结果  
  60.           
  61.         int ans = -1;// 实际结果  
  62.         for(int j=0; j<36; j++)  
  63.         {  
  64.             if( outputs.data.fl[i*(outputs.step/4)+j] == 1.0f )  
  65.             {  
  66.                 ans = j;  
  67.                 break;  
  68.             }  
  69.         }  
  70.         cout<<(char)( best<10 ? '0'+best : 'A'+best-10 );  
  71.         cout<<(char)( ans<10 ? '0'+ans : 'A'+ans-10 );  
  72.         if( best==ans )  
  73.         {  
  74.             cout<<"+";  
  75.             right++;  
  76.         }  
  77.         //cin.get();  
  78.         cout<<endl;  
  79.     }  
  80.     cvReleaseMat( &output );  
  81.     cout<<endl<<right<<"/"<<count<<endl;  
  82.       
  83.     cvReleaseMat( &batch );  
  84.       
  85.     system( "pause" );  
  86.       
  87.     return 0;  
  88. }  

上面的代码都是vc6控制台程序,OpenCV入门的都懂的吧。

发表于 @ 2009年05月04日 09:33:00 | 评论( 11 ) | 编辑| 举报| 收藏

旧一篇:控制台的小游戏 | 新一篇:GPS/GPRS定位

 
查看最新精华文章 请访问博客首页相关文章
ACM_1906
刚学C写的东西,纪念下:)
用C语言绘制中空的N边形
RGB和HSV的相互转换的代码
zoj 2857
嵌入式系统C语言编程大赛初赛
itoa
C/C++的大小写转换方法
loven_11 发表于2010年5月21日 16:50:39  IP:举报回复
Hi, 孙文赟 我正在尝试如何使用ML的训练与识别技术. 可是刚开始无从下手, 借由你的这篇范例, 有了那么点认识了. 请问下, 第二段代码中的batch是什么意思啊? 是letter_recog.cpp里面的"./letter-recognition.data"? 我看了opencv2.0的sample里面的这个例子, 能跑,但是生成的文件看了很费解, 不是很明白是什么意思. 我用你的例子,将上面的那个data导入进去了, 也生成一个mpl.xml文件, 但是再跑第一个例子, 什么都解析不出来. 我使用的内容: 1. sample/1.jpg来自这个网页的截屏 2. 原始data使用的opencv2.0/sample/c/letter-recognition.data 3. 代码均来自你的这个页面 希望能得到你支持, 不胜感激啊. QQ & MSN: loven_11@163.com Email: lu_feng@hoperun.com
anders0821 发表于2010年5月26日 16:40:12  IP:举报回复
回复 loven_11: batch是一个二进制格式的文件,用它把人工输入的教师数据保存起来,对于网络学习来讲就是样本输入了,你可以编程序查看或者用WinHEX查看(其实数据太多也看不出什么) 你那边只有1张网页的截屏是不够建立mlp的我用了100张 你的mlp.xml肯定和我这里产生的不一样 letter_recog.cpp比我这个简单点,没有图像预处理部分,你甚至可以试着做一个更简单的异或问题,你会有所收获的
loven_11 发表于2010年5月28日 12:25:27  IP:举报回复
回复 anders0821:感谢你给我回复啊. 我这两天一直在摸索中, 麻烦你帮我看下我理解的一整套还对啊. 1. 我准备好了26张字母的图片(黑底白字), 然后用findContours得到每个字母的像素值, 最后resize成8*8的矩阵大小; 2. 然后将这些像素按照A,x,x,x,x,x,x...形式保存在文件中 3. 用CvANN_MLP的train方法,将目标值与输入值传入其中,进行训练,最后生成一个xml文件 4. 使用CvANN_MLP加载这个xml, 我做了一张包含多个字母的图片,进行识别. 我试验的思路大致如上, 有不对的地方还望能指正我一下啊.
loven_11 发表于2010年5月28日 12:25:51  IP:举报回复
我现在碰到些问题是, 1) 按照你的例子里面的findContours时,用了CV_RETR_CCOMP双层结构, 结果在遍历这些contours的时候,总是找不全,不知道问题出在哪; 2) 你给的例子中的处理方式,是不是对字体要求不能太小的,否则不能识别? 3) 我在生成data数据的时候, 是否还能再经过一些变化或者处理,能减少输入数据的长度呢? 譬如你的例子中用的是256(16*16), 我看opencv自带的例子中, 才16个, 这个是我比较费解的地方,为什么opencv的letter.data里面才那么一点输入数据啊. 用的时候,应该怎么生成这些输入数据的. 啊, 写了那么,希望您能有耐心看下来啊. 再次谢谢了啊.
anders0821 发表于2010年5月30日 19:03:47  IP:举报回复
回 复 loven_11: 我这个里是将连通区域,在保持宽高比的情况下,规格化(缩放)到16*16像素的二值图像上来,总共256个输入,这是一种比较笨的方法,不是我最先提出 的,但实验表明确实有用;CV范例上那个16个特征是从标准库(代码最前注释有讲)得到的,它们的含义分别为x y重心x平方之类的,专门用于某种印刷体英文识别。 findContours的用法你参考手册上试试看,这个不是难点
loven_11 发表于2010年6月1日 15:34:16  IP:举报回复
回复 anders0821:谢谢, 我平时看东西比较粗心大意, 尤其是对英文反应很愚钝, 没注意那里描述. 我先看看这个网址的内容吧 http://archive.ics.uci.edu/ml/datasets/Letter+Recognition
loven_11 发表于2010年6月3日 10:26:04  IP:举报回复
回复 anders0821:你有邮箱或者即时通讯工具(MSN,GTALK)么? 有些琐碎的问题希望能请教你下啊, 在这上面交流起来比较麻烦,且慢啊
loven_11 发表于2010年6月3日 10:27:09  IP:举报回复
我的邮箱是 lu_feng@hoperun.com, Msn是 loven_11@163.com .
bios8086 发表于2010年10月5日 15:03:01  IP:218.95.73.*举报回复
回复 loven_11: 哥们 你还在研究这个东西吗?
crystal8700 发表于2010年11月29日 11:06:12  IP:202.203.41.*举报回复
我现在正在做分类,就是从我提取出来的轮廓中提取出若干个特征,然后跟据这些特征值来分类。关于怎么分类没有思路,还望多多指典!
anders0821 发表于2011年3月20日 16:56:03  IP:114.226.193.*举报回复
回复 crystal8700: 关键是特征提取困难,分类的方法很多,且比较成熟。CV提供的神经网络是可以考虑使用的