基于matlab的简单数字验证码识别系统 【验证码识别】计算机视觉,数字图像处理,含GUI界面。 步骤:图像降噪,二值化,定位数字,分割合并,字符识别。 功能:可识别简单的数字验证码图片,支持图片中有多张验证码的共同识别。 代码结构清晰,含有注释,运算速度快,可扩展。 ,包远程调试(第063期)

最近在折腾数字验证码识别,用MATLAB撸了个能处理简单场景的验证码识别系统。这玩意儿虽然不能破解复杂验证码,但对付教务系统那种四位数验证码绰绰有余。先晒个处理效果:加载验证码图片后自动输出识别结果,还能同时处理多张验证码同框的情况。

先来个预处理全家桶。验证码图片常见的噪点、粘连、扭曲三大难题,咱们用中值滤波+形态学操作开刀。实测下面这个组合拳效果不错:
matlab
% 降噪三板斧
gray_img = rgb2gray(orig_img); % 转灰度
med_filter = medfilt2(gray_img,[3 3]); % 中值滤波去椒盐噪点
bin_img = imbinarize(med_filter,'adaptive','Sensitivity',0.7); % 自适应二值化
clean_img = bwareaopen(bin_img,20); % 去除小面积噪点
这段代码里有个坑------自适应二值化的敏感度参数得根据验证码颜色深浅调整。试过用大津法自动阈值,但遇到渐变背景直接翻车,最后还是换成手动调参。

定位数字是关键难点。垂直投影法适合字符间距大的情况,但遇到字符粘连就gg。这里改用连通域分析法:
matlab
% 连通域定位
cc = bwconncomp(clean_img);
stats = regionprops(cc,'BoundingBox','Area');
valid_boxes = [];
for k = 1:length(stats)
if stats(k).Area > 30 % 过滤噪点
box = stats(k).BoundingBox;
% 合并横向重叠区域(处理字符断裂)
if ~isempty(valid_boxes) && box(1) < (valid_boxes(end,1)+valid_boxes(end,3))
valid_boxes(end,3) = box(1)+box(3)-valid_boxes(end,1);
else
valid_boxes = [valid_boxes; box];
end
end
end
这个合并逻辑能解决数字中间断裂的情况。比如数字"8"可能被误分成上下两部分,通过判断包围盒的横向重叠进行合并。不过要注意合并阈值,设太大可能把相邻数字错误合并。

识别部分采用模板匹配+特征值双校验。虽然CNN更强大,但传统方法速度快啊!先准备0-9的标准模板:
matlab
% 加载数字模板
templates = cell(10,1);
for i = 0:9
templates{i+1} = imresize(imread(['template/',num2str(i),'.png']),[32 32]);
end
% 相似度比对
function num = match_number(img_patch)
max_score = 0;
for n = 1:10
corr_score = corr2(img_patch,templates{n});
if corr_score > max_score
max_score = corr_score;
num = n-1;
end
end
end
模板图片建议自己截取验证码生成页面的标准字体。实测相关系数比对在字符无旋转时准确率95%以上,但遇到倾斜字符需要先做旋转校正。

整个系统打包成GUI后长这样:左侧显示原图和处理过程,右侧实时输出识别结果。重点说下多验证码同框的处理逻辑------通过寻找大面积空白区域自动分块,每块单独走识别流程:
matlab
% 多验证码分割
[~, threshold] = edge(clean_img,'sobel');
BW = edge(clean_img,'sobel',threshold * 0.5);
se = strel('rectangle',[15 15]);
BW_close = imclose(BW,se); % 闭合操作连接区域
这套方案在i5处理器上处理单张验证码耗时约0.3秒。想要再提速可以预加载模板、改用矩阵运算替代循环。代码特意保留了扩展接口,比如在match_number函数处替换成SVM分类器,立马升级成机器学习方案。
最后说下实际部署的坑:不同验证码的字体粗细差异可能导致二值化失效,这时需要在GUI里增加手动调节阈值的滑块。远程调试时遇到过字符分割错位,后来发现是不同屏幕分辨率导致imshow缩放图片引起的,加上axis normal固定显示比例才解决。