图像处理相关算子

2018-08-11 11:56:00 dbsggal90047018 阅读数 86
Robert算子是一阶微分算子,比较简单,计算量小,对细节反应敏感。
Sobel算子是基于一阶导数的微分算子,其中引入了类似局部平均的运算,对于噪声有平滑作用,能很好地消除噪声的影响,所以计算量变大。
Prewitt算子和Sobel一样,图像中的点用Sobel的两个卷积核卷积,取最大值作为输出值。也增加了计算量。
Canny算子比较复杂,既要计算多个方向的梯度,又要记录方向和大小,然后又进行NMS非极大值抑制,大小阈值,反正很复杂就对了,自己百度一下。

转载于:https://www.cnblogs.com/eilearn/p/9459260.html

2020-03-16 14:33:06 qestion_yz_10086 阅读数 38

opencv图像处理各种算子

  1. Roberts算子

import cv2
import numpy as np
import matplotlib.pyplot as plt
import os
#读取图像
path=os.getcwd()
img_path=path+'\\'+'code.png'
img=cv2.imread(img_path)
lenna_img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)

#灰度化处理图像
grayImage=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

#Roberts算子
kernelx=np.array([[-1,0],[0,1]],dtype=int)
kernely=np.array([[0,-1],[1,0]],dtype=int)
x=cv2.filter2D(grayImage,cv2.CV_16S,kernelx)
y=cv2.filter2D(grayImage,cv2.CV_16S,kernely)

#转uint8
absX=cv2.convertScaleAbs(x)
absY=cv2.convertScaleAbs(y)
Roberts=cv2.addWeighted(absX,0.5,absY,0.5,0)


#用来正常显示中文标签
plt.rcParams['font.sans-serif']=['SimHei']

#显示图像
titles=[u'原始图像','Roberts算子']
images=[lenna_img,Roberts]
for i in range(2):
    plt.subplot(1,2,i+1)
    plt.imshow(images[i])
    plt.title(titles[i])
    plt.xticks([])
    plt.yticks([])
plt.show()

在这里插入图片描述
3. Prewitt算子

import cv2
import numpy as np
import matplotlib.pyplot as plt
import os
path=os.getcwd()
img_path=path+'\\'+'code.png'
img=cv2.imread(img_path)
res1=cv2.resize(img,None,fx=2,fy=2,interpolation=cv2.INTER_CUBIC)
lenna_img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
#灰度化处理图像
grayImage=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

#Prewitt算子
kernelx=np.array([[1,1,1],[0,0,0],[-1,-1,-1]],dtype=int)
kernely=np.array([[-1,0,1],[-1,0,1],[-1,0,1]],dtype=int)
x=cv2.filter2D(grayImage,cv2.CV_16S,kernelx)
y=cv2.filter2D(grayImage,cv2.CV_16S,kernely)

#转uint8
absX=cv2.convertScaleAbs(x)
absY=cv2.convertScaleAbs(y)
Prewitt=cv2.addWeighted(absX,0.5,absY,0.5,0)

#用来正常显示中文标签
plt.rcParams['font.sans-serif']=['SimHei']

#显示图像
titles=[u'原始图像','Prewitt算子']
images=[lenna_img,Prewitt]
for i in range(2):
    plt.subplot(1,2,i+1)
    plt.imshow(images[i])
    plt.title(titles[i])
    plt.xticks([])
    plt.yticks([])
plt.show()

在这里插入图片描述
5. Sobel算子

import cv2
import numpy as np
import matplotlib.pyplot as plt
import os
path=os.getcwd()
img_path=path+'\\'+'code.png'
img=cv2.imread(img_path)
res1=cv2.resize(img,None,fx=2,fy=2,interpolation=cv2.INTER_CUBIC)
lenna_img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
#灰度化处理图像
grayImage=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

#Sobel算子
x=cv2.Sobel(grayImage,cv2.CV_16S,1,0) #对x求一阶导
y=cv2.Sobel(grayImage,cv2.CV_16S,0,1) #对y求一阶导

#转uint8
absX=cv2.convertScaleAbs(x)
absY=cv2.convertScaleAbs(y)
Sobel=cv2.addWeighted(absX,0.5,absY,0.5,0)

#用来正常显示中文标签
plt.rcParams['font.sans-serif']=['SimHei']

#显示图像
titles=[u'原始图像','Sobel算子']
images=[lenna_img,Sobel]
for i in range(2):
    plt.subplot(1,2,i+1)
    plt.imshow(images[i])
    plt.title(titles[i])
    plt.xticks([])
    plt.yticks([])
plt.show()

在这里插入图片描述
7. Laplacian算子

import cv2
import numpy as np
import matplotlib.pyplot as plt
import os
path=os.getcwd()
img_path=path+'\\'+'code.png'
img=cv2.imread(img_path)
res1=cv2.resize(img,None,fx=2,fy=2,interpolation=cv2.INTER_CUBIC)
lenna_img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
#灰度化处理图像
grayImage=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

#拉普拉斯算法
dst=cv2.Laplacian(grayImage,cv2.CV_16S,ksize=3)
Laplocian=cv2.convertScaleAbs(dst)
#用来正常显示中文标签
plt.rcParams['font.sans-serif']=['SimHei']

#显示图像
titles=[u'原始图像','Laplacian算子']
images=[lenna_img,Laplocian]
for i in range(2):
    plt.subplot(1,2,i+1)
    plt.imshow(images[i])
    plt.title(titles[i])
    plt.xticks([])
    plt.yticks([])
plt.show()

在这里插入图片描述

2018-09-21 09:00:13 zqx951102 阅读数 1730

OpenCV-跟我一起学数字图像处理之拉普拉斯算子

Laplace算子和Sobel算子一样,属于空间锐化滤波操作。起本质与前面的Spatial Filter操作大同小异,下面就通过Laplace算子来介绍一下空间锐化滤波,并对OpenCV中提供的Laplacian函数进行一些说明。

  • 数学原理

离散函数导数

离散函数的导数退化成了差分,一维一阶差分公式和二阶差分公式分别为,

CodeCogsEqn

CodeCogsEqn(2)

Laplace算子的差分形式

分别对Laplace算子x,y两个方向的二阶导数进行差分就得到了离散函数的Laplace算子。

在一个二维函数f(x,y)中,x,y两个方向的二阶差分分别为,

CodeCogsEqn(3)

CodeCogsEqn(4)

所以Laplace算子的差分形式为,

CodeCogsEqn(5)

写成filter mask的形式如下,

0 1 0
1 -4 1
0 1 0
注意该mask的特点,mask在上下左右四个90度的方向上结果相同,也就是说在90度方向上无方向性。为了让该mask在45度的方向上也具有该性质,对该filter mask进行扩展定义为,
1 1 1
1 -8 1
1 1 1
 

注:

有时我们也会见到不同于上述结果的Laplace算子的filter mask,

0 -1 0
-1 4 -1
0 -1 0
 
-1 -1 -1
-1 8 -1
-1 -1 -1

其原因是在定义二阶导数的时候采用了相反的定义,这个无关紧要,但是要注意,当用Laplace算子滤波后的图像与原图叠加时,混合操作是加还是减因上述的定义而异。

图像的Laplace操作

如同本文开始时说的那样,将Laplace算子写成filter mask后,其操作大同小异于其他的空间滤波操作。将filter mask在原图上逐行移动,然后mask中数值与其重合的像素相乘后求和,赋给与mask中心重合的像素,对图像的第一,和最后的行和列无法做上述操作的像素赋值零,就得到了拉普拉斯操作结果。

拉普拉斯操作结果与原图的混合

因为Laplace算子是二阶导数操作,其在强调图像素中灰度不连续的部分的同时也不在强调灰度值连续的部分。这样会产生一个具有很明显的灰度边界,但是没有足够特征的黑色背景。背景特征可以通过原图像与Laplace算子操作后的图像混合恢复。用公式,

CodeCogsEqn(6)

其中的参数c的取值和上面的两种mask定义有关,当mask中心的数值取正时c=-1,相反c=1;

  • 基于OpenCV的Laplace算子的计算

OpenCV中Laplacian函数可以实现对图像的Laplace操作,具体用法如下,

Laplacian( src_gray, dst, ddepth, kernel_size, scale, delta, BORDER_DEFAULT );

参数意义为,

  1. src_gray,输入图像
  2. dst,Laplace操作结果
  3. ddepth,输出图像深度,因为输入图像一般为CV_8U,为了避免数据溢出,输出图像深度应该设置为CV_16S
  4. kernel_size,filter mask的规模,我们的mask时3x3的,所以这里应该设置为3
  5. scale,delta,BORDER_DEFAULT,默认设置就好

基于OpenCV的Laplace算子仿真代码段如下,

//load the Original Image and get some informations
Mat src = imread("012.jpg",0);
namedWindow("OriginalImage");
imshow("OriginalImage",src);
CV_Assert(src.depth() == CV_8U);

//OpenCV solution - Laplacian
Mat dst,abs_dst_laplace;
Laplacian(src,dst,CV_16S,
3);
convertScaleAbs(dst,abs_dst_laplace);

//show the result
namedWindow(result_laplacian);
imshow(
result_laplacian,abs_dst_laplace);

其中convertScaleAbs函数功能是将CV_16S型的输出图像转变成CV_8U型的图像。

仿真结果:

原图:

original

Laplace操作结果:

abs_dst_laplae

  • 基于mask operation原理仿真

Laplace算子滤波仿真

根据数学原理中介绍的算法,编写相应代码,进行相关仿真。其中对Laplace操作结果进行了图像拉伸显示,因为Laplace操作结果的像素值范围可能落在了[0,255]之外,而计算机在显示的时候将赋值全部置为0,大于255的像素全部显示成255。

代码段如下,

//get some informations of original image
int nr = src.rows;
int nc = src.cols;
int n = nr*nc;
int arr[9] = {0};

//scan the whole pixels of original image
//and do Laplacian Operation
int* table_lap = new int[n];
int* table_orig = new int[n];
int l;
for (int i=0;i<n;i++)
{
table_lap[i]
= 0;
table_orig[i]
= 0;
}
for (int i=1;i<nr-1;i++)
{
const uchar* previous = src.ptr<uchar>(i-1);
const uchar* current = src.ptr<uchar>(i);
const uchar* next = src.ptr<uchar>(i+1);
for (int j=1;j<nc-1;j++)
{
for (int k=0;k<3;k++)
{
arr[k]
= previous[j+k-1];
arr[k
+3] = current[j+k-1];
arr[k
+6] = next[j+k-1];
}
l
= nc*i+j; //calculate the location in the table of current pixel
Lmaskoperation(table_lap,arr,l);
table_orig[l]
= arr[4];
}
}

//pixels scale
uchar* La_scaled = new uchar[n];
table_scale(table_lap,La_scaled,n);

//padding values
Mat LaResult_own;
LaResult_own.create(src.size(),src.type());
uchar
* p = NULL;
for (int i=0;i<nr;i++)
{
p
= LaResult_own.ptr<uchar>(i);
for (int j=0;j<nc;j++)
{
l
= nc*i+j;
p[j]
= La_scaled[l];
}
}

//show results
namedWindow(LaResult_own);
imshow(
LaResult_own,LaResult_own);

其中Lmaskoperation是我写的mask为Laplace mask的mask operation操作函数,函数段如下,

//**********************//
//Laplacian mask operation
//**********************//
void Lmaskoperation(int* table,int* arr,int l)
{
    int tmp[9] = {-1,-1,-1,-1,8,-1,-1,-1,-1};
    for (int i=0;i<9;i++)
    {
        table[l] = table[l] + tmp[i]*arr[i];
    }
}

tabel_scale函数就是我写的图像拉伸函数,将Laplace操作结果拉伸到[0,255],具体函数段如下,

//*****************************//
//scale the pixels to [0 255]
//*****************************//
void table_scale(int* table,uchar* result,int n)
{
    int min = table[0];
    int max = table[0];
    for (int i=0;i<n;i++)
    {
        if(min>table[i])
        {
            min = table[i];
        }
        if(max<table[i])
        {
            max = table[i];
        }
    }
    for (int i=0;i<n;i++)
    {
        result[i] = (uchar)(255*(table[i]-min)/(max-min));
    }
}

仿真结果,拉伸后Laplace算子的操作结果

LaResult_own

以灰色为主色调的显示结果就是Laplace算子操作拉伸后显示的一大特点。

Laplace滤波图像与原图像的混合

我使用的mask中心值为正,所以混合操作需要原图减去Laplace滤波图像,代码段如下,

//blending with the original image using Eq g(x,y)=f(x,y)+c*Lap(x,y)
int* table_blend = new int[n];
for(int i=0;i<n;i++)
{
    table_blend[i] = table_orig[i] - table_lap[i];
    if(table_blend[i]<0)
    {
        table_blend[i] = 0;
    }
    else if (table_blend[i]>255)
    {
        table_blend[i] = 255;
    }
}

//padding values to blending result
Mat Blresult;
Blresult.create(src.size(),src.type());
for (int i=0;i<nr;i++)
{
p
= Blresult.ptr<uchar>(i);
for(int j=0;j<nc;j++)
{
l
= nc*i+j;
p[j]
= table_blend[l];
}
}

//show blending result
namedWindow(blending result_laplacian);
imshow(
blending result_laplacian,Blresult);

仿真结果:

blending result_laplacian

最后给出冈萨雷斯在介绍Laplacian时所给素材的仿真结果

blending result_laplacian

2017-04-29 11:21:25 XiaoHeiBlack 阅读数 2126

测试图

这里写图片描述

sobel算子

sobel算子模板为

w1=101202101

w2=121000121

运行结果如下(白框左上角区域)
这里写图片描述
可以看到特性为:1.两个像素宽 2.顶点值最大

roborts算子

roborts算子模板为

w1=1001

w1=0110

运行结果如下
这里写图片描述
特点 1.单线宽 2.各个点值相同

拉普拉斯算子

w=111181111

结果图:
这里写图片描述
结果复合阶跃边缘二阶导的形式——正负梯度过零点,这里零点在-3和3之间。若取亚像素则为两个像素的正中间。比较上的算子,发现可以有l拉普拉斯算子可以有以下功能
1.如果直接取abs则可以作为边缘检测算子来做,和sobel结果相似。
2.设置原图为f,拉普拉斯后结果为g,则f=f-g可以达到增强边缘(纹理)的效果。也就是增强了边缘的对比度,比如原来差为X如此一正一负加上后,对比度肯定大于X。

但是我们也可以直观的感受到拉普拉斯算子对噪声会比其他算子更加敏感,因为孤立的点的噪声点也会有很大的响应。所以在做拉普拉斯之前都会有个高斯模糊的操作(LoG),根据卷积计算的特性,可以先计算LoG的算子,再用原图和该算子卷积计算,不需要做两遍。例如

w=00100012101216210121000100

—————————-2017.5.20 更新——————————-
最近在看《特征提取与图像处理》,对二阶模板多了一些理解。拉普拉斯相比sobel,不需要乘法和开方来计算边缘强度。但是多了一步过零点检测,有符号模板法、曲线拟合法等,可以搜到相关文献。且二阶目标是缺少方向信息的。但实际应用中谁优谁劣应该还是看图像本身的属性。以后若项目中遇到这样的问题,在此文中继续更新。

2018-01-28 23:47:45 fengye2two 阅读数 40763

首先感谢以下两位的渊博知识:

(1)爱鱼         https://www.cnblogs.com/mightycode/p/6394810.html

(2)mitutao   https://www.cnblogs.com/love6tao/p/5152020.html

图像边缘信息主要集中在高频段,通常说图像锐化或检测边缘,实质就是高频滤波。我们知道微分运算是求信号的变化率,具有加强高频分量的作用。在空域运算中来说,对图像的锐化就是计算微分。由于数字图像的离散信号,微分运算就变成计算差分或梯度。图像处理中有多种边缘检测(梯度)算子,常用的包括普通一阶差分,Robert算子(交叉差分),Sobel算子等等,是基于寻找梯度强度。拉普拉斯算子(二阶差分)是基于过零点检测。通过计算梯度,设置阈值,得到边缘图像。

何为边缘?图象局部区域亮度变化显著的部分,对于灰度图像来说,也就是灰度值有一个明显变化,既从一个灰度值在很小的缓冲区域内急剧变化到另一个灰度相差较大的灰度值。在提高对景物边缘的敏感性的同时,可以抑制噪声的方法才是好的边缘提取方法。

Canny算子求边缘点具体算法步骤如下:

1. 用高斯滤波器平滑图像.

2. 用一阶偏导有限差分计算梯度幅值和方向.

3. 对梯度幅值进行非极大值抑制.

4. 用双阈值算法检测和连接边缘.


第一步:灰度化 

把彩色图像变成灰度图像,该部分是按照Canny算法通常处理的图像为灰度图,如果获取的彩色图像,那首先就得进行灰度化。以RGB格式的彩图为例,通常灰度化采用的公式是:

Gray=0.299R+0.587G+0.114B;

第二步:高斯滤波 

对图像高斯滤波,图像高斯滤波的实现可以用两个一维高斯核分别两次加权实现,也就是先一维X方向卷积,得到的结果再一维Y方向卷积。当然也可以直接通过一个二维高斯核一次卷积实现。也就是二维卷积模板,由于水平有限,只说二维卷积模板怎么算。

       首先,一维高斯函数:

                          

          二维高斯函数:

                                

         模板中每一个点的高斯系数可以由上面的公式计算,这样得到的是不是最终的模板呢?答案不是,需要归一化,也即是每一个点的系数要除以所有系数之和,这样才是最终的二维高斯模板。

      这个里面有个小知识点,要想计算上面的系数,需要知道高斯函数的标准差σ (sigma),还需要知道选3*3还是5*5的模板,也就是模板要多大,实际应用的时候,这两者是有关系的,根据数理统计的知识,高斯分布的特点就是数值分布在(μ—3σ,μ+3σ)中的概率为0.9974,也就是模板的大小其实就是6σ这么大就OK了,但是6σ可能不是奇数,因为我们一定要保证有核心。所以模板窗口的大小一般采用1+2*ceil(3*nSigma) ceil是向上取整函数,例如ceil(0.6)=1。

       计算得到模板,那就是直接卷积就OK,卷积的意思就是图像中的点附近的模板大小区域乘以高斯模板区域,得到的结果就是该点卷积后的结果。卷积的核心意义就是获取原始图像中像模板特征的性质。

第三步:计算梯度值和方向 

图像的边缘可以指向不同方向,因此经典Canny算法用了四个梯度算子来分别计算水平,垂直和对角线方向的梯度。但是通常都不用四个梯度算子来分别计算四个方向。常用的边缘差分算子(如Rober,Prewitt,Sobel)计算水平和垂直方向的差分Gx和Gy。这样就可以如下计算梯度模和方向:

梯度角度θ范围从弧度-π到π,然后把它近似到四个方向,分别代表水平,垂直和两个对角线方向(0°,45°,90°,135°)。可以以±iπ/8(i=1,3,5,7)分割,落在每个区域的梯度角给一个特定值,代表四个方向之一。

这里选择Sobel算子计算梯度,相对于其他边缘算子,Sobel算子得出来的边缘粗大明亮。

 

 

 

下图是对上面半径2的高斯模糊图像L通道(HSL)应用Sobel算子的梯度模图,没有施加任何值。

           Sobel算子,无

第四步:非极大值抑制

非极大值抑制是进行边缘检测的一个重要步骤,通俗意义上是指寻找像素点局部最大值。沿着梯度方向,比较它前面和后面的梯度值进行了。见下图。

     

   上图中左右图:g1、g2、g3、g4都代表像素点,很明显它们是c的八领域中的4个,左图中c点是我们需要判断的点,蓝色的直线是它的梯度方向,也就是说c要是局部极大值,它的梯度幅值M需要大于直线与g1g2和g2g3的交点,dtmp1和dtmp2处的梯度幅值。但是dtmp1和dtmp2不是整像素,而是亚像素,也就是坐标是浮点的,那怎么求它们的梯度幅值呢?线性插值,例如dtmp1在g1、g2之间,g1、g2的幅值都知道,我们只要知道dtmp1在g1、g2之间的比例,就能得到它的梯度幅值,而比例是可以靠夹角计算出来的,夹角又是梯度的方向。

    写个线性插值的公式:设g1的幅值M(g1),g2的幅值M(g2),则dtmp1可以很得到:

        M(dtmp1)=w*M(g2)+(1-w)*M(g1)  

       其中w=distance(dtmp1,g2)/distance(g1,g2)      

    distance(g1,g2) 表示两点之间的距离。实际上w是一个比例系数,这个比例系数可以通过梯度方向(幅角的正切和余切)得到。

右边图中的4个直线就是4个不同的情况,情况不同,g1、g2、g3、g4代表c的八领域中的4个坐标会有所差异,但是线性插值的原理都是一致的。

下图是非最大值抑制的结果。可见边缘宽度已经大大减小。但是这个图像中因为没有应用任何值,还含有大量小梯度模值的点,也就是图中很暗的地方。下面,值要上场了。

             非最大值抑制结果


第五步:双阈值的选取

一般的边缘检测算法用一个值来滤除噪声或颜色变化引起的小的梯度值,而保留大的梯度值。Canny算法应用双值,即一个高值和一个低值来区分边缘像素。如果边缘像素点梯度值大于高值,则被认为是强边缘点。如果边缘梯度值小于高值,大于低值,则标记为弱边缘点。小于低值的点则被抑制掉。

第六步:滞后边界跟踪

强边缘点可以认为是真的边缘。弱边缘点则可能是真的边缘,也可能是噪声或颜色变化引起的。为得到精确的结果,后者引起的弱边缘点应该去掉。通常认为真实边缘引起的弱边缘点和强边缘点是连通的,而又噪声引起的弱边缘点则不会。所谓的滞后边界跟踪算法检查一个弱边缘点的8连通领域像素,只要有强边缘点存在,那么这个弱边缘点被认为是真是边缘保留下来。

这个算法搜索所有连通的弱边缘,如果一条连通的弱边缘的任何一个点和强边缘点连通,则保留这条弱边缘,否则抑制这条弱边缘。搜索时可以用广度优先或者深度优先算法,我在这里实现了应该是最容易的深度优先算法。一次连通一条边缘的深度优先算法如下:

  1. 准备一个栈s,一个队列q,设联通指示变量connected为假。从图像的第一个点开始,进入2。
  2. 如果这个点是弱边界点并且没有被标记,把它标记,并把它作为第一个元素放入栈s中,同时把它放入记录连通曲线的队列q,进入3。如果这个点不是弱边界或者已经被标记过,到图像的下一个点,重复2。
  3. 从栈s中取出一个元素,查找它的8像素领域。如果一个领域像素是弱边界并且没有被标记过,把这个领域像素标记,并加入栈s中,同时加入队列q。同时查找领域对应的强边界图,如果有一个像素是强边界,表示这条弱边界曲线和强边界联通,设置connected为真。重复3直到栈中没有元素了。如果connected为假,则依次从队列q中取出每个元素,清空标记。如果connected为真,保留标记。
  4. 清空队列q,设置connected为假,移动到图像的下一个点,到2。
第七步:结果查看

下面是对Lena图计算Canny边缘检测的梯度模图和二值化图,高斯半径2,高值100,低值50。

   

             Canny检测梯度模图                        Canny检测梯度二值图

作为对比,下面是用一阶差分和Sobel算子对原图计算的结果,阀值100。由于一阶差分的梯度值相对较小,我对一阶差分的梯度值放大了一定倍数,使得它和Sobel的梯度值保持同样的水平。

   

               一阶差分梯度模图                        一阶差分梯度二值图

   

                 Sobel梯度模图                          Sobel梯度二值图

很明显,Canny边缘检测的效果是很显著的。相比普通的梯度算法大大抑制了噪声引起的伪边缘,而且是边缘细化,易于后续处理。对于对比度较低的图像,通过调节参数,Canny算法也能有很好的效果。

原图   

Canny边缘梯度模,高斯半径2,低阀值30,高阀值100

   Canny边缘梯度二值化图,高斯半径2,低阀值30,高阀值100

从上往下依次为(a)(b)  (c)

(a)原图                       

(b)Canny梯度模,高斯半径2,低值30,高值100       

(c)Canny梯度二值化图,高斯半径2,低值30,高值100

原图

   Canny边缘梯度模,高斯半径1,低阀值40,高阀值80

   Canny边缘梯度二值化图,高斯半径1,低阀值40,高阀值80

从上往下依次为(d)(e)  (f)

(d)原图                       

(e)Canny梯度模,高斯半径1,低值40,高值80       

(f)Canny梯度二值化图,高斯半径1,低值40,高值80