Matlab神经网络验证码识别

   2023-02-09 学习力0
核心提示:本文,将会简述如何利用Matlab的强大功能,调用神经网络处理验证码的识别问题。 预备知识,Matlab基础编程,神经网络基础。 可以先看下:Matlab基础视频教程Matlab经典教程——从入门到精通神经网络入门验证码识别原理Matlab对图像读入处理,去掉噪声点和较

本文,将会简述如何利用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的离散点
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

我们看看目标的图片: 
Matlab神经网络验证码识别

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

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

Matlab神经网络验证码识别

切割后的图片:

Matlab神经网络验证码识别

下面我们来写一个完整的函数分割器函数,为了检测正确性,我们这里提供了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);   % 去除连通分量中小于10的离散点

    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);

    %% matlab 设计的实在太烂!真是我有史以来见过的最烂的语言
    %% 函数只有搅成一坨的情况下才能正确运行
    %% 他们根部不知道如何用闭包,以及合理的封装对象

    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;
        % figure;
        % imshow(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
  • 24
  • 25
  • 26
  • 27
  • 28

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

BP网络结构

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

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

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

BP网络的训练及识别

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


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

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

function y = runbp(imgs_sample, imgs_sample_num, max_size)
    % bp 网络训练
    [a, b] = buildtrainset(imgs_sample, imgs_sample_num);
    net = bpann(a', b');

    % bp 测试
    image_dir=dir('image/*.jpg');
    for i = 1: length(image_dir)
        str_name = image_dir(i).name;
        imgs_test{i} = str_name(1:4);
    end

    rightnum = 0;
    sumnum = 0;

    for i = 1 : length(imgs_test)
        img_name = imgs_test{i};
        imgs = cutting(imread(['image/',img_name,'.jpg']), false);
        if (length(imgs) == length(img_name))
            for j = 1 : length(img_name)
                tmp_num = str2num(img_name(j)) + 1;

                %% 等大小化
                temp = zeros(max_size);
                imgs_size = size(imgs{j});
                temp(1:imgs_size(1,1), 1:imgs_size(1,2)) = imgs{j};
                imgs{j} = temp;

                input_size = numel(temp);
                testInput(j, :) = reshape(temp', input_size, 1);
            end
            size(testInput)
            Y = sim( net , testInput' );

            mans = [1:4];
            for j = 1 : length(img_name)
                ymax = 0;
                yans = NaN;
                for k = 1 : 10
                    if (ymax < Y(k, j))
                        ymax = Y(k, j);
                        yans = k;
                    end
                end
                mans(j) = yans-1;

                sumnum = sumnum + 1;
                if (mans(j) == str2num(img_name(j)))
                    rightnum = rightnum + 1;
                end
            end

            img_name
            mans

        end
    end
    rightdata = [rightnum, sumnum-rightnum]
    pie(rightdata, {'right', 'wrong'});

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

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

Matlab神经网络验证码识别

Matlab神经网络验证码识别

识别结果:

1830
mans =
     1     8     3     0

2940
mans =
     2     9     4     0

3742
mans =
     3     7     4     2

5980
mans =
     5     9     8     0

6739
mans =
     6     7     3     9

8240
mans =
     8     2     4     0

8324
mans =
     8     3     2     4
  • 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

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

深度卷积网络的图像识别

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

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

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

    % 网络训练集构造
    [a, b] = buildtrainset_cnn(imgs_sample, imgs_sample_num);

    % 16×16的原图片

    cnn.layers = {
        struct('type', 'i') %input layer
        struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer
        struct('type', 's', 'scale', 2) %sub sampling layer
        struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer
        struct('type', 's', 'scale', 2) %sub sampling layer
    };
    cnn = cnnsetup(cnn, a, b);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

而卷积网络的配置如下:

    % 学习率  
    opts.alpha = 2;  
    % 每次挑出一个batchsize的batch来训练,也就是每用batchsize个样本就调整一次权值,而不是  
    % 把所有样本都输入了,计算所有样本的误差了才调整一次权值  
    opts.batchsize = size(a, 3);   
    % 训练次数,用同样的样本集。我训练的时候:  
    % 1的时候 11.41% error  
    % 5的时候 4.2% error  
    % 10的时候 2.73% error  
    opts.numepochs = 2000;

    % cnn = cnntrain(cnn, a, b, opts);  % 如果是还未训练
    load cnn_save cnn;  %如果已经训练过,载入保存的网络就可以了
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

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

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

% 测试
    image_dir=dir('image/*.jpg');
    for i = 1: length(image_dir)
        str_name = image_dir(i).name;
        imgs_test{i} = str_name(1:4);
    end


    rightnum = 0;
    sumnum = 0;

    for i = 1 : length(imgs_test)
        img_name = imgs_test{i};
        imgs = cutting(imread(['image/',img_name,'.jpg']), false);
        if (length(imgs) == length(img_name))
            for j = 1 : length(img_name)
                tmp_num = str2num(img_name(j)) + 1;

                %% 等大小化
                temp = zeros(max_size);
                imgs_size = size(imgs{j});
                temp(1:imgs_size(1,1), 1:imgs_size(1,2)) = imgs{j};
                imgs{j} = temp;

                input_size = size(temp);
                testInput(:, :, j) = reshape(temp', input_size(1,1), input_size(1,2));
            end

            % 然后就用测试样本来测试  

            cnn = cnnff(cnn, testInput);
            cnn.o
            [~, mans] = max(cnn.o);

            img_name
            mans = mans-1
            % [~, a] = max(y);
            % bad = find(mans ~= a);
        end
    end

    %plot mean squared error  
    plot(cnn.rL);  
  • 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

Matlab神经网络验证码识别

附: 源码仓库

https://github.com/sunxfancy/ANN2

 
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • 如何在Abaqus的python中调用Matlab程序
    目录1. 确定版本信息2. 备份python3. 设置环境变量4. 安装程序5. 调试运行参考资料Abaqus2018操作系统Win10 64位Python版本2.7(路径C:\SIMULIA\CAE\2018\win_b64\tools\SMApy\python2.7)2. 备份python将上述的“python2.7”文件夹复制出来,避免因操作错误
    03-16
  • 如何将极坐标数据转换为笛卡尔坐标系并绘制[MATLAB]
    如何将极坐标数据转换为笛卡尔坐标系并绘制[MAT
    你想做的事考虑根据与原点的距离 $r$ 和 $xy$ 平面上的角度 $heta$ 绘制数据 $P(r, heta)$。例如,雷达获取的信号包含有关目标范围 $r$ 和方位角 $heta$ 的信息。就是下图。在本文中,$heta$ 是从 $x$ 轴测量的角度。显示示例考虑创建依赖于 $r, heta$ 的虚拟
    03-16
  • 【MATLAB与机械设计】一维优化进退法确定初始区间
    【MATLAB与机械设计】一维优化进退法确定初始区
    在讨论一维搜索时,首先保证搜索区间函数具有单峰性,也就是在区间[a,b]中函数是凸函数,对于求极小值问题,函数值具有高—低—高的特性,在区间[a,b]上有唯一的最小值。1,方法的建立2.进退法确定搜索区间的程序框图3,根据上述的程序框图,编写的MATLAB程序
    03-08
  • 用于微型四轮驱动的 6T 小齿轮原型和使用 MATLAB 的 FEM 结构分析
    用于微型四轮驱动的 6T 小齿轮原型和使用 MATLA
    介绍我使用迷你 4WD 套件使用 Raspberry Pi 制作机器人汽车。定制零件丰富且方便,因为它们在附近的商店很容易买到。但是,由于Mini 4WD的速度非常快,因此在低速时很难控制速度。因此,我使用 3D 打印机制作了自己的 6T 小齿轮,并尝试改变齿轮比。 成型小齿
    03-08
  • ROS与Matlab系列:一个简单的运动控制 基于matl
    转自:http://blog.exbot.net/archives/2594Matlab拥有强大的数据处理、可视化绘图能力以及众多成熟的算法函数,非常适合算法开发;在控制系统设计中,Simulink也是普遍使用的设计和仿真工具。而ROS系统,则是一种新的标准化机器人系统软件框架。通过ROS,你
    02-10
  • matlab 遍历结构体struc的成员
    MATLAB中专门用于对结构数组的操作的函数并不多,通过 help datatypes获取数据类型列表,可以看到其中的结构数据类型的有关的函数,主要如表4.3.1所示。表4.3.1 结构数组的操作函数函数名             功能描述 deal                 把输入处
    02-09
  • 02-09
  • schroeder reverb matlab实现
    schroeder reverb matlab实现
    原理参考:Natural sounding artificial reverberation combFilter.m:function output = combFilter(delay, gain, input)fs = 48000;delaySample = int32(delayTime * fs / 1000);B = [1 zeros(1, delaySample - 1)];A=[1 zeros(1, delaySample - 2) -gain];
    02-09
  • C/C++中调用matlab引擎计算 matlab转c
    原帖地址:http://blog.sina.com.cn/s/blog_6adcb3530101cvot.html一,在linux环境使用matlab引擎必须先进行一些必要的配置1,matlab引擎依赖/bin/csh启动,所以不管你使用何种shell,都必须安装csh。**2,matlab引擎依赖的动态库文件目录必须在系统当前的
    02-09
  • MATLAB 图像放大/缩小,双线性插值
    MATLAB 图像放大/缩小,双线性插值
    半年前写过matlab最邻近插值的图像缩放,没怎么考虑边界问题。更早之前用Opencv写过双线性插值图像放大,不过写的比较混乱。所以这里用matlab重新再清楚的写一遍。 1 close all; 2 clear all; 3 clc; 45 m=1.8;%放大或缩小的高度 6 n=2.3;%放大或缩小的宽度 7
    02-09
点击排行