首页 神经网络算法正文

CNN(卷积神经网络) - 卷积计算提取图像边缘

webpro 神经网络算法 2018-09-11 372 0

CNN(卷积神经网络)算法一般应用在图像识别领域,如对数字字母的识别、区分猫狗等。卷积神经网络运算的第一步即使对输入图像进行边缘提

取。这篇文章用来讲解如何对图像的边缘进行提取。

算法思维跨越语言,这里用PHP语言来进行算法的讲解,实际开发中,非常不建议使用PHP来进行多次卷积运算,效率堪忧。

基础不清晰的请阅读本文代码下面的CNN基础,转自 CSDN博主ice_actor 写的一篇文章《吴恩达deeplearning之CNN—卷积神经网络入门》


在这里,将边缘提取用下面两张动态图片加以表示,接下来的算法机理便是基于这两张图片


Cache_-3e0e8fecedbbe99b.gif QQ图片20180911182856.gif

<?php
/**
 * 基于卷积神经网络算法的图像识别
 * Bill
 * 2018年9月7日 08点46分
 */
ini_set('memory_limit','-1');
set_time_limit(0);
header('content-type: text/html; charset=utf-8;');

// $imagePath = './ehuixue/1.jpg';
// $imagePath = './img/1.jpg';
// $imagePath = './img/crh.jpg';
$imagePath = './img/train.jpg';

$array = getimagesize($imagePath);
print_r($array);
echo '<br/>';
echo '<h2>【图像初始样式 - 60%】</h2>';
echo '<img width="60%" src="'.$imagePath.'"/>';
echo '<br/>';
echo '<br/>';
echo '<br/>';

$res = imagecreatefromjpeg($imagePath);
$size = getimagesize($imagePath);
$maxX = $size[0];
$maxY = $size[1];
// // echo "<pre>";
// // echo "<table border=\"1\" cellspacing=\"0\" cellpadding=\"0\">";
// // for ($i = 0; $i < $size[1]; ++$i) { // 行
// //     echo "<tr>";
// //     for ($j = 0; $j < $size[0]; ++$j) { // 列
// //         $rgb = imagecolorat($res, $j, $i);
// //         $rgbarray = imagecolorsforindex($res, $rgb);
// //         echo "<td>";
// //         echo $rgbarray['red'].',<br/>'.$rgbarray['green'].',<br/>'.$rgbarray['blue'];
// //         echo "</td>";
// //     }
// //     echo "<tr>";
// // }
// // echo "</table>";
// // echo "</pre>";
// // echo "<br/>";
$input = array();
$emmm = imagecreatetruecolor($size[0], $size[1]);
for ($i = 0; $i < $size[0]; ++$i) { // x
for ($j = 0; $j < $size[1]; ++$j) { // y
$rgb = imagecolorat($res, $i, $j);
$rgbarray = imagecolorsforindex($res, $rgb);
$rgb = (int)(($rgbarray['red'] + $rgbarray['green']/3 + $rgbarray['blue'])/12);
if($rgb > 20){
$color = imagecolorallocate(  $emmm, 255, 255, 255);
$input[$j][$i] = 255;
}else{
$color = imagecolorallocate(  $emmm, 0, 0, 0);
$input[$j][$i] = 0;
}
// $color = imagecolorallocate(  $emmm, $rgb, $rgb, $rgb);
// $color  =  imagecolorallocate ( $emmm ,  255 ,  0 ,  0 );// 设置颜色 - ps里的选择画笔颜色
imagesetpixel (  $emmm , $i , $j , $color );
}
}
date_default_timezone_set('PRC');
$now = time();
echo '<h2>【灰度化 - 60%】</h2>';
ImagePNG($emmm,'./img/'.$now.'.png');
// imagepng($emmm);
imagedestroy($emmm);// 销毁图片,释放内存
echo '<img width="60%" src="./img/'.$now.'.png"/>';
echo '<br/>';
// $red  =  imagecolorallocate ( $image ,  255 ,  0 ,  0 );// 设置颜色 - ps里的选择画笔颜色
// for($i=0; $i<300; ++$i){
//     imagesetpixel (  $emmm , 100 , $i , $red );
// }
// header('Content-Type:image/jpg');
/////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////
// 二值化// 二值化// 二值化// 二值化// 二值化// 二值化// 二值化//
// 二值化// 二值化// 二值化// 二值化// 二值化// 二值化// 二值化//

// date_default_timezone_set('PRC');
// $now = time();
// ImagePNG($emmm,'./img/'.$now.'.png');
// // imagepng($emmm);
// imagedestroy($emmm);// 销毁图片,释放内存
// echo '<img src="./img/'.$now.'.png"/>';
// echo '<br/>';
// foreach($input as $key => $value){ // 先固定行,即y坐标,$j是y
//     foreach($value as $inner => $x){
//         if($x < 100){
//             echo '1';
//         }else{
//             echo '0';
//         }
//     }
//     echo '<br/>';
// }

/////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////
// 二值化// 二值化// 二值化// 二值化// 二值化// 二值化// 二值化//
// 二值化// 二值化// 二值化// 二值化// 二值化// 二值化// 二值化//

// print_r($input);

/**INPUT padding 处理 */
// 暂时不需要

// $input = $temp;
// print_r($input);
// exit;
// for ( $i = 0; $i < $x; ++$i ) { // 列
//     for ( $j = 0; $j < $y; ++$j ) { // 行
//         if ($input[$i][$j] < 80) { 
//             echo "1";
//         }else{
//             echo "0";
//         }
//     }
//     echo '<br/>';
// }

$output = array(); // 卷积计算后输出

// 卷积计算

echo '<h2>【水平卷积过滤】</h2>';

/**
X过滤,算子:
1  0  -1
1  0  -1
1  0  -1
 */
$wx = array(
0 => array( 1, 0, -1),
1 => array( 1, 0, -1),
2 => array( 1, 0, -1),
);
$wx = array(
0 => array( 1, -1, 1),
1 => array( 1, -1, 0),
2 => array( 1, -1, -1),
);
for( $i = 0; $i < ($maxY - 2); ++$i ){ // 固定行
for( $j = 0; $j < ($maxX - 2); ++$j ){ // 遍历列
$output[$i+1][$j+1] = 0; // 赋初始值
$temp = array(
0 => array( $input[$i+0][$j+0], $input[$i+1][$j+0], $input[$i+2][$j+0] ),
1 => array( $input[$i+0][$j+1], $input[$i+1][$j+1], $input[$i+2][$j+1] ),
2 => array( $input[$i+0][$j+2], $input[$i+1][$j+2], $input[$i+2][$j+2] ),
);
// 卷积计算
for( $m = 0; $m < 3; ++$m){
for( $n = 0; $n < 3; ++$n){
$output[$i+1][$j+1] += $temp[$m][$n] * $wx[$m][$n];
}
}
}
}

echo "<br/>";

echo "<table border=\"1\" cellspacing=\"0\" cellpadding=\"0\">";
for( $i = 0; $i < ($maxY - 2); ++$i ){ // 固定行
echo "<tr>";
for( $j = 0; $j < ($maxX - 2); ++$j ){ // 遍历列
echo "<td>";
echo reluActive($output[$i+1][$j+1]);
echo "</td>";
}
echo "</tr>";
}
echo "</table>";

echo "<br/>";
$emmm = imagecreatetruecolor($maxX - 2, $maxY - 2);
for( $i = 0; $i < ($maxY - 2); ++$i ){ // 固定行
echo "<tr>";
for( $j = 0; $j < ($maxX - 2); ++$j ){ // 遍历列
$rgb = $output[$i+1][$j+1];
$color = imagecolorallocate(  $emmm, $rgb, $rgb, $rgb);
imagesetpixel (  $emmm , $j , $i , $color );
}
}
date_default_timezone_set('PRC');
$now = time();
ImagePNG($emmm,'./img/filtered'.$now.'.png');
// imagepng($emmm);
imagedestroy($emmm);// 销毁图片,释放内存
echo '<img width="60%" src="./img/filtered'.$now.'.png"/>';
echo '<br/>';

$output1 = array(); // 卷积计算后输出

echo '<h2>【垂直卷积过滤】</h2>';

/**
Y过滤,算子:
 1  1  1 
 0  0  0
-1 -1 -1
 */
$wy = array(
0 => array( 1, 1, 1),
1 => array( 0, 0, 0),
2 => array( -1, -1, -1),
);

for( $i = 0; $i < ($maxY - 2); ++$i ){ // 固定行
for( $j = 0; $j < ($maxX - 2); ++$j ){ // 遍历列
$output1[$i+1][$j+1] = 0; // 赋初始值
$temp = array(
0 => array( $input[$i+0][$j+0], $input[$i+1][$j+0], $input[$i+2][$j+0] ),
1 => array( $input[$i+0][$j+1], $input[$i+1][$j+1], $input[$i+2][$j+1] ),
2 => array( $input[$i+0][$j+2], $input[$i+1][$j+2], $input[$i+2][$j+2] ),
);
// 卷积计算
for( $m = 0; $m < 3; ++$m){
for( $n = 0; $n < 3; ++$n){
$output1[$i+1][$j+1] += $temp[$m][$n] * $wy[$m][$n];
}
}
}
}

echo "<br/>";

echo "<table border=\"1\" cellspacing=\"0\" cellpadding=\"0\">";
for( $i = 0; $i < ($maxY - 2); ++$i ){ // 固定行
echo "<tr>";
for( $j = 0; $j < ($maxX - 2); ++$j ){ // 遍历列
echo "<td>";
echo reluActive($output1[$i+1][$j+1]);
echo "</td>";
}
echo "</tr>";
}
echo "</table>";

echo "<br/>";
$emmm = imagecreatetruecolor($maxX - 2, $maxY - 2);
for( $i = 0; $i < ($maxY - 2); ++$i ){ // 固定行
echo "<tr>";
for( $j = 0; $j < ($maxX - 2); ++$j ){ // 遍历列
$rgb = $output1[$i+1][$j+1];
$color = imagecolorallocate(  $emmm, $rgb, $rgb, $rgb);
imagesetpixel (  $emmm , $j , $i , $color );
}
}
date_default_timezone_set('PRC');
$now = time();
ImagePNG($emmm,'./img/filtered1'.$now.'.png');
// imagepng($emmm);
imagedestroy($emmm);// 销毁图片,释放内存
echo '<img width="60%" src="./img/filtered1'.$now.'.png"/>';
echo '<br/>';

$final = array();

echo '<h2>【X+Y卷积结果】</h2>';

// XY合并
for( $i = 0; $i < ($maxY - 2); ++$i ){ // 固定行
for( $j = 0; $j < ($maxX - 2); ++$j ){ // 遍历列
$final[$i][$j] = ($output[$i+1][$j+1])?($output[$i+1][$j+1]):($output1[$i+1][$j+1]);
}
}
echo "<br/>";

echo "<table border=\"1\" cellspacing=\"0\" cellpadding=\"0\">";
for( $i = 0; $i < ($maxY - 2); ++$i ){ // 固定行
echo "<tr>";
for( $j = 0; $j < ($maxX - 2); ++$j ){ // 遍历列
echo "<td>";
echo reluActive($final[$i][$j]);
echo "</td>";
}
echo "</tr>";
}
echo "</table>";

echo "<br/>";
$emmm = imagecreatetruecolor($maxX - 2, $maxY - 2);
for( $i = 0; $i < ($maxY - 2); ++$i ){ // 固定行
echo "<tr>";
for( $j = 0; $j < ($maxX - 2); ++$j ){ // 遍历列
$rgb = $final[$i][$j];
$color = imagecolorallocate(  $emmm, $rgb, $rgb, $rgb);
imagesetpixel (  $emmm , $j , $i , $color );
}
}
date_default_timezone_set('PRC');
$now = time();
ImagePNG($emmm,'./img/final'.$now.'.png');
// imagepng($emmm);
imagedestroy($emmm);// 销毁图片,释放内存
echo '<img width="60%" src="./img/final'.$now.'.png"/>';
echo '<br/>';

function reluActive($x){
return max(0, $x);
}

这里附上train.jpg

train.jpg

灰度化处理后

1536662844.png

水平卷积算法处理

filtered1536662858.png


垂直卷积算法处理

filtered11536662885.png


水平 + 垂直 叠加后 处理

final1536662908.png


至此,train.jpg的边缘通过卷积计算提取了出来


=================================================


下面的CNN基础转自 CSDN博主ice_actor 写的一篇文章《吴恩达deeplearning之CNN—卷积神经网络入门》

本文拿来引用,仅供学习交流


1.边界检测示例

假如你有一张如下的图像,你想让计算机搞清楚图像上有什么物体,你可以做的事情是检测图像的垂直边缘和水平边缘。 
这里写图片描述
如下是一个6*6的灰度图像,构造一个3*3的矩阵,在卷积神经网络中通常称之为filter,对这个6*6的图像进行卷积运算,以左上角的-5计算为例 
3*1+0*0+1*-1+1*1+5*0+8*-1+2*1+7*0+2*-1 = -5 
其它的以此类推,让过滤器在图像上逐步滑动,对整个图像进行卷积计算得到一幅4*4的图像。 
这里写图片描述
为什么这种卷积计算可以得到图像的边缘,下图0表示图像暗色区域,10为图像比较亮的区域,同样用一个3*3过滤器,对图像进行卷积,得到的图像中间亮,两边暗,亮色区域就对应图像边缘。 
这里写图片描述
通过以下的水平过滤器和垂直过滤器,可以实现图像水平和垂直边缘检测。 
这里写图片描述
以下列出了一些常用的过滤器,对于不同的过滤器也有着不同的争论,在卷积神经网络中把这些过滤器当成我们要学习的参数,卷积神经网络训练的目标就是去理解过滤器的参数。 
这里写图片描述

2. padding

在上部分中,通过一个3*3的过滤器来对6*6的图像进行卷积,得到了一幅4*4的图像,假设输出图像大小为n*n与过滤器大小为f*f,输出图像大小则为(nf+1)(nf+1)。 
这样做卷积运算的缺点是,卷积图像的大小会不断缩小,另外图像的左上角的元素只被一个输出所使用,所以在图像边缘的像素在输出中采用较少,也就意味着你丢掉了很多图像边缘的信息,为了解决这两个问题,就引入了padding操作,也就是在图像卷积操作之前,沿着图像边缘用0进行图像填充。对于3*3的过滤器,我们填充宽度为1时,就可以保证输出图像和输入图像一样大。 
这里写图片描述
padding的两种模式: 
Valid:no padding 
输入图像n*n,过滤器f*f,输出图像大小为:(nf+1)(nf+1) 
Same:输出图像和输入图像一样大

3.卷积步长

卷积步长是指过滤器在图像上滑动的距离,前两部分步长都默认为1,如果卷积步长为2,卷积运算过程为: 
这里写图片描述
这里写图片描述
这里写图片描述
加入stride后卷积图像大小的通用计算公式为: 
输入图像:n*n,过滤器:f*f步长:s,padding:p 
输出图像大小为:(n+2pfs+1))(n+2pfs+1)表示向下取整

以输入图像7*7,过滤器3*3,步长为2,padding模式为valid为例输出图像大小为:(7+2032+1)7+2032+1)=33

4.彩色图像的卷积

以上讲述的卷积都是灰度图像的,如果想要在RGB图像上进行卷积,过滤器的大小不在是3*3而是有3*3*3,最后的3对应为通道数(channels),卷积生成图像中每个像素值为3*3*3过滤器对应位置和图像对应位置相乘累加,过滤器依次在RGB图像上滑动,最终生成图像大小为4*4。 
这里写图片描述
另外一个问题是,如果我们在不仅仅在图像总检测一种类型的特征,而是要同时检测垂直边缘、水平边缘、45度边缘等等,也就是多个过滤器的问题。如果有两个过滤器,最终生成图像为4*4*2的立方体,这里的2来源于我们采用了两个过滤器。如果有10个过滤器那么输出图像就是4*4*10的立方体。 
这里写图片描述

5.单层卷积网络

通过上一节的讲述,图像通过两个过滤器得到了两个4*4的矩阵,在两个矩阵上分别加入偏差b1b2,然后对加入偏差的矩阵做非线性的Relu变换,得到一个新的4*4矩阵,这就是单层卷积网络的完整计算过程。用公式表示: 

z[1]=w[1]a[0]+b[1]
a[1]=g(z[1])


其中输入图像为a[0],过滤器用w[1]表示,对图像进行线性变化并加入偏差得到矩阵z[1]a[1]是应用Relu激活后的结果。 
这里写图片描述


  • 如果有10个过滤器参数个数有多少个呢? 
    每个过滤器都有3*3*3+1=28个参数,3*3*3为过滤器大小,1是偏差系数,10个过滤器参数个数就是28*10=280个。不论输入图像大小参数个数是不会发生改变的。

  • 描述卷积神经网络的一些符号标识: 
    l为一个卷积层: 
    f[l]:第l层过滤器的大小 
    p[l]:第l层padding的数量 
    s[l]:第l层步长大小 
    nCl:过滤器的个数 
    Input: 
    nHl1×nWl1×nCl1l1层输入图像的高、宽以及通道数。 
    Output: 
    nHl×nWl×nCl:输出图像的高、宽以及通道数 
    输出图像的大小: 
    nHl=nHl1+2plf[l]sl+1 
    nWl=nWl1+2plf[l]sl+1 
    输出图像的通道数就是过滤器的个数 
    这里写图片描述

6.简单卷积网络示例

  • 输入图像:39*39*3,符号表示:nH[0]=nW[0]=39 ;nc[0]=3

  • 第1层超参数:f[l]=3(过滤器大小);s[l]=1(步长);p[l]=0(padding大小);nC[l]=10(过滤器个数)

  • 第1层输出图像:37*37*10,符号表示:nH[1]=nW[1]=37 ;nc[1]=10

  • 第2层超参数:f[2]=5s[2]=2p[2]=0nC[2]=20

  • 第2层输出图像:17*17*20,符号表示:nH[2]=nW[2]=17 ;nc[2]=20

  • 第3层超参数:f[3]=5s[3]=2p[2]=0nC[3]=40

  • 第3层输出图像:7*7*40,符号表示:nH[3]=nW[3]=17 ;nc[3]=40

  • 将第三层的输出展开成1960个元素

  • 然后将其输出到logistic或softmax来决定是判断图片中有没有猫,还是想识别图像中K中不同的对象 
    这里写图片描述
    卷积神经网络层的类型:

  • 卷积层(convolution,conv)

  • 池化层(pooling,pool)

  • 全连接层(Fully connected,FC)

7.池化层

最大池化(Max pooling) 
最大池化思想很简单,以下图为例,把4*4的图像分割成4个不同的区域,然后输出每个区域的最大值,这就是最大池化所做的事情。其实这里我们选择了2*2的过滤器,步长为2。在一幅真正的图像中提取最大值可能意味着提取了某些特定特征,比如垂直边缘、一只眼睛等等。 
这里写图片描述
以下是一个过滤器大小为3*3,步长为1的池化过程,具体计算和上面相同,最大池化中输出图像的大小计算方式和卷积网络中计算方法一致,如果有多个通道需要做池化操作,那么就分通道计算池化操作。 
这里写图片描述
平均池化和最大池化唯一的不同是,它计算的是区域内的平均值而最大池化计算的是最大值。在日常应用使用最多的还是最大池化。 
这里写图片描述
池化的超参数:步长、过滤器大小、池化类型最大池化or平均池化

8.卷积神经网络示例

以下是一个完整的卷积神经网络,用于手写字识别,这并不是一个LeNet-5网络,但是设计令该来自于LeNet-5。 
这里写图片描述
网络各层参数个数表: 
这里写图片描述


版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

评论

运行

«   2019年10月   »
123456
78910111213
14151617181920
21222324252627
28293031

WebPro统计

Top