2019-08-09 09:32:50 jesseyule 阅读数 331
  • 卷积神经网络与人脸识别实现

    本课程讲解人工神经网络的基本知识,而后详细讲解深度学习的经典模型卷积神经网络 CNN,后基于CNN 讲解一个简单的人脸识别系统。知识点包括:神经元、感知机、BP 算法、梯度优化、卷积运算、池化运算、全连接层、激活函数、深度学习python 实现等。

    3519 人正在学习 去看看 CSDN讲师

在介绍卷积神经网络之前,我们需要先了解以下卷积运算和互相关运算。很多时候,我们都说卷积神经网络在图像处理方面具有很大的优势,主要原因就在于卷积运算,所以接下来就主要从图像处理和卷积的联系入手进行分析。

卷积运算在概率统计中关于随机变量的和的计算中也有出现,从数学上的定义来看,当我们有两个随机变量分别服从密度函数f和g,如果需要求它们的和t的概率密度,那么就有:

s(t)=fg=f(x)g(x+t)dxs(t) = f*g = \int _{-\infty} ^{\infty} f(x) g(-x+t)dx

这是一维的情况,对于二维,我们可以进一步推广:

s(u,v)=fg=f(x,y)g(x+u,y+v)dxdys(u,v) = f*g = \int _{-\infty} ^{\infty} \int _{-\infty} ^{\infty} f(x,y) g(-x+u, -y+v)dxdy

与卷积运算非常相似的还有互相关运算:

r(t)=fg=fu(x)fv(x+t)dxr (t) = f \bigodot g = \int _{-\infty} ^{\infty} f_u (x) f_v (x+t)dx

二维形式:

r(u,v)=fg=fu(x,y)fv(x+u,y+v)dxdyr (u,v) = f \bigodot g = \int _{-\infty} ^{\infty} \int _{-\infty} ^{\infty} f_u (x,y) f_v (x+u, y+v)dxdy

对比卷积运算和互相关运算公式,就可以发现它们形式上是多么相似,唯一的区别只是正负号,这个区别导致卷积运算涉及到函数翻转而互相关运算不涉及的原因,但这里不细说,而是把重点放在分析为什么这种形式的运算会和图像处理产生联系。在运用卷积神经网络进行图像处理时,原则上既可以使用卷积运算也可以使用互相关运算,两者的效果可以做到完全等同只是算法的细节处理上有所不同,而实际上出于简便性的考虑一般会采用互相关运算,所以接下来的分析主要从互相关运算入手,而后文提到的卷积实际上也是指互相关运算。

首先关于图像处理,我们来看这样一个例子,现在我们有一副黑白图像,用矩阵表示,黑色像素点为1,白色像素点为0:

00000100010001000000 \begin{matrix} 0 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 0 \\ \end{matrix}
如果我们现在想要检测这幅图像有没有一条垂直的直线,应该怎么做,这里有一个方法,那就是构建一个反映特征的矩阵,或者说一个具有明显特征的图像矩阵:
010010010 \begin{matrix} 0 & 1 & 0 \\ 0 & 1 & 0 \\ 0 & 1 & 0 \\ \end{matrix}
然后,我们就可以把原图划分成一个个小块,对比是否具有类似我们分析的特征的区域,这个构成,也像我们人类观察的过程,比如我们找一幅图里面有没有眼镜,我们也需要一处处仔细观察,而不能一下子就看完整张图片。那么从数学的角度,这个过程就是原图的矩阵分成和特征矩阵同等大小的一个个小矩阵,比如从左上角开始划分,得到第一个小矩阵:

000010010 \begin{matrix} 0 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 1 & 0 \\ \end{matrix}
用它和特征矩阵按对应元素相乘得到:

000010010 \begin{matrix} 0 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 1 & 0 \\ \end{matrix}
r(1,1)=2r(1,1) = 2

按照这样遍历整副图像,最后把每次计算的结果写成矩阵形式,得到:

203020 \begin{matrix} 2 & 0 \\ 3 & 0 \\ 2 & 0 \\ \end{matrix}
根据这个矩阵,我们可以确定阈值为3,达到阈值就认为原图像存在特征,然后就可以判断在原图像中间偏左的位置存在一条垂直直线。

以上的这个过程,其实就是卷积神经网络的核心思想,也是反映了卷积运算和图像处理的关系,其中,反映特征的矩阵称为卷积核,图像就是我们的输入,两者相乘得到的结果称为特征映射图。

还记得一开始说过,互相关运算反映了函数的平移,这种平移就体现在上面提到的卷积核对输入图像遍历过程中的移动,而互相关运算中的两个函数相乘就反映了输入图像和卷积核相乘,最后积分的步骤就反映了卷积核对输入图像的遍历,所以一次遍历得到一个输出结果,作为特征映射图的一个点的值。

想浏览更多关于数学、机器学习、深度学习的内容,可浏览本人博客

2014-12-07 10:37:41 twobqn123 阅读数 483
  • 卷积神经网络与人脸识别实现

    本课程讲解人工神经网络的基本知识,而后详细讲解深度学习的经典模型卷积神经网络 CNN,后基于CNN 讲解一个简单的人脸识别系统。知识点包括:神经元、感知机、BP 算法、梯度优化、卷积运算、池化运算、全连接层、激活函数、深度学习python 实现等。

    3519 人正在学习 去看看 CSDN讲师
1.使用模板处理图像相关概念:     

      模板:矩阵方块,其数学含义是卷积运算。
      卷积运算:可看作是加权求和的过程,使用到的图像区域中的每个像素分别于卷积核(权矩阵)的每个元素对应相
                乘,所有乘积之和作为区域中心像素的新值。
      卷积核:卷积时使用到的权用一个矩阵表示,该矩阵使用的图像区域大小相同,其行、列都是奇数,
              是一个权矩阵。
      卷积示例:
              3 * 3 的像素区域R与卷积核G的卷积运算:
              R5(中心像素)=R1G1 + R2G2 + R3G3 + R4G4 + R5G5 + R6G6 + R7G7 + R8G8 + R9G9
            

2.使用模板处理图像的问题:
       边界问题:当处理图像边界像素时,卷积与图像使用区域不能匹配,卷积核的中心边界像素点对应,
                 卷积运算将出现问题。
       处理办法:
              A. 忽略边界像素,即处理后的图像将丢掉这些像素。
              B. 保留原边界像素,即copy边界像素到处理后的图像

3.常用模板


如果你刚刚接触图像处理,或者离开大学很长时间,看到卷积这个东西,肯定和我样感到晕菜.那么就复习下,并且实际的写个程序验证下,我保证你这辈子不会再忘记卷积的概念了.我们来看卷积的概念.
连续空间的卷积定义是 f(x)g(x)的卷积是 f(t-x)g(x) 在t从负无穷到正无穷的积分值.t-x要在f(x)定义域内,所以看上去很大的积分实际上还是在定范围的.
实际的过程就是f(x) 先做一个Y轴的反转,然后再沿X轴平移t就是f(t-x),然后再把g(x)拿来,两者乘积的值再积分.想象下如果g(x)或者f(x)是个单位的阶越函数. 那么就是f(t-x)g(x)相交部分的面积.这就是卷积了.
把积分符号换成求和就是离散空间的卷积定义了.那么在图像卷积卷积地是什么意思呢,就是图像就是图像f(x),模板是g(x),然后将模版g(x)在模版中移动,每到一个位置,就把f(x)g(x)的定义域相交的元素进行乘积并且求和,得出新的图像一点,就是被卷积后的图像. 模版又称为卷积核.卷积核做一个矩阵的形状.
卷积定义上是线性系统分析经常用到的.线性系统就是一个系统的输入和输出的关系是线性关系.就是说整个系统可以分解成N多的无关独立变化,整个系统就是这些变化的累加.
如 x1->y1, x2->y2; 那么A*x1 + B*x2 -> A*y1 + B*y2 这就是线性系统. 表示一个线性系统可以用积分的形式 如 Y = Sf(t,x)g(x)dt S表示积分符号,就是f(t,x)表示的是A B之类的线性系数.
看上去很像卷积呀,,对如果f(t,x) = F(t-x) 不就是了吗.从f(t,x)变成F(t-x)实际上是说明f(t,x)是个线性移不变,就是说 变量的差不变化的时候,那么函数的值不变化. 实际上说明一个事情就是说线性移不变系统的输出可以通过输入和表示系统线性特征的函数卷积得到.

2016-06-13 11:20:15 Times_poem 阅读数 8143
  • 卷积神经网络与人脸识别实现

    本课程讲解人工神经网络的基本知识,而后详细讲解深度学习的经典模型卷积神经网络 CNN,后基于CNN 讲解一个简单的人脸识别系统。知识点包括:神经元、感知机、BP 算法、梯度优化、卷积运算、池化运算、全连接层、激活函数、深度学习python 实现等。

    3519 人正在学习 去看看 CSDN讲师

需求说明:深度学习FPGA实现知识储备

内容:第一部分:矩阵的卷积运算详细过程

          第二部分:图像处理之卷积理解

          第三部分:矩阵卷积转换为矩阵相乘

整理来自:时间的诗


第一部分:矩阵的卷积运算详细过程

来自:http://blog.csdn.net/frankyzhangc/article/details/6990782

一个矩阵与另一个矩阵的卷积运算大部分运用在图像处理上,例如用一个模板去对一幅图像进行卷积。

把模板(n*n)放在矩阵上(中心对准要处理的元素),用模板的每个元素去乘矩阵中的的元素,累加和等于这个元素例如例子中的第二行第二个元素16= 1*2+1*1+1*3+1*1+1*2+1*1+1*2+1*1+1*2+1*1+1*3的计算,依次计算每个元素的值,如果矩阵的中心在边缘就要将原矩阵进行扩展,例如补0,或者直接规定模板的中心距离边缘(n-1)/2个单位以上。

以下举一个简单的例子,并用Matlab来观察

相关MATALB代码

a=[2 1 3 1;1 2 1 2;2 1 3 2;1 3 1 2];
b=[1 1 1;1 1 1;1 1 1];
c=conv2(a,b,'same');
d=conv2(a,b,'full');
fprintf('\na = \n');
disp(a);
fprintf('\nb = \n');
disp(b);
fprintf('\nc = \n');
disp(c);
fprintf('\nd = \n');
disp(d);


MATALB仿真结果

a = 
     2     1     3     1
     1     2     1     2
     2     1     3     2
     1     3     1     2

b = 
     1     1     1
     1     1     1
     1     1     1

c = 
     6    10    10     7
     9    16    16    12
    10    15    17    11
     7    11    12     8

d = 
     2     3     6     5     4     1
     3     6    10    10     7     3
     5     9    16    16    12     5
     4    10    15    17    11     6
     3     7    11    12     8     4
     1     4     5     6     3     2

卷积的计算步骤:
(1)    卷积核绕自己的核心元素顺时针旋转180度(这个千万不要忘了)
(2)    移动卷积核的中心元素,使它位于输入图像待处理像素的正上方
(3)    在旋转后的卷积核中,将输入图像的像素值作为权重相乘
(4)    第三步各结果的和做为该输入像素对应的输出像素

请看用水平和垂直差分算子对矩阵处理后的结果,然后细细体会

a = 
     2     1     3     1
     1     2     1     2
     2     1     3     2
     1     3     1     2
b = 
    -1    -1    -1
     0     0     0
     1     1     1
e = 
    -1     0     1
    -1     0     1
    -1     0     1

c = 
    -3    -4    -5    -3
     0     0    -1    -1
    -1    -1    -1     0
     3     6     6     5

d = 
    -3    -1     0     4
    -4    -2    -1     7
    -6    -1     0     5
    -4    -1     0     4

第二部分:图像处理之卷积理解

来自:http://blog.csdn.net/jia20003/article/details/7038938


图像处理之理解卷积

 

一:什么是卷积

离散卷积的数学公式可以表示为如下形式:

f(x) =  - 其中C(k)代表卷积操作数,g(i)代表样本数据, f(x)代表输出结果。

举例如下:

假设g(i)是一个一维的函数,而且代表的样本数为G = [1,2,3,4,5,6,7,8,9]

假设C(k)是一个一维的卷积操作数, 操作数为C=[-1,0,1]

则输出结果f(x)可以表示为 F=[1,2,2,2,2,2,2,2,1]  //边界数据未处理

 

以上只是一维的情况下,当对一幅二维数字图像加以卷积时,其数学意义可以解释如下:

源图像是作为输入源数据,处理以后要的图像是卷积输出结果,卷积操作数作为Filter

在XY两个方向上对源图像的每个像素点实施卷积操作。如图所示:

 

粉红色的方格每次在X/Y前进一个像素方格,就会产生一个新的输出像素,图中深蓝色的代

表要输出的像素方格,走完全部的像素方格,就得到了所有输出像素。

 

图中,粉红色的矩阵表示卷积操作数矩阵,黑色表示源图像– 每个方格代表一个像素点。

 

二:卷积在数字图像处理中应用

一副数字图像可以看作一个二维空间的离散函数可以表示为f(x, y), 假设有对于二维卷积操

作函数C(u, v) ,则会产生输出图像g(x, y) = f(x, y) *C(u,v), 利用卷积可以实现对图像模糊处理,边缘检测,产生轧花效果的图像。

 

一个简单的数字图像卷积处理流程可以如下:

1.      读取源图像像素

2.      应用卷积操作数矩阵产生目标图像

3.      对目标图像进行归一化处理

4.      处理边界像素

三:一个纯Java的卷积模糊图像效果

 

四:关键代码解释

 

完成对像素点RGB颜色的卷积计算代码如下:

// red color

out3DData[row][col][1] =in3DData[row][col][1] +

       in3DData[row-1][col][1] +

       in3DData[row+1][col][1] +

       in3DData[row][col-1][1] +

       in3DData[row-1][col-1][1] +

       in3DData[row+1][col-1][1] +

       in3DData[row][col+1][1] +

       in3DData[row-1][col+1][1] +

       in3DData[row+1][col+1][1];

             

// green color

out3DData[row][col][2] =in3DData[row][col][2] +

       in3DData[row-1][col][2] +

       in3DData[row+1][col][2] +

       in3DData[row][col-1][2] +

       in3DData[row-1][col-1][2] +

       in3DData[row+1][col-1][2] +

       in3DData[row][col+1][2] +

       in3DData[row-1][col+1][2] +

       in3DData[row+1][col+1][2];

             

// blue color

out3DData[row][col][3] =in3DData[row][col][3] +

       in3DData[row-1][col][3] +

       in3DData[row+1][col][3] +

       in3DData[row][col-1][3] +

       in3DData[row-1][col-1][3] +

       in3DData[row+1][col-1][3] +

       in3DData[row][col+1][3] +

       in3DData[row-1][col+1][3] +

       in3DData[row+1][col+1][3];

 

计算归一化因子以及对卷积结果归一化处理的代码如下:

// find the peak data frominput and output pixel data.

int inpeak = 0;

int outPeak = 0;

for(int row=0; row<srcH; row++) {

    for(int col=0; col<srcW; col++) {

       if(inpeak < in3DData[row][col][1]) {

           inpeak = in3DData[row][col][1];

       }

             

       if(inpeak < in3DData[row][col][2]) {

           inpeak = in3DData[row][col][2];

       }

             

       if(inpeak < in3DData[row][col][3]) {

           inpeak = in3DData[row][col][3];

       }

             

       if(outPeak < out3DData[row][col][1]) {

           outPeak = out3DData[row][col][1];

       }

       if(outPeak < out3DData[row][col][2]) {

           outPeak = out3DData[row][col][2];

       }

       if(outPeak < out3DData[row][col][3]) {

           outPeak = out3DData[row][col][3];

       }

    }

}

 

// normalization

double outputScale = ((double) inpeak) / ((double)outPeak);

for(int row=0; row<srcH; row++) {

    for(int col=0; col<srcW; col++) {

out3DData[row][col][1] = (int)(outputScale * out3DData[row][col][1]);

out3DData[row][col][2] = (int)(outputScale * out3DData[row][col][2]);

out3DData[row][col][3] = (int)(outputScale * out3DData[row][col][3]);

    }

}

 

五:本文没有提及的内容 –边界像素处理

没有处理边缘像素,对边缘像素的处理,有两个可以参考的方法

其一是直接填充法– 超出边界部分的以边界像素填充。

其二是线性插值法– 超出边界部分的以 i/row的像素填充。


第三部分:矩阵卷积转换为矩阵相乘

来自:http://blog.csdn.net/anan1205/article/details/12313593

  两个矩阵卷积转化为矩阵相乘形式——Matlab应用(这里考虑二维矩阵,在图像中对应)两个图像模糊(边缘)操作,假设矩阵A、B,A代表源图像,B代表卷积模板,那么B的取值决定最后运算的结果。

       Matlab中的应用函数——conv2(二维卷积,一维对应conv)

       函数给出的公式定义为:

    

        同一维数据卷积一样,它的实质在于将卷积模板图像翻转(旋转180),这里等同于一维信号的翻转,然后将卷积模板依次从上到下、从左到右滑动,计算在模板与原始图像交集元素的乘积和,该和就作为卷积以后的数值。

        为了验证后续矩阵卷积转化为矩阵相乘,这里给出的conv2的实例描述: 

        假设矩阵A(4*3)、B(2*3)如下:

               

       首先,B需要旋转180,

      命令旋转2次90即可:

      B = rot90(rot90(B));或者B = rot90(h,2);  结果为:

      

      其次:命令conv2函数:

      C = conv2(A,B,‘shape’),该函数的具体操作图示:

                            

       依次计算直至结束,结果数据为:

    

         shape的取值有三种,full代表返回卷积以后的全部数据,size为(mA+mB-1,nA+nB-1)的数据;same代表返回卷积以后的原图size (mA,nA)的部分数据;valid返回size为(mA-mB+1,nA-nB+1)的数据,指的是模板元素全部参加运算的结果数据,即源图像和模板的交集为模板。

        

         矩阵卷积转化为矩阵相乘,网上也有很多方法,通俗化表示为:

A×B = B1*A1;

         需要针对原始数据与模板数据做变换,变换过程如下:

                        

       首先进行周期延拓,补零:

       M = mA+mB-1 = 5;  N = nA+nB-1 = 5,对应卷积以后full数据大小。

      那么初次换换的A和B为:

   

        其次对A1和B1分别进行变换

        转化B1——针对B1以及转换矩阵方法为:

        


          将B1中的每一行向量依次按照B转化为一个方形矩阵Ba~Be,然后针对于每一个方形矩阵按照B矩阵组合成一个新的矩阵B1。B1矩阵的大小为((mA+mB-1)*(nA+nB-1),(mA+mB-1)*(nA+nB-1))。

          转化A1——堆叠向量式

         将上个步骤转换的A1按照行向量顺寻依次转化为一个列向量,那么列向量的大小为((mA+mB-1)*(nA+nB-1),1)大小。

        

        针对实例:具体代码为:

      周期延拓:

       转化A——>A1

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. [m1,n1] = size(A);  [m2,n2] = size(B);  
  2. m=m1+m2-1;n=n1+n2-1;  
  3. AA = padarray(A,[m2-1,n2-1],'post');%%%补零  
  4. BB = padarray(B,[m1-1,n1-1],'post');%%%补零  
  5. AA =AA';  
  6. A1 = AA(:);%%%%  

     转化B——>B1

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. B2(1,:) = BB(1,:);  
  2. for i =2:m  
  3.     B2(i,:) = BB(m-i+2,:);  
  4. end %%%矩阵a ~ e的重新赋值  
  5.   
  6. B4 = zeros(n,n);%%%%%%%每一行转化的方阵  
  7. B1 = zeros(m*n,m*n);%%%%%最后的矩阵  
  8. for i =1:m%%%%%%%%几维向量  
  9.     B = B2(i,:);  
  10.     if sum(sum(abs(B))==0)  
  11.         B4 = zeros(n,n);  
  12.     else  
  13.        for j = 1:n%%%%%%%元素  
  14.            for k =0:n-1%%%%%%%%位置(搞定一行向量转化为方阵的形式)  
  15.                t = mod(j+k,n);  
  16.                if t==0  
  17.                   t = n;  
  18.                end  %%%end if  
  19.                B4(t,k+1) = B(j);  
  20.            end %%%end for  
  21.        end  %%%end for  
  22.        for  k =0:m-1%%%%%%%%每一个转换矩阵在大矩阵中的位置编号(搞定小方阵在大阵中的位置转化为大方阵的形式)  
  23.             t = mod(i+k,m);  
  24.             if t==0  
  25.                 t = m;  
  26.             end  %%%end if  
  27.             B1(k*n+1:(k+1)*n,(t-1)*n+1:t*n) = B4;  
  28.        end  %%%end for  
  29.    end %%%end if else   
  30. end  %%%end for      

     结果数据转化:

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. Result = B1*A1;  
  2. Result = reshape(Result,n,m);  
  3. Result = Result';  

    得到的结果等同于conv2的数据结果:    


   利用matlab接口更快的实现方法:

   还是以5 * 5的原始数据与3*3的卷积核为例子:

   代码如下:
[html] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. dd_data = [1,2,4,5,6;6,8,9,1,3;6,8,9,2,4;7,3,5,7,5;1,5,8,9,3]; % 5 *  5  
  2. f_k = [3,4,5;6,7,8;3,2,1]; % 3 * 3  
  3. dd_data_f_k = conv2(dd_data,f_k,'full'); % matlab 函数接口  
  4. dd_data1 = padarray(dd_data,[2 2],'both'); % 扩充原始数据  
  5. v_dd_data = im2col(dd_data1,[3 3]);% 块数据向量化  
  6. f_k1 = f_k(:);  
  7. f_k1 = f_k1(end : -1 :1);  
  8. f_k1 = f_k1'; % 卷积核的表示  
  9. dd_data_f_k1 = f_k1 * v_dd_data; % 卷积转化为相乘  
  10. dd_data_f_k1 = reshape(dd_data_f_k1,[7 7]); % 转化为结果数据  
2019-06-25 22:03:56 matt45m 阅读数 276
  • 卷积神经网络与人脸识别实现

    本课程讲解人工神经网络的基本知识,而后详细讲解深度学习的经典模型卷积神经网络 CNN,后基于CNN 讲解一个简单的人脸识别系统。知识点包括:神经元、感知机、BP 算法、梯度优化、卷积运算、池化运算、全连接层、激活函数、深度学习python 实现等。

    3519 人正在学习 去看看 CSDN讲师

前言

1.在图像处理中,特别在深度学习图像处理,最常看到图像卷积操作,那什么是卷积呢,卷积就是两个原函数产生一个新的函数,两个函数之间的这种操作就称着卷积,在图像这里的图像卷积也用输入的图像矩阵与一个特定的矩阵进行操作得到一个新的图像。
2.那先了解二维矩阵的卷积是如何运算,之后再讲讲卷积在图像中的应用。

卷积运算

1.一个模板矩阵和另一个输入矩阵进行卷积,是使锚点覆盖在待计算矩阵元素上面,然后计算元素值与被覆盖的卷积核中的值的乘积和。将这个和赋值给当前元素,这就是卷积的过程
那现在假设有待处理矩阵src,模板是Kernel,如下图:
在这里插入图片描述
2.计算公式如下:
在这里插入图片描述
3.这里只演示运算方式,先不对卷积核进行180度旋转,也暂时不考虑扩展边界问题,只拿卷积核与输入矩阵做运算,那么一个44的矩阵与一个33的核运算,不超出边界的计算的话,最终只得到一个22的矩阵,步骤如下图。
在这里插入图片描述
那么最终得到的矩阵是一个2
2的矩阵,如下图:
在这里插入图片描述
4.最终得到的矩阵与原矩阵大小不一致,这肯定不是我们想要的结果,那么这里就要用到扩展边界这个概念,如果不是很清楚什么是边界扩展,可以看我之前的博文,我这里使用特定的值(0)来扩展边界,扩展的大小为卷积核的半径。扩展之后如下图:
在这里插入图片描述
运算时卷积核滑动的步骤:
在这里插入图片描述
运算得到的结果:
在这里插入图片描述
这里只演示卷积的运算方法,没有对卷积核做180度的旋转,也没有对负数取绝对值。

2017-01-17 16:49:45 u010830004 阅读数 1660
  • 卷积神经网络与人脸识别实现

    本课程讲解人工神经网络的基本知识,而后详细讲解深度学习的经典模型卷积神经网络 CNN,后基于CNN 讲解一个简单的人脸识别系统。知识点包括:神经元、感知机、BP 算法、梯度优化、卷积运算、池化运算、全连接层、激活函数、深度学习python 实现等。

    3519 人正在学习 去看看 CSDN讲师

需求说明:深度学习FPGA实现知识储备

内容:第一部分:矩阵的卷积运算详细过程

          第二部分:图像处理之卷积理解

          第三部分:矩阵卷积转换为矩阵相乘

整理来自:时间的诗


第一部分:矩阵的卷积运算详细过程

来自:http://blog.csdn.net/frankyzhangc/article/details/6990782

一个矩阵与另一个矩阵的卷积运算大部分运用在图像处理上,例如用一个模板去对一幅图像进行卷积。

把模板(n*n)放在矩阵上(中心对准要处理的元素),用模板的每个元素去乘矩阵中的的元素,累加和等于这个元素例如例子中的第二行第二个元素16= 1*2+1*1+1*3+1*1+1*2+1*1+1*2+1*1+1*2+1*1+1*3的计算,依次计算每个元素的值,如果矩阵的中心在边缘就要将原矩阵进行扩展,例如补0,或者直接规定模板的中心距离边缘(n-1)/2个单位以上。

以下举一个简单的例子,并用Matlab来观察

相关MATALB代码

a=[2 1 3 1;1 2 1 2;2 1 3 2;1 3 1 2];
b=[1 1 1;1 1 1;1 1 1];
c=conv2(a,b,'same');
d=conv2(a,b,'full');
fprintf('\na = \n');
disp(a);
fprintf('\nb = \n');
disp(b);
fprintf('\nc = \n');
disp(c);
fprintf('\nd = \n');
disp(d);


MATALB仿真结果

a = 
     2     1     3     1
     1     2     1     2
     2     1     3     2
     1     3     1     2

b = 
     1     1     1
     1     1     1
     1     1     1

c = 
     6    10    10     7
     9    16    16    12
    10    15    17    11
     7    11    12     8

d = 
     2     3     6     5     4     1
     3     6    10    10     7     3
     5     9    16    16    12     5
     4    10    15    17    11     6
     3     7    11    12     8     4
     1     4     5     6     3     2

卷积的计算步骤:
(1)    卷积核绕自己的核心元素顺时针旋转180度(这个千万不要忘了)
(2)    移动卷积核的中心元素,使它位于输入图像待处理像素的正上方
(3)    在旋转后的卷积核中,将输入图像的像素值作为权重相乘
(4)    第三步各结果的和做为该输入像素对应的输出像素

请看用水平和垂直差分算子对矩阵处理后的结果,然后细细体会

a = 
     2     1     3     1
     1     2     1     2
     2     1     3     2
     1     3     1     2
b = 
    -1    -1    -1
     0     0     0
     1     1     1
e = 
    -1     0     1
    -1     0     1
    -1     0     1

c = 
    -3    -4    -5    -3
     0     0    -1    -1
    -1    -1    -1     0
     3     6     6     5

d = 
    -3    -1     0     4
    -4    -2    -1     7
    -6    -1     0     5
    -4    -1     0     4

第二部分:图像处理之卷积理解

来自:http://blog.csdn.net/jia20003/article/details/7038938


图像处理之理解卷积

 

一:什么是卷积

离散卷积的数学公式可以表示为如下形式:

f(x) =  - 其中C(k)代表卷积操作数,g(i)代表样本数据, f(x)代表输出结果。

举例如下:

假设g(i)是一个一维的函数,而且代表的样本数为G = [1,2,3,4,5,6,7,8,9]

假设C(k)是一个一维的卷积操作数, 操作数为C=[-1,0,1]

则输出结果f(x)可以表示为 F=[1,2,2,2,2,2,2,2,1]  //边界数据未处理

 

以上只是一维的情况下,当对一幅二维数字图像加以卷积时,其数学意义可以解释如下:

源图像是作为输入源数据,处理以后要的图像是卷积输出结果,卷积操作数作为Filter

在XY两个方向上对源图像的每个像素点实施卷积操作。如图所示:

 

粉红色的方格每次在X/Y前进一个像素方格,就会产生一个新的输出像素,图中深蓝色的代

表要输出的像素方格,走完全部的像素方格,就得到了所有输出像素。

 

图中,粉红色的矩阵表示卷积操作数矩阵,黑色表示源图像– 每个方格代表一个像素点。

 

二:卷积在数字图像处理中应用

一副数字图像可以看作一个二维空间的离散函数可以表示为f(x, y), 假设有对于二维卷积操

作函数C(u, v) ,则会产生输出图像g(x, y) = f(x, y) *C(u,v), 利用卷积可以实现对图像模糊处理,边缘检测,产生轧花效果的图像。

 

一个简单的数字图像卷积处理流程可以如下:

1.      读取源图像像素

2.      应用卷积操作数矩阵产生目标图像

3.      对目标图像进行归一化处理

4.      处理边界像素

三:一个纯Java的卷积模糊图像效果

 

四:关键代码解释

 

完成对像素点RGB颜色的卷积计算代码如下:

// red color

out3DData[row][col][1] =in3DData[row][col][1] +

       in3DData[row-1][col][1] +

       in3DData[row+1][col][1] +

       in3DData[row][col-1][1] +

       in3DData[row-1][col-1][1] +

       in3DData[row+1][col-1][1] +

       in3DData[row][col+1][1] +

       in3DData[row-1][col+1][1] +

       in3DData[row+1][col+1][1];

             

// green color

out3DData[row][col][2] =in3DData[row][col][2] +

       in3DData[row-1][col][2] +

       in3DData[row+1][col][2] +

       in3DData[row][col-1][2] +

       in3DData[row-1][col-1][2] +

       in3DData[row+1][col-1][2] +

       in3DData[row][col+1][2] +

       in3DData[row-1][col+1][2] +

       in3DData[row+1][col+1][2];

             

// blue color

out3DData[row][col][3] =in3DData[row][col][3] +

       in3DData[row-1][col][3] +

       in3DData[row+1][col][3] +

       in3DData[row][col-1][3] +

       in3DData[row-1][col-1][3] +

       in3DData[row+1][col-1][3] +

       in3DData[row][col+1][3] +

       in3DData[row-1][col+1][3] +

       in3DData[row+1][col+1][3];

 

计算归一化因子以及对卷积结果归一化处理的代码如下:

// find the peak data frominput and output pixel data.

int inpeak = 0;

int outPeak = 0;

for(int row=0; row<srcH; row++) {

    for(int col=0; col<srcW; col++) {

       if(inpeak < in3DData[row][col][1]) {

           inpeak = in3DData[row][col][1];

       }

             

       if(inpeak < in3DData[row][col][2]) {

           inpeak = in3DData[row][col][2];

       }

             

       if(inpeak < in3DData[row][col][3]) {

           inpeak = in3DData[row][col][3];

       }

             

       if(outPeak < out3DData[row][col][1]) {

           outPeak = out3DData[row][col][1];

       }

       if(outPeak < out3DData[row][col][2]) {

           outPeak = out3DData[row][col][2];

       }

       if(outPeak < out3DData[row][col][3]) {

           outPeak = out3DData[row][col][3];

       }

    }

}

 

// normalization

double outputScale = ((double) inpeak) / ((double)outPeak);

for(int row=0; row<srcH; row++) {

    for(int col=0; col<srcW; col++) {

out3DData[row][col][1] = (int)(outputScale * out3DData[row][col][1]);

out3DData[row][col][2] = (int)(outputScale * out3DData[row][col][2]);

out3DData[row][col][3] = (int)(outputScale * out3DData[row][col][3]);

    }

}

 

五:本文没有提及的内容 –边界像素处理

没有处理边缘像素,对边缘像素的处理,有两个可以参考的方法

其一是直接填充法– 超出边界部分的以边界像素填充。

其二是线性插值法– 超出边界部分的以 i/row的像素填充。


第三部分:矩阵卷积转换为矩阵相乘

来自:http://blog.csdn.net/anan1205/article/details/12313593

  两个矩阵卷积转化为矩阵相乘形式——Matlab应用(这里考虑二维矩阵,在图像中对应)两个图像模糊(边缘)操作,假设矩阵A、B,A代表源图像,B代表卷积模板,那么B的取值决定最后运算的结果。

       Matlab中的应用函数——conv2(二维卷积,一维对应conv)

       函数给出的公式定义为:

    

        同一维数据卷积一样,它的实质在于将卷积模板图像翻转(旋转180),这里等同于一维信号的翻转,然后将卷积模板依次从上到下、从左到右滑动,计算在模板与原始图像交集元素的乘积和,该和就作为卷积以后的数值。

        为了验证后续矩阵卷积转化为矩阵相乘,这里给出的conv2的实例描述: 

        假设矩阵A(4*3)、B(2*3)如下:

               

       首先,B需要旋转180,

      命令旋转2次90即可:

      B = rot90(rot90(B));或者B = rot90(h,2);  结果为:

      

      其次:命令conv2函数:

      C = conv2(A,B,‘shape’),该函数的具体操作图示:

                            

       依次计算直至结束,结果数据为:

    

         shape的取值有三种,full代表返回卷积以后的全部数据,size为(mA+mB-1,nA+nB-1)的数据;same代表返回卷积以后的原图size (mA,nA)的部分数据;valid返回size为(mA-mB+1,nA-nB+1)的数据,指的是模板元素全部参加运算的结果数据,即源图像和模板的交集为模板。

        

         矩阵卷积转化为矩阵相乘,网上也有很多方法,通俗化表示为:

A×B = B1*A1;

         需要针对原始数据与模板数据做变换,变换过程如下:

                        

       首先进行周期延拓,补零:

       M = mA+mB-1 = 5;  N = nA+nB-1 = 5,对应卷积以后full数据大小。

      那么初次换换的A和B为:

   

        其次对A1和B1分别进行变换

        转化B1——针对B1以及转换矩阵方法为:

        


          将B1中的每一行向量依次按照B转化为一个方形矩阵Ba~Be,然后针对于每一个方形矩阵按照B矩阵组合成一个新的矩阵B1。B1矩阵的大小为((mA+mB-1)*(nA+nB-1),(mA+mB-1)*(nA+nB-1))。

          转化A1——堆叠向量式

         将上个步骤转换的A1按照行向量顺寻依次转化为一个列向量,那么列向量的大小为((mA+mB-1)*(nA+nB-1),1)大小。

        

        针对实例:具体代码为:

      周期延拓:

       转化A——>A1

[plain] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. [m1,n1] = size(A);  [m2,n2] = size(B);  
  2. m=m1+m2-1;n=n1+n2-1;  
  3. AA = padarray(A,[m2-1,n2-1],'post');%%%补零  
  4. BB = padarray(B,[m1-1,n1-1],'post');%%%补零  
  5. AA =AA';  
  6. A1 = AA(:);%%%%  

     转化B——>B1

[plain] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. B2(1,:) = BB(1,:);  
  2. for i =2:m  
  3.     B2(i,:) = BB(m-i+2,:);  
  4. end %%%矩阵a ~ e的重新赋值  
  5.   
  6. B4 = zeros(n,n);%%%%%%%每一行转化的方阵  
  7. B1 = zeros(m*n,m*n);%%%%%最后的矩阵  
  8. for i =1:m%%%%%%%%几维向量  
  9.     B = B2(i,:);  
  10.     if sum(sum(abs(B))==0)  
  11.         B4 = zeros(n,n);  
  12.     else  
  13.        for j = 1:n%%%%%%%元素  
  14.            for k =0:n-1%%%%%%%%位置(搞定一行向量转化为方阵的形式)  
  15.                t = mod(j+k,n);  
  16.                if t==0  
  17.                   t = n;  
  18.                end  %%%end if  
  19.                B4(t,k+1) = B(j);  
  20.            end %%%end for  
  21.        end  %%%end for  
  22.        for  k =0:m-1%%%%%%%%每一个转换矩阵在大矩阵中的位置编号(搞定小方阵在大阵中的位置转化为大方阵的形式)  
  23.             t = mod(i+k,m);  
  24.             if t==0  
  25.                 t = m;  
  26.             end  %%%end if  
  27.             B1(k*n+1:(k+1)*n,(t-1)*n+1:t*n) = B4;  
  28.        end  %%%end for  
  29.    end %%%end if else   
  30. end  %%%end for      

     结果数据转化:

[plain] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. Result = B1*A1;  
  2. Result = reshape(Result,n,m);  
  3. Result = Result';  

    得到的结果等同于conv2的数据结果:    


   利用matlab接口更快的实现方法:

   还是以5 * 5的原始数据与3*3的卷积核为例子:

   代码如下:
[html] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. dd_data = [1,2,4,5,6;6,8,9,1,3;6,8,9,2,4;7,3,5,7,5;1,5,8,9,3]; % 5 *  5  
  2. f_k = [3,4,5;6,7,8;3,2,1]; % 3 * 3  
  3. dd_data_f_k = conv2(dd_data,f_k,'full'); % matlab 函数接口  
  4. dd_data1 = padarray(dd_data,[2 2],'both'); % 扩充原始数据  
  5. v_dd_data = im2col(dd_data1,[3 3]);% 块数据向量化  
  6. f_k1 = f_k(:);  
  7. f_k1 = f_k1(end : -1 :1);  
  8. f_k1 = f_k1'; % 卷积核的表示  
  9. dd_data_f_k1 = f_k1 * v_dd_data; % 卷积转化为相乘  
  10. dd_data_f_k1 = reshape(dd_data_f_k1,[7 7]); % 转化为结果数据  
没有更多推荐了,返回首页