当前位置:   article > 正文

Tutorial教程:Matlab神经网络验证码识别_matlabvarray

matlabvarray

本文,将会简述如何利用Matlab的强大功能,调用神经网络处理验证码的识别问题。 
预备知识,Matlab基础编程,神经网络基础。 
可以先看下:

Matlab基础视频教程

Matlab经典教程——从入门到精通

神经网络入门

验证码识别原理

Matlab对图像读入处理,去掉噪声点和较浅的点,进行二值化,将图像转变为0/1矩阵,这样就完成了预处理。 
然后要对图像进行切割,取到每个数字的小图片位置,将其缩放至等大小,方便神经网络进一步处理。 
最后将图片转成神经网络能够识别的格式,例如BP网络,则将其转为行向量,深卷积网络,则将其转为矩阵即可。

识别预处理

Matlab对验证码的识别是基于神经网络的,但预处理工作还是占了整体工作的大半,将数据整理好并处理成对应可用的格式,问题就简单了很多。 
Matlab的一大缺陷是不注重数据结构,其结构体无比难用,所以我们这里将尽可能使用矩阵进行处理,而参数较多时,我们也只是简单的将其放入到元胞数组中,不优雅之处,敬请见谅。

首先介绍一下matlab的图像基本处理函数:

  1. img = imread('path') # 返回一个图像的矩阵,其每个元素的值,包含rgb三个通道的数据。
  2. imshow(img) # 显示图像
  3. imgGray = rgb2gray(img) # 转为灰度图像
  4. thresh = graythresh(imgGray); % 自动确定二值化阀值
  5. BW = 1 - im2bw(imgGray,thresh); % 二值化,且取反,黑的部分是0,白的部分是1,
  6. I2 = bwareaopen(BW, 8, 8); % 去除连通分量中小于10的离散点
  •  

我们看看目标的图片: 
这里写图片描述

有很多随机的像素点干扰,我们需要将这些像素点去除,然后进行图像切割。

切割图片实际上很简单,就是对图片中每行每列进行统计,然后将形成的波形进行扫描,每个从0上升又下降到0的区域,就是一个字符。

这里写图片描述

切割后的图片:

这里写图片描述

下面我们来写一个完整的函数分割器函数,为了检测正确性,我们这里提供了isshow标记,如果设置为true,将会打印中间的调试信息。

  1. % 图片分割器
  2. function y = cutting(img, isshow)
  3. if nargin < 2; isshow = false; end
  4. if isshow;
  5. imshow(img); % 显示彩色图像
  6. end
  7. imgGray = rgb2gray(img); % 转为灰度图像
  8. thresh = graythresh(imgGray); % 自动确定二值化阀值 (这个不太好,有时会整体删除一个字)
  9. BW = 1 - im2bw(imgGray,thresh); % 二值化
  10. I2 = bwareaopen(BW, 8, 8); % 去除连通分量中小于10的离散点
  11. varray = sum(I2);
  12. imgsize = size(I2);
  13. if isshow
  14. figure; % 打开一个新的窗口显示灰度图像
  15. imshow(imgGray); % 显示转化后的灰度图像
  16. harray = sum(I2');
  17. x1 = 1 : imgsize(1, 1);
  18. x2 = 1 : imgsize(1, 2);
  19. figure; % 打开一个新的窗口显示分割图
  20. plot(x1, harray, 'r+-', x2, varray, 'y*-');
  21. figure; % 打开一个新的窗口显示灰度图像
  22. imshow(I2); % 显示转化后的灰度图像
  23. end
  24. va = mean(varray); % 计算平均值
  25. harray = sum(I2');
  26. vb = mean(harray);
  27. %% matlab 设计的实在太烂!真是我有史以来见过的最烂的语言
  28. %% 函数只有搅成一坨的情况下才能正确运行
  29. %% 他们根部不知道如何用闭包,以及合理的封装对象
  30. isanum = false;
  31. sumy = 0;
  32. for i = 1 : imgsize(1, 1)
  33. if harray(i) > vb;
  34. if isanum == false;
  35. isanum = true;
  36. cvb = i;
  37. end
  38. else
  39. if isanum;
  40. isanum = false;
  41. cve = i;
  42. sumy = sumy + 1;
  43. if isshow;
  44. hold on;
  45. plot([0 imgsize(1,2)], [cvb cvb],'r--');
  46. plot([0 imgsize(1,2)], [cve cve], 'r--');
  47. end
  48. end
  49. end
  50. end
  51. y = {}
  52. sumy = 0;
  53. for i = 1 : imgsize(1, 2);
  54. if varray(i) > va;
  55. if isanum == false;
  56. isanum = true;
  57. ctb = i;
  58. end
  59. else
  60. if isanum;
  61. isanum = false;
  62. cte = i;
  63. sumy = sumy + 1;
  64. if isshow;
  65. hold on;
  66. plot([ctb ctb], [0 imgsize(1,1)],'r--');
  67. plot([cte cte], [0 imgsize(1,1)],'r--');
  68. end
  69. t = I2(cvb:cve, ctb:cte);
  70. y{sumy} = t;
  71. end
  72. end
  73. end
  74. end

我们这个函数实现了对图片的预处理工作,成功的将大部分图片分割成了小图片,放到返回的元胞数组中,但这还有一个重要的问题,就是切割后的图片并不等大小。

并且,我们为了让这些图片能够方便的进行训练,希望将他们归好类别,方便标记。将图像等大小十分简单,只需要将图像的最大的长和宽找到,然后对矩阵进行扩展,多余的位置补0即可。

  1. %% 将数字分类放置
  2. for i = 1 : length(imgs_name)
  3. img_name = imgs_name{i};
  4. imgs = cutting(imread(['train/',img_name,'.jpg']), false);
  5. if (length(imgs) == length(img_name))
  6. imgs_num_size = length(img_name);
  7. for j = 1 : imgs_num_size
  8. tmp_num = str2num(img_name(j)) + 1;
  9. imgs_sample_num(tmp_num) = imgs_sample_num(tmp_num) + 1;
  10. imgs_sample{tmp_num, imgs_sample_num(tmp_num)} = imgs{j};
  11. tmp_size = size(imgs{j});
  12. end
  13. end
  14. end
  15. max_size = [16 16];
  16. %% 归一化所有样本,使其等大小
  17. for i = 1 : 10
  18. for j = 1 : imgs_sample_num(i)
  19. temp = zeros(max_size);
  20. imgs_size = size(imgs_sample{i, j});
  21. temp(1:imgs_size(1,1), 1:imgs_size(1,2)) = imgs_sample{i, j};
  22. imgs_sample{i, j} = temp;
  23. % figure;
  24. % imshow(temp);
  25. end
  26. 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

分别用BP网络和深卷积网络来进行图像识别

BP网络结构

由于已经做好了充足的预处理工作,那么接下来的识别就十分简单了,BP网络和深卷积网络都有对应的库支持操作,所以我们只需要编写配置代码就可以了。

BP网络就是简单的三层结构,由于层数太大可能带来误差残差太小等问题,造成训练困难,我们这里使用足够多的隐层节点保障BP网络的精度就可以了。

输入就是整个图像转为1维向量,输出则是可能属于的类别的概率,是一个10维的向量,要确定分类结果,就将其中最大的数字找到即可。

BP网络的训练及识别

那么,我们就可以开始组织训练数据了。

  1. % 创建数据集
  2. %% buildtrainset: 用来创建神经网络适合的训练集
  3. function [inputs outputs] = buildtrainset(imgs, number)
  4. i = 1;
  5. for k = 1 : 10
  6. for j = 1 : number(k)
  7. input = imgs{k, j};
  8. input_size = numel(input);
  9. inputs(i, :) = reshape(input', input_size, 1);
  10. outputs(i, :) = zeros(10, 1);
  11. outputs(i, k) = 1;
  12. i = i + 1;
  13. end
  14. end
  15. end

然后训练并比较正确与否:

  1. function y = runbp(imgs_sample, imgs_sample_num, max_size)
  2. % bp 网络训练
  3. [a, b] = buildtrainset(imgs_sample, imgs_sample_num);
  4. net = bpann(a', b');
  5. % bp 测试
  6. image_dir=dir('image/*.jpg');
  7. for i = 1: length(image_dir)
  8. str_name = image_dir(i).name;
  9. imgs_test{i} = str_name(1:4);
  10. end
  11. rightnum = 0;
  12. sumnum = 0;
  13. for i = 1 : length(imgs_test)
  14. img_name = imgs_test{i};
  15. imgs = cutting(imread(['image/',img_name,'.jpg']), false);
  16. if (length(imgs) == length(img_name))
  17. for j = 1 : length(img_name)
  18. tmp_num = str2num(img_name(j)) + 1;
  19. %% 等大小化
  20. temp = zeros(max_size);
  21. imgs_size = size(imgs{j});
  22. temp(1:imgs_size(1,1), 1:imgs_size(1,2)) = imgs{j};
  23. imgs{j} = temp;
  24. input_size = numel(temp);
  25. testInput(j, :) = reshape(temp', input_size, 1);
  26. end
  27. size(testInput)
  28. Y = sim( net , testInput' );
  29. mans = [1:4];
  30. for j = 1 : length(img_name)
  31. ymax = 0;
  32. yans = NaN;
  33. for k = 1 : 10
  34. if (ymax < Y(k, j))
  35. ymax = Y(k, j);
  36. yans = k;
  37. end
  38. end
  39. mans(j) = yans-1;
  40. sumnum = sumnum + 1;
  41. if (mans(j) == str2num(img_name(j)))
  42. rightnum = rightnum + 1;
  43. end
  44. end
  45. img_name
  46. mans
  47. end
  48. end
  49. rightdata = [rightnum, sumnum-rightnum]
  50. pie(rightdata, {'right', 'wrong'});
  51. end

经过1500次左右的迭代,收敛精度基本达到了要求:

这里写图片描述

这里写图片描述

识别结果:

  1. 1830
  2. mans =
  3. 1 8 3 0
  4. 2940
  5. mans =
  6. 2 9 4 0
  7. 3742
  8. mans =
  9. 3 7 4 2
  10. 5980
  11. mans =
  12. 5 9 8 0
  13. 6739
  14. mans =
  15. 6 7 3 9
  16. 8240
  17. mans =
  18. 8 2 4 0
  19. 8324
  20. mans =
  21. 8 3 2 4

但遗憾的是,识别正确率并不是100%,而是70%,由于有3组数据在预处理时失败了,并没有被正确的二值化,造成了无法识别,但可以看出,神经网络的识别正确率还是相当高的。

深度卷积网络的图像识别

我们这里使用了一个流行的深度学习工具包DeepLearnToolbox,这个工具包可以在github上被找到。 
将其下载下来,然后添加两个path路径,将其引用:

  1. path(path, 'DeepLearnToolbox-master/CNN/')
  2. path(path, 'DeepLearnToolbox-master/util/')
  • 1
  • 2

然后我们构建一个卷积网络的结构struct,并利用类似BP的方式,将数据集构造好:

  1. % 网络训练集构造
  2. [a, b] = buildtrainset_cnn(imgs_sample, imgs_sample_num);
  3. % 16×16的原图片
  4. cnn.layers = {
  5. struct('type', 'i') %input layer
  6. struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer
  7. struct('type', 's', 'scale', 2) %sub sampling layer
  8. struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer
  9. struct('type', 's', 'scale', 2) %sub sampling layer
  10. };
  11. cnn = cnnsetup(cnn, a, b);

而卷积网络的配置如下:

  1. % 学习率
  2. opts.alpha = 2;
  3. % 每次挑出一个batchsize的batch来训练,也就是每用batchsize个样本就调整一次权值,而不是
  4. % 把所有样本都输入了,计算所有样本的误差了才调整一次权值
  5. opts.batchsize = size(a, 3);
  6. % 训练次数,用同样的样本集。我训练的时候:
  7. % 1的时候 11.41% error
  8. % 5的时候 4.2% error
  9. % 10的时候 2.73% error
  10. opts.numepochs = 2000;
  11. % cnn = cnntrain(cnn, a, b, opts); % 如果是还未训练
  12. load cnn_save cnn; %如果已经训练过,载入保存的网络就可以了

这样我们来观察一下网络的结构,这是一个复杂的网络,input是一个16×16的图片,而每次卷积的核都是5×5的,还会有两个降维层。

然后我们会进行测试,和BP网络几乎一样

  1. % 测试
  2. image_dir=dir('image/*.jpg');
  3. for i = 1: length(image_dir)
  4. str_name = image_dir(i).name;
  5. imgs_test{i} = str_name(1:4);
  6. end
  7. rightnum = 0;
  8. sumnum = 0;
  9. for i = 1 : length(imgs_test)
  10. img_name = imgs_test{i};
  11. imgs = cutting(imread(['image/',img_name,'.jpg']), false);
  12. if (length(imgs) == length(img_name))
  13. for j = 1 : length(img_name)
  14. tmp_num = str2num(img_name(j)) + 1;
  15. %% 等大小化
  16. temp = zeros(max_size);
  17. imgs_size = size(imgs{j});
  18. temp(1:imgs_size(1,1), 1:imgs_size(1,2)) = imgs{j};
  19. imgs{j} = temp;
  20. input_size = size(temp);
  21. testInput(:, :, j) = reshape(temp', input_size(1,1), input_size(1,2));
  22. end
  23. % 然后就用测试样本来测试
  24. cnn = cnnff(cnn, testInput);
  25. cnn.o
  26. [~, mans] = max(cnn.o);
  27. img_name
  28. mans = mans-1
  29. % [~, a] = max(y);
  30. % bad = find(mans ~= a);
  31. end
  32. end
  33. %plot mean squared error
  34. plot(cnn.rL);

这里写图片描述

附: 源码仓库

https://github.com/sunxfancy/ANN2

 
 
本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号