opencv版本: 3.0.0
处理验证码: 纯数字验证码 (颜色不同,有噪音,和带有较多的划痕)
测试时间 : 一天+一晚
效果: 比较挫,可能是由于测试的图片是在太小了的缘故.
原理:
验证码识别作为身份证号机器识别的一个衍生,夹杂了很多干扰的噪音,所以加大了二值化的难度。以及轮廓追踪的不好协调。
操作过程大过程有以下几个:
(1) 待测试的图片灰度化并二值化
(2)预先装载特征库(这里分为多样,形式不一)
(3)物体轮廓检测
(4)扫描待测图片,并进行特征码比对,匹配优先
处理图片展示:
代码演示:
1 #include<opencv2/opencv.hpp> 2 3 #include <iostream> 4 #include <string> 5 6 struct DataBase{ 7 int value; //库特征对应的值 8 vector<Mat> sample; //特征库 9 DataBase(int var , Mat & sam){ 10 value = var; 11 sample.push_back(sam); 12 } 13 }; 14 15 typedef struct DataBase dataBase; 16 17 18 19 20 //加载图片 21 bool loadImage(Mat &src , Mat &gray ,String &filename){ 22 23 Mat cbgray ; //合成后图像 24 int chans; //bgR分量 25 src = imread( filename , true ); 26 if( src.empty() ) return false; 27 chans = src.channels(); 28 vector<Mat> bgR( chans ) ; 29 //分割通道 30 split(src,bgR); 31 //直方图均衡化 32 for(int chan=0 ; chan < chans ; ++chan ){ 33 equalizeHist(bgR[chan] , bgR[chan]); 34 } 35 //单通道合并 36 merge(bgR , cbgray ); 37 //灰度化 38 cvtColor(cbgray ,gray ,CV_RGB2GRAY); 39 return true ; 40 } 41 42 //二值化 43 bool binImage(Mat& src , Mat& dst , int _size , int lparam ,int mediansize){ 44 //采用自适应二值化 45 adaptiveThreshold(src,src,255,CV_ADAPTIVE_THRESH_MEAN_C,CV_THRESH_BINARY,_size , lparam); 46 //中值滤波 47 medianBlur(src,dst,mediansize); 48 return true; 49 } 50 51 //装载特征库 52 /*通常来说这个应该是预先被加载好,以数据库或者其他的形式保存起来 53 在这地方由于东西比较少,直接现场处理 54 */ 55 int loadProperty(vector<dataBase> &db ,int index[] 56 , int _size = 31 , int lparam = 7 , int mediansize = 3 ){ 57 58 //固定路径 59 char filename[30]; 60 61 for(int i=0; i<20 ; ++i){ 62 sprintf(filename,"D:\\yzm\\tzk\\%d.png",index[i]); 63 Mat tmp; 64 String path =filename; 65 loadImage(tmp,tmp,path); //装载并灰度化 66 binImage(tmp,tmp,_size,lparam,mediansize); //二值化 67 //imshow("sample",tmp); 68 //waitKey(0); 69 db.push_back( dataBase( index[i]%10 , tmp ) ); 70 } 71 72 return true; 73 } 74 75 76 //对于模块进行匹配 77 int StartMatch(Mat src , vector< dataBase > db , Point &curpx){ 78 79 int res ; 80 double maxValue , minValue ,resValue ; 81 Point minloc , maxloc ,resloc; 82 83 vector< dataBase >::iterator it; 84 vector< Mat >::iterator m_it; 85 86 Mat sample ,result; 87 int curcols , currows; 88 resValue =1.; 89 90 for( it = db.begin() ; it !=db.end() ; it++ ){ 91 92 for( m_it = it->sample.begin() ; m_it != it->sample.end() ; m_it++ ){ 93 94 sample = *m_it; 95 int res_rows = src.rows - sample.rows + 1 ; 96 int res_cols = src.cols - sample.cols + 1 ; 97 if( res_rows < 1 || res_cols< 1 ) break; 98 result = cv::cvarrToMat(cvCreateImage(cvSize(res_cols, res_rows), 1, 1)); 99 100 matchTemplate(src, sample , result ,CV_TM_SQDIFF_NORMED); //模板匹配算法,平方差匹配 101 102 minMaxLoc(result, &minValue, &maxValue, &minloc, &maxloc,Mat() ); 103 if(resValue > minValue){ 104 resValue = minValue; 105 resloc = minloc; 106 res = it->value; //记录这个值的大小 107 curcols = sample.cols; 108 currows = sample.rows; 109 } 110 } 111 } 112 113 // rectangle(srcResult, matchLoc, cvPoint(matchLoc.x + curtemplatW, matchLoc.y+ curtemplatH), cvScalar(0,0,255)); 114 //设定一个阈值 115 if(resValue<0.2){ 116 //++curpx.x; 117 curpx.x += resloc.x + curcols/2.; 118 rectangle(src,resloc,cvPoint(resloc.x + curcols , resloc.y + currows ),cvScalar(0,0,255)); 119 } 120 else{ 121 ++curpx.x; 122 res=-1; 123 } 124 return res; 125 } 126 127 //逐步的扫描 128 vector< int > ScanImage( Mat &src , vector< dataBase > db , int window_width=12 ,int window_height=12 ){ 129 130 Point srcp; 131 132 window_height = src.rows; 133 vector< int > ans ; 134 while(srcp.x<src.cols){ 135 136 if(srcp.x + window_width > src.cols) 137 window_width = src.cols - srcp.x; 138 Mat tmp = src( Rect(srcp.x,srcp.y,window_width,window_height) ); 139 140 //轮廓检测 141 /* vector< vector <Point> >reg; 142 Mat newtmp = tmp.clone(); 143 findContours(newtmp, reg,CV_RETR_EXTERNAL , CV_CHAIN_APPROX_NONE); 144 if( reg.empty() ) break; 145 Rect rect = boundingRect(Mat(reg[0])); 146 Mat ttmp = tmp(rect); 147 imshow("ttmp",ttmp); 148 waitKey(0);*/ 149 150 int ansvalue =StartMatch(tmp,db,srcp); 151 if(ansvalue !=-1){ 152 ans.push_back( ansvalue); 153 printf("%d ",ansvalue); 154 } 155 } 156 puts(""); 157 return ans; 158 } 159 160 int main() 161 { 162 163 Mat check; 164 vector< dataBase > dblist; 165 int dex[20];//{0,1,2,3,4,5,6,7,8,9}; //建立一个索引 166 for(int i=0;i<20 ; dex[i]=i++); 167 loadProperty(dblist,dex,7,33,3); 168 169 for(int i=0;i<9;i++) 170 { 171 char path[30]; 172 173 if(i<9) sprintf(path,"D:/yzm/%d.jpg",i+1); 174 else sprintf(path,"D:/yzm/%d.png",i-8); 175 176 loadImage(check,check,String(path)); 177 imshow("check",check); 178 waitKey(0); 179 180 binImage(check,check,17,50,3); 181 182 ScanImage(check,dblist,11,3); 183 imshow("final",check); 184 waitKey(0); 185 } 186 waitKey(0); 187 return 0; 188 }
可能是由于测试的图片太小了,导致二值化的时候,图片很不理想,只好取消轮廓检测,然后改为手动设置窗口大小,虽然比较原始,,但是对于比较清晰的图片多能较好的
识别出来!