文章地址:http://blog.csdn.net/u011535382/article/details/48210643
本文是成都地区CMCC-EDU登陆时候的验证码识别过程分析,完整的登陆过程分析在 这里。
1.验证码识别难度分析
经过对比观察发现,CMCC-EUD的验证码其实很二的,其中每个数字的出现位置是固定的,每个数字每次出现的形状也是一样的,只有少量的噪点可以通过分区和二值化处理来消除。
可以将图片看成是44*20的一个矩阵,只要能够把它每个数字标准的形式存储下来,再将整个验证码分为四个区域,逐一比较,找出差异度最小的就实现了。
2.标准数字矩阵的建立
由于每个数字可以看成是 13*9 的矩阵,需要将他们转化为二值并储存在二维数组中作为每次比较的标准。先通过ps将图片裁剪成 13*9 分辨率的文件,再由软件对比识别。
这是二值化前的效果:
其中彩色转化为灰度的计算方式为 gray = R*0.11+G *0.59 + B*0.3;灰度转二值的阀值取为 128,这样实际的的效果最好。再将识别出来的图像矩阵存储到文本文件 stand.txt 中方便以后编程的使用。
二值化后的效果:
4.验证码的识别思路
1、将待验证的图片分为四个区域;
2、选择一个区域数字识别;
3、将10个标准数字矩阵和待识别区做异或操作,统计差异最小的那个数就是识别出来的数num;
4、若四个区域都识别完,返回识别结果,若没有,转到步骤2。
5.具体实现代码
/*
验证码识别函数
参数: 包含验证码图片的 CImage 对象
返回值: 识别结果的 CString */
CString Distinguish(CImage &image)
{
CString strResult;
//每张验证码分为四个区域
for(int temp= 0; temp<=3; temp++)
{
bool pixelArray[13][9] = {0};
int numL = 11*temp+2; //x像素坐标的左边起点
int numR = numL + 9; //x像素坐标的右边起点
int resultNum = 0;
//对一个图像进行扫描二值化 存储在 pixelArray
for (int y=2; y<15; y++)
{
for (int x=numL; x<numR; x++)
{
COLORREF colorRef = image.GetPixel(x,y);
//RGB同时扩大100倍 转化为灰度值
int gray = GetRValue(colorRef)*11+GetGValue(colorRef)*59+GetBValue(colorRef)*30;
if (gray>=12800)
{
pixelArray[y-2][x-numL] = true;
}
else
{
pixelArray[y-2][x-numL] = false;
}
}
}
//对一个区域的数字进行识别
//将10个标准数字与目标数字矩阵比较
int mincount = 117;
for (int num =0; num<10; num++)
{
int count = 0;
for (int y=0; y<13; y++)
{
for (int x=0; x<9 ;x++)
{
//统计差异的个数
if (standNum[num][y][x]&&pixelArray[y][x])
{
count++;
}
}
}
if (count<mincount)
{
mincount = count;
resultNum = num;
}
}
//将识别出来的数字转化为CString
CString strFormat;
strFormat.Format("%d", resultNum);
strResult += strFormat;
}
return strResult;
}
/*
验证码识别函数
参数: 包含验证码图片的 CImage 对象
返回值: 识别结果的 CString */
CString Distinguish(CImage &image)
{
CString strResult;
//每张验证码分为四个区域
for(int temp= 0; temp<=3; temp++)
{
bool pixelArray[13][9] = {0};
int numL = 11*temp+2; //x像素坐标的左边起点
int numR = numL + 9; //x像素坐标的右边起点
int resultNum = 0;
//对一个图像进行扫描二值化 存储在 pixelArray
for (int y=2; y<15; y++)
{
for (int x=numL; x<numR; x++)
{
COLORREF colorRef = image.GetPixel(x,y);
//RGB同时扩大100倍 转化为灰度值
int gray = GetRValue(colorRef)*11+GetGValue(colorRef)*59+GetBValue(colorRef)*30;
if (gray>=12800)
{
pixelArray[y-2][x-numL] = true;
}
else
{
pixelArray[y-2][x-numL] = false;
}
}
}
//对一个区域的数字进行识别
//将10个标准数字与目标数字矩阵比较
int mincount = 117;
for (int num =0; num<10; num++)
{
int count = 0;
for (int y=0; y<13; y++)
{
for (int x=0; x<9 ;x++)
{
//统计差异的个数
if (standNum[num][y][x]&&pixelArray[y][x])
{
count++;
}
}
}
if (count<mincount)
{
mincount = count;
resultNum = num;
}
}
//将识别出来的数字转化为CString
CString strFormat;
strFormat.Format("%d", resultNum);
strResult += strFormat;
}
return strResult;
}
6.验证码识别效果
经过300多张图片的测试,成功率为 100% (主要是图片太简单)。