首先看看新版验证码,
嗯,难度系数设计一般(毕竟是手机站嘛),字符些许偏转、部分稍微扭曲,但没有粘连且位置固定,噪音也比较单一,没有干扰线,正好拿来练练爪.本文演示的仅仅是运用OCR(好处是你不用自己去写匹配算法,缺点是训练过程略繁琐)进行简单的验证码识别,属基础中的基础级别.
原图是JPEG格式,为了方便在C++操作最好先转成BMP,可以用ConvertJpegToBmp方法进行转换,可自行百度,这里使用专门用于C++处理验证码的辅助类:XYCode来处理这些琐碎的工作.
XYCode verify_code(T("1.jpeg"));
//XYCode verify_code(T("/rrrfff/1.jpeg"));实际情况下从网络下载得到的验证码的类型是随机变化的,其中新版的尺寸固定为116x54,所以要判断一下宽度滤去.
if(!(verify_code.InfoHeader.biWidth == 116 && verify_code.InfoHeader.biHeight == 54)) return;
确定是我们要处理的验证码后,在交给OCR前,需要进行一些预处理,这关系到能否识别成功. 我的惯常做法是先截掉多余部分(去掉没用的字符不然会干扰识别),然后去噪(把不需要的信息除去,这里BZ(博主)偷了懒,用的算法比较粗糙,所以有些锯齿,但是影响不太就算了:用ps取得若干个噪点rgb值,确定范围,此范围外的认为是字符,否则统统枪毙):
//干掉底部19行, 顶部8行
verify_code.VTrim(8, 19);
//干掉左边8列
verify_code.HTrim(4 * 2);
//简单去噪
verify_code.ChangePixel(215, 40, 255, 215, 40, 255, 205, 52, 255);
然后是二值化(顾名思义,把图像转换成仅有1和0的二进制点阵,其中字符和背景的值是相对的),
for (int h = 0; h < verify_code.InfoHeader.biHeight; ++h)
{
XYCode::Pixel *pp = (XYCode::Pixel *)&verify_code.pImageData[verify_code.LineByte * h];
for (int w = 0; w < verify_code.InfoHeader.biWidth; ++w)
{
if ( !(XYCode::is_in(pp[w].r, 250, 5) && XYCode::is_in(pp[w].g, 250, 5)
&& XYCode::is_in(pp[w].b, 250, 5)) )
{
pp[w].r = pp[w].g = pp[w].b = 0;
} //if
} //for
} //for
嗯,看看效果?
看起来好多了,就这样,接下来是字符矫正(不太喜欢灰度化,留着先) 首先你需要下载
Tesseract-OCR 3.0.2 VS可直接编译源码
jTessBoxEditor-1.0.zip(训练用)