本文,将会简述如何利用Matlab的强大功能,调用神经网络处理验证码的识别问题。
预备知识,Matlab基础编程,神经网络基础。
可以先看下:
Matlab基础视频教程
Matlab经典教程——从入门到精通
神经网络入门
验证码识别原理
Matlab对图像读入处理,去掉噪声点和较浅的点,进行二值化,将图像转变为0/1矩阵,这样就完成了预处理。
然后要对图像进行切割,取到每个数字的小图片位置,将其缩放至等大小,方便神经网络进一步处理。
最后将图片转成神经网络能够识别的格式,例如BP网络,则将其转为行向量,深卷积网络,则将其转为矩阵即可。
识别预处理
Matlab对验证码的识别是基于神经网络的,但预处理工作还是占了整体工作的大半,将数据整理好并处理成对应可用的格式,问题就简单了很多。
Matlab的一大缺陷是不注重数据结构,其结构体无比难用,所以我们这里将尽可能使用矩阵进行处理,而参数较多时,我们也只是简单的将其放入到元胞数组中,不优雅之处,敬请见谅。
首先介绍一下matlab的图像基本处理函数:
img = imread(\'path\') # 返回一个图像的矩阵,其每个元素的值,包含rgb三个通道的数据。
imshow(img)
imgGray = rgb2gray(img) # 转为灰度图像
thresh = graythresh(imgGray); % 自动确定二值化阀值
BW = 1 - im2bw(imgGray,thresh); % 二值化,且取反,黑的部分是0,白的部分是1,
I2 = bwareaopen(BW, 8, 8); % 去除连通分量中小于10的离散点
我们看看目标的图片:
有很多随机的像素点干扰,我们需要将这些像素点去除,然后进行图像切割。
切割图片实际上很简单,就是对图片中每行每列进行统计,然后将形成的波形进行扫描,每个从0上升又下降到0的区域,就是一个字符。
切割后的图片:
下面我们来写一个完整的函数分割器函数,为了检测正确性,我们这里提供了isshow标记,如果设置为true,将会打印中间的调试信息。
function y = cutting(img, isshow)
if nargin < 2; isshow = false; end
if isshow;
imshow(img);
end
imgGray = rgb2gray(img);
thresh = graythresh(imgGray);
BW = 1 - im2bw(imgGray,thresh);
I2 = bwareaopen(BW, 8, 8);
varray = sum(I2);
imgsize = size(I2);
if isshow
figure;
imshow(imgGray);
harray = sum(I2\');
x1 = 1 : imgsize(1, 1);
x2 = 1 : imgsize(1, 2);
figure;
plot(x1, harray, \'r+-\', x2, varray, \'y*-\');
figure;
imshow(I2);
end
va = mean(varray);
harray = sum(I2\');
vb = mean(harray);
isanum = false;
sumy = 0;
for i = 1 : imgsize(1, 1)
if harray(i) > vb;
if isanum == false;
isanum = true;
cvb = i;
end
else
if isanum;
isanum = false;
cve = i;
sumy = sumy + 1;
if isshow;
hold on;
plot([0 imgsize(1,2)], [cvb cvb],\'r--\');
plot([0 imgsize(1,2)], [cve cve], \'r--\');
end
end
end
end
y = {}
sumy = 0;
for i = 1 : imgsize(1, 2);
if varray(i) > va;
if isanum == false;
isanum = true;
ctb = i;
end
else
if isanum;
isanum = false;
cte = i;
sumy = sumy + 1;
if isshow;
hold on;
plot([ctb ctb], [0 imgsize(1,1)],\'r--\');
plot([cte cte], [0 imgsize(1,1)],\'r--\');
end
t = I2(cvb:cve, ctb:cte);
y{sumy} = t;
end
end
end
end
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
我们这个函数实现了对图片的预处理工作,成功的将大部分图片分割成了小图片,放到返回的元胞数组中,但这还有一个重要的问题,就是切割后的图片并不等大小。
并且,我们为了让这些图片能够方便的进行训练,希望将他们归好类别,方便标记。将图像等大小十分简单,只需要将图像的最大的长和宽找到,然后对矩阵进行扩展,多余的位置补0即可。
for i = 1 : length(imgs_name)
img_name = imgs_name{i};
imgs = cutting(imread([\'train/\',img_name,\'.jpg\']), false);
if (length(imgs) == length(img_name))
imgs_num_size = length(img_name);
for j = 1 : imgs_num_size
tmp_num = str2num(img_name(j)) + 1;
imgs_sample_num(tmp_num) = imgs_sample_num(tmp_num) + 1;
imgs_sample{tmp_num, imgs_sample_num(tmp_num)} = imgs{j};
tmp_size = size(imgs{j});
end
end
end
max_size = [16 16];
for i = 1 : 10
for j = 1 : imgs_sample_num(i)
temp = zeros(max_size);
imgs_size = size(imgs_sample{i, j});
temp(1:imgs_size(1,1), 1:imgs_size(1,2)) = imgs_sample{i, j};
imgs_sample{i, j} = temp;
end
end
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
-
请发表评论