图像处理一阶微分周围取零

2019-04-22 11:54:01 qq_24463801 阅读数 1297
  • SIFT特征提取2

    了解Hough变换基本思想及直线检测步骤; 掌握Harris角点检测的基本思想及实现步骤; 了解尺度空间概念及SIFT特征提取的基本思想 了解ORB中快速特征检测及BRIEF特征建立方法 掌握前述算子的OpenCV实现

    2606人学习 CSDN就业班
    免费试看

转自 https://blog.csdn.net/Scrat000/article/details/81866409

数学基础

       拉普拉斯算子,二阶微分线性算子,为什么上来就学二阶微分算子,前文说过,与一阶微分相比,二阶微分的边缘定位能力更强,锐化效果更好,所以我们来先学习二阶微分算子,使用二阶微分算子的基本方法是定义一种二阶微分的离散形式,然后根据这个形式生成一个滤波模板,与图像卷积。

       各向同性滤波器,图像旋转后响应不变,这就要求滤波模板自身是对称的,如果不对称,结果就是,当原图旋转90°时,原图某一点能检测出细节(突变)的,现在却检测不出来,这就是各向异性的原因。我们更关心的是各向同性滤波模板,对图像的旋转不敏感。

       对于二维图像f(x,y),二阶微分最简单的定义--拉普拉斯算子定义为:


对于任意阶微分算子都是线性算子,所以二阶微分算子和后面的一阶微分算子都可以用生成模板然后卷积的方式得出结果。

根据前面对二阶微分的定义有:


根据上面的定义,与拉普拉斯算子的定义相结合,得到:


也就是一个点的拉普拉斯的算子计算结果是上下左右的灰度的和减去本身灰度的四倍。同样,可以根据二阶微分的不同定义,所有符号相反,也就是上式所有灰度值全加上负号,就是-1,-1,-1,-1,4。但要注意,符号改变,锐化的时候与原图的加或减应当相对变化。上面是四邻接的拉普拉斯算子,将这个算子旋转45°后与原算子相加,就变成八邻域的算子了,也就是一个像素周围一圈8个像素的和与中间像素8倍的差,作为拉普拉斯计算结果。

       因为要强调图像中突变(细节),所以平滑灰度的区域,无响应,即模板系数的和为0,也是二阶微分必备条件。

       最后的锐化公式:


      g是输出,f为原始图像,c是系数,也就是要加上多少细节的多少。

      由于拉普拉斯算子是最简单的各向同性微分算子,它具有旋转不变性。一个二维图像函数的拉普拉斯变换是各向同性的二阶导数,定义为:


用更加形象的图像来解释,假设我们有一张一维图形。下图(a)中灰度值的”跃升”表示边缘的存在.如果使用一阶微分求导我们可以更加清晰的看到边缘”跃升”的存在(这里显示为高峰值)图(b); 如果在边缘部分求二阶导数会出现什么情况?,图(c)所示。(其图片和定义公式来源于http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/imgtrans/laplace_operator/laplace_operator.html)。

  

(a)                                                                                                          (b)

(c)

你会发现在一阶导数的极值位置,二阶导数为0。所以我们也可以用这个特点来作为检测图像边缘的方法。 但是, 二阶导数的0值不仅仅出现在边缘(它们也可能出现在无意义的位置),但是我们可以过滤掉这些点。

为了更适合于数字图像处理,将该方程表示为离散形式:


另外,拉普拉斯算子还可以表示成模板的形式,以便更好编程需要。如图1所示。


图1(a)表示离散拉普拉斯算子的模板,图1(b)表示其扩展模板,图1(c)则分别表示其他两种拉普拉斯的实现模板。从模板形式容易看出,如果在图像中一个较暗的区域中出现了一个亮点,那么用拉普拉斯运算就会使这个亮点变得更亮。因为图像中的边缘就是那些灰度发生跳变的区域,所以拉普拉斯锐化模板在边缘检测中很有用。一般增强技术对于陡峭的边缘和缓慢变化的边缘很难确定其边缘线的位置。但此算子却可用二次微分正峰和负峰之间的过零点来确定,对孤立点或端点更为敏感,因此特别适用于以突出图像中的孤立点、孤立线或线端点为目的的场合。同梯度算子一样,拉普拉斯算子也会增强图像中的噪声,有时用拉普拉斯算子进行边缘检测时,可将图像先进行平滑处理

图像锐化处理的作用是使灰度反差增强,从而使模糊图像变得更加清晰。图像模糊的实质就是图像受到平均运算或积分运算,因此可以对图像进行逆运算,如微分运算能够突出图像细节,使图像变得更为清晰。由于拉普拉斯是一种微分算子,它的应用可增强图像中灰度突变的区域,减弱灰度的缓慢变化区域。因此,锐化处理可选择拉普拉斯算子对原图像进行处理,产生描述灰度突变的图像,再将拉普拉斯图像与原始图像叠加而产生锐化图像。拉普拉斯锐化的基本方法可以由下式表示:


这种简单的锐化方法既可以产生拉普拉斯锐化处理的效果,同时又能保留背景信息,将原始图像叠加到拉普拉斯变换的处理结果中去,可以使图像中的各灰度值得到保留,使灰度突变处的对比度得到增强,最终结果是在保留图像背景的前提下,突现出图像中小的细节信息但其缺点是对图像中的某些边缘产生双重响应。



2019-07-04 15:46:40 guzhao9901 阅读数 1142
  • SIFT特征提取2

    了解Hough变换基本思想及直线检测步骤; 掌握Harris角点检测的基本思想及实现步骤; 了解尺度空间概念及SIFT特征提取的基本思想 了解ORB中快速特征检测及BRIEF特征建立方法 掌握前述算子的OpenCV实现

    2606人学习 CSDN就业班
    免费试看

首先,图像是离散的数据,若求其导数就要用差分的方法,常用的差分方法是前向差分(forward differencing)与中心差分(central differencing)。一阶导本质上求的是斜率,二阶导求的是拐点。

一阶导

连续函数,其微分可表达为

f^{\prime}(x)=\lim _{h \rightarrow 0} \frac{f(x+h)-f(x)}{h} ,或,f^{\prime}(x)=\frac{f(x+h)-f(x-h)}{2 h}                     (1.1)

对于图像这种离散的数据,其可以表达为:

I_{x}=\frac{I(x)-I(x-h)}{h},或,I_{x}=\frac{I(x+h)-I(x-h)}{2 h}                                       (1.2)

以Prewitt一阶微分边缘检测算子为例,其利用像素点上下、左右邻点的灰度差,在边缘处达到极值检测边缘,去掉部分伪边缘,对噪声具有平滑作用 。其原理是在图像空间利用两个方向模板与图像进行邻域卷积来完成的,这两个方向模板一个检测水平边缘,一个检测垂直边缘,这两个方向的模板就是一阶微分运算。具体如下:

G(x)=|[f(i-1, j-1)+f(i-1, j)+f(i-1, j+1)]-[f(i+1, j-1)+f(i+1, j)+f(i+1, j+1)]|        (1.3)

G(y)=|[f(i-1, j+1)+f(i, j+1)+f(i+1, j+1)]-[f(i-1, j-1)+f(i, j-1)+f(i+1, j-1)]|        (1.4)

      G=\max [G(x), G(y)],或,\mathrm{G}=\mathrm{G}(\mathrm{x})+\mathrm{G}(\mathrm{y})                                                          (1.5)

Prewitt梯度算子法就是先求平均,再求差分来求梯度。水平和垂直梯度模板分别为:

G_{x}=\left[\begin{array}{lll}{-1} & {0} & {1} \\ {-1} & {0} & {1} \\ {-1} & {0} & {1}\end{array}\right]         G_{y}=\left[\begin{array}{ccc}{1} & {1} & {1} \\ {0} & {0} & {0} \\ {-1} & {-1} & {-1}\end{array}\right]

二阶导

对于一维函数,其二阶导数为:

f^{\prime \prime}(x)=\lim _{h \rightarrow 0} \frac{f^{\prime}(x+h)-f^{\prime}(x)}{h},即 f^{\prime \prime}(x)=\frac{f(x+h)-2 f(x)+f(x-h)}{h^{2}}          (2.1)

它的差分函数为:

I_{x x}=\frac{I(x+h)-2 I(x)+I(x-h)}{h^{2}}                                                                            (2.2)

二阶导部分以Laplacian边缘检测算子为例。Laplace算子是一种各向同性算子,二阶微分算子,在只关心边缘的位置而不考虑其周围的象素灰度差值时比较合适。Laplace算子对孤立象素的响应要比对边缘或线的响应要更强烈,因此只适用于无噪声图象。存在噪声情况下,使用Laplacian算子检测边缘之前需要先进行低通滤波。所以,通常的分割算法都是把Laplacian算子和平滑算子结合起来生成一个新的模板。拉普拉斯算子也是最简单的各向同性微分算子,具有旋转不变性。

拉普拉斯算子是n维欧式空间的一个二阶微分算子。它定义为两个梯度向量算子的内积:

\triangle \triangleq \nabla^{2} \triangleq \nabla \cdot \nabla=\left(\frac{\partial}{\partial x} \vec{i}+\frac{\partial}{\partial y} \vec{j}\right) \cdot\left(\frac{\partial}{\partial x} \vec{i}+\frac{\partial}{\partial y} \vec{j}\right)=\frac{\partial^{2}}{\partial x^{2}}+\frac{\partial^{2}}{\partial y^{2}}                          (2.3)

其在二维空间上的公式为:

\Delta f=\frac{\partial^{2} f}{\partial x^{2}}+\frac{\partial^{2} f}{\partial y^{2}}                                                                                                            (2.4)

1、对于1维离散情况,其二阶导数变为二阶差分:

1)首先,其一阶差分为:

\nabla f[n]=f^{\prime}[n]=D_{n}[f[n]]=f[n+1]-f[n]                                                                (2.5)

2)因此,二阶差分为:

\begin{aligned} \Delta f[n] =& \nabla^{2} f[n]=f^{\prime \prime}[n]=D_{n}^{2}[f[n]]=f^{\prime}[n]-f^{\prime}[n-1] \\ =&(f[n+1]-f[n])-(f[n]-f[n-1])=f[n+1]-2 f[n]+f[n-1] \end{aligned}         (2.6)

3)因此,1维拉普拉斯运算可以通过1维卷积核[1,-2, 1]实现

2、对于2维离散情况(图像),拉普拉斯算子是2个维上二阶差分的和(见式2.4),其公式为:

\begin{array}{ll}{\Delta f[m, n]} &= {D_{m}^{2}[f[m, n]]+D_{n}^{2}[f[m, n]]=f[m+1, n]-2 f[m, n]+f[m-1, n]+f[m, n+1]-2 f[m, n]+f[m, n-1]} \\ {} &= {f[m+1, n]+f[m-1, n]+f[m, n+1]+f[m, n-1]-4 f[m, n]}\end{array}

其卷积可写为:

\left[\begin{array}{ccc}{0} & {1} & {0} \\ {1} & {-4} & {1} \\ {0} & {1} & {0}\end{array}\right]     

其可拓展为

\left[\begin{array}{ccc}{1} & {1} & {1} \\ {1} & {-8} & {1} \\ {1} & {1} & {1}\end{array}\right]

参考文章:图像处理-线性滤波-2 图像微分(1、2阶导数和拉普拉斯算子)

2015-07-24 10:07:43 mao0514 阅读数 2187
  • SIFT特征提取2

    了解Hough变换基本思想及直线检测步骤; 掌握Harris角点检测的基本思想及实现步骤; 了解尺度空间概念及SIFT特征提取的基本思想 了解ORB中快速特征检测及BRIEF特征建立方法 掌握前述算子的OpenCV实现

    2606人学习 CSDN就业班
    免费试看

一:数学背景

首先看一下一维的微分公式Δf = f(x+1) – f(x), 对于一幅二维的数字图像f(x,y)而言,需要完

成XY两个方向上的微分,所以有如下的公式:

分别对X,Y两个方向上求出它们的偏微分,最终得到梯度Delta F.

对于离散的图像来说,一阶微分的数学表达相当于两个相邻像素的差值,根据选择的梯度算

子不同,效果可能有所不同,但是基本原理不会变化。最常见的算子为Roberts算子,其它

常见还有Sobel,Prewitt等算子。以Roberts算子为例的X,Y的梯度计算演示如下图:


二:图像微分应用

图像微分(梯度计算)是图像边缘提取的重要的中间步骤,根据X,Y方向的梯度向量值,可以

得到如下两个重要参数振幅magnitude, 角度theta,计算公式如下:


Theta = tan-1(yGradient/xGradient)

magnitude表示边缘强度信息

theta预言边缘的方向走势。

假如对一幅数字图像,求出magnitude之后与原来每个像素点对应值相加,则图像边缘将被

大大加强,轮廓更加明显,是一个很典型的sharp filter的效果。

 

三:程序效果

X, Y梯度效果,及magnitude效果


图像微分的Sharp效果:


四:程序源代码

  1. package com.process.blur.study;  
  2.   
  3. import java.awt.image.BufferedImage;  
  4.   
  5. // roberts operator  
  6. // X direction 1, 0  
  7. //             0,-1  
  8. // Y direction 0, 1  
  9. //            -1, 0  
  10.   
  11. public class ImageGradientFilter extends AbstractBufferedImageOp {  
  12.     public final static int X_DIRECTION = 0;  
  13.     public final static int Y_DIRECTION = 2;  
  14.     public final static int XY_DIRECTION = 4;  
  15.       
  16.     private boolean sharp;  
  17.     private int direction;  
  18.       
  19.     public ImageGradientFilter() {  
  20.         direction = XY_DIRECTION; // default;  
  21.         sharp = false;  
  22.     }  
  23.       
  24.     public boolean isSharp() {  
  25.         return sharp;  
  26.     }  
  27.   
  28.     public void setSharp(boolean sharp) {  
  29.         this.sharp = sharp;  
  30.     }  
  31.   
  32.     public int getDirection() {  
  33.         return direction;  
  34.     }  
  35.   
  36.     public void setDirection(int direction) {  
  37.         this.direction = direction;  
  38.     }  
  39.   
  40.     @Override  
  41.     public BufferedImage filter(BufferedImage src, BufferedImage dest) {  
  42.         int width = src.getWidth();  
  43.         int height = src.getHeight();  
  44.   
  45.         if (dest == null )  
  46.             dest = createCompatibleDestImage( src, null );  
  47.   
  48.         int[] inPixels = new int[width*height];  
  49.         int[] outPixels = new int[width*height];  
  50.         getRGB( src, 00, width, height, inPixels );  
  51.         int index = 0;  
  52.         double mred, mgreen, mblue;  
  53.         int newX, newY;  
  54.         int index1, index2, index3;  
  55.         for(int row=0; row<height; row++) {  
  56.             int ta = 0, tr = 0, tg = 0, tb = 0;  
  57.             for(int col=0; col<width; col++) {  
  58.                 index = row * width + col;  
  59.                   
  60.                 // base on roberts operator  
  61.                 newX = col + 1;  
  62.                 newY = row + 1;  
  63.                 if(newX > 0 && newX < width) {  
  64.                     newX = col + 1;  
  65.                 } else {  
  66.                     newX = 0;  
  67.                 }  
  68.                   
  69.                 if(newY > 0 && newY < height) {  
  70.                     newY = row + 1;  
  71.                 } else {  
  72.                     newY = 0;  
  73.                 }  
  74.                 index1 = newY * width + newX;  
  75.                 index2 = row * width + newX;  
  76.                 index3 = newY * width + col;  
  77.                 ta = (inPixels[index] >> 24) & 0xff;  
  78.                 tr = (inPixels[index] >> 16) & 0xff;  
  79.                 tg = (inPixels[index] >> 8) & 0xff;  
  80.                 tb = inPixels[index] & 0xff;  
  81.                   
  82.                 int ta1 = (inPixels[index1] >> 24) & 0xff;  
  83.                 int tr1 = (inPixels[index1] >> 16) & 0xff;  
  84.                 int tg1 = (inPixels[index1] >> 8) & 0xff;  
  85.                 int tb1 = inPixels[index1] & 0xff;  
  86.                   
  87.                 int xgred = tr -tr1;  
  88.                 int xggreen = tg - tg1;  
  89.                 int xgblue = tb - tb1;  
  90.                   
  91.                 int ta2 = (inPixels[index2] >> 24) & 0xff;  
  92.                 int tr2 = (inPixels[index2] >> 16) & 0xff;  
  93.                 int tg2 = (inPixels[index2] >> 8) & 0xff;  
  94.                 int tb2 = inPixels[index2] & 0xff;  
  95.                   
  96.                 int ta3 = (inPixels[index3] >> 24) & 0xff;  
  97.                 int tr3 = (inPixels[index3] >> 16) & 0xff;  
  98.                 int tg3 = (inPixels[index3] >> 8) & 0xff;  
  99.                 int tb3 = inPixels[index3] & 0xff;  
  100.                   
  101.                 int ygred = tr2 - tr3;  
  102.                 int yggreen = tg2 - tg3;  
  103.                 int ygblue = tb2 - tb3;  
  104.                   
  105.                 mred = Math.sqrt(xgred * xgred + ygred * ygred);  
  106.                 mgreen = Math.sqrt(xggreen * xggreen + yggreen * yggreen);  
  107.                 mblue = Math.sqrt(xgblue * xgblue + ygblue * ygblue);  
  108.                 if(sharp) {  
  109.                     tr = (int)(tr + mred);  
  110.                     tg = (int)(tg + mgreen);  
  111.                     tb = (int)(tb + mblue);  
  112.                     outPixels[index] = (ta << 24) | (clamp(tr) << 16) | (clamp(tg) << 8) | clamp(tb);  
  113.                 } else {  
  114.                     outPixels[index] = (ta << 24) | (clamp((int)mred) << 16) | (clamp((int)mgreen) << 8) | clamp((int)mblue);  
  115.                     // outPixels[index] = (ta << 24) | (clamp((int)ygred) << 16) | (clamp((int)yggreen) << 8) | clamp((int)ygblue);  
  116.                     // outPixels[index] = (ta << 24) | (clamp((int)xgred) << 16) | (clamp((int)xggreen) << 8) | clamp((int)xgblue);  
  117.                 }  
  118.                   
  119.                   
  120.             }  
  121.         }  
  122.         setRGB(dest, 00, width, height, outPixels );  
  123.         return dest;  
  124.     }  
  125.   
  126.     public static int clamp(int c) {  
  127.         if (c < 0)  
  128.             return 0;  
  129.         if (c > 255)  
  130.             return 255;  
  131.         return c;  
  132.     }  
  133. }  
2020-05-07 18:33:46 my_kun 阅读数 916
  • SIFT特征提取2

    了解Hough变换基本思想及直线检测步骤; 掌握Harris角点检测的基本思想及实现步骤; 了解尺度空间概念及SIFT特征提取的基本思想 了解ORB中快速特征检测及BRIEF特征建立方法 掌握前述算子的OpenCV实现

    2606人学习 CSDN就业班
    免费试看

目录

一、边缘简介

1.1 何为边缘

1.2 产生原因

二、边缘检测方法

2.1 一阶微分算子计算原理

2.2 噪声对一阶微分算子的影响及解决方案

2.3 常见的一阶微分算子

2.3.1 Roberts算子

2.3.2 Prewitt算子

2.3.3 Sobel算子

2.4 二阶微分算子计算原理

2.5 常见的二阶微分算子

2.5.1 拉普拉斯(Laplace)算子

2.5.2 LoG算子

2.5.3 DoG算子

2.6 Canny边缘检测

2.6.1 Canny边缘检测简介

2.6.2 Canny边缘检测原理及流程

三、基于python-opencv的实现

3.1 Sobel算子实现

3.2 Laplacian算子实现

3.3 Canny边缘检测实现

参考


一、边缘简介

1.1 何为边缘

图像的边缘是图像像素快速变化的地方,图像边缘不等同图像中物体的边界。边缘指的是图像中像素的值有突变的地方,而物体间的边界指的是现实场景中的存在于物体之间的边界。有可能有边缘的地方并非边界,也有可能边界的地方并无边缘,因为现实世界中的物体是三维的,而图像只具有二维信息,从三维到二维的投影成像不可避免的会丢失一部分信息;另外,成像过程中的光照和噪声也是不可避免的重要因素。

1.2 产生原因

物体的边界、物体表面方向的变化、不同的颜色、光照明暗的变化都可能造成图像边缘的产生。

二、边缘检测方法

2.1 一阶微分算子计算原理

如果我们将图像看作一个二维函数,则图像像素值的变化率就可以使用导数(梯度)表示,而边缘的梯度幅值会比较大。如下面的图像表示:

我们可以看到,对于经过图像边缘的一条线,如图中的红线,我们可以将其看作为一条关于像素值的函数f(x),表达式图像如上图中间曲线所示。我们可以看出,边缘所处位置即为函数f(x)一阶导数的极值点。我们可以将其扩展到图像(二维离散函数),边缘就是梯度幅值M的局部极值点。

在图像中,图像的梯度与x方向和y方向上的偏导数有关,图像梯度定义为:

图像在各方向上的导数如下图所示:

我们可以看到,图像梯度是具有方向和大小的,其方向指向了像素值变化率最大的方向,一般用角度θ来表达;而梯度大小表示了图像边缘的强弱程度,用梯度幅值M表达。梯度方向和梯度幅值的公式为:

在数字图像处理领域,通常将梯度幅值M(x,y)称为梯度。而在一阶微分算子检测边缘的方法中就是通过一阶微分算子计算得到图像在x方向和y方向的偏导数,再进一步的计算得到梯度幅值M,二值化M后得到图像边缘的。

假设在图像中用f(x,y)表示在点(x,y)处的像素值,则图像在x方向和y方向的一阶微分算子应该计算为:

由于图像是离散的二维函数,ε不能无限小,图像按照像素来离散,最小的ε就是1像素,因此上式就变成了如下的形式(ε=1):

我们可以从这里看到,图像的偏导数就是2个相邻像素之间差值。我们通过gx和gy便可以进一步计算得到梯度幅值M。在实际中,我们常用一个小区域的模板卷积来近似偏导计算。对gx和gy各采用一个模板,并将这两个模板组合起来构成一个梯度算子。根据模板的大小,和模板中系数值的不同,可以提出很多不同的检查算子。下面就列举了一个采用差分近似提出的一种梯度算子计算模板:

2.2 噪声对一阶微分算子的影响及解决方案

如果我们直接对图像进行一阶微分,很容易受到噪声的影响。以下图为例说明:

图中,当f(x)存在噪声时,直接进行一阶微分,得到的导数图像是凌乱的,有很大的波动,不能够直接找出边缘。此时我们应该先对图像进行平滑(降噪),之后在进行微分。例如,当我们使用高斯平滑之后,在进行微分就能够找到边缘所在了,如下图所示:

特别强调一个卷积运算性质:两个函数卷积后的导数等于其中一个函数的导数与另一个函数的卷积,即:

所以,我们可以将平滑和微分合成一个算子:

通过上面的例子,我们也看到在进行边缘检测是应该特别注意噪声对图像产生的影响,当有噪声时应该先进性平滑处理。也因此,在实际应用中,我们也经常将二维高斯的一阶微分进行数值近似,以用来计算图像的梯度,图像如下:

2.3 常见的一阶微分算子

Roberts算子、Prewitt算子和Sobel算子是三种常用微分边缘检测算子,这三个算子都以一阶导数为基础,先通过合适的微分算子计算出图像的梯度矩阵(记录图像的梯度幅值),再对梯度矩阵进行二值化(将梯度幅值大于阈值的点标记为边缘)从而得到图像的边缘,同时我们页可选择的将边缘细化(thinning)为一个像素宽度。

2.3.1 Roberts算子

Roberts边缘检测算子是根据任一对互相垂直方向上的差分可用来计算梯度的原理,采用对角线方向相邻像素之差进行梯度幅度检测,其检测水平、垂直方向边缘的性能要好于斜线方向边缘,并且检测定位精度比较高,但对噪声敏感。

Robert算子对应模板如下:

2.3.2 Prewitt算子

2*2的检测模板虽然简单,但是不方便找到中心点计算梯度,并且受噪声影响大。Prewitt算子模板的大小为3*3,关于中心点对称,携带了更多的图像信息,减少了噪声的影响。

Prewitt算子对应模板如下:

2.3.3 Sobel算子

Sobel边缘算子是一种类似Prewitt边缘检测算子的边缘模板算子,Sobel算子对于像素的位置的影响做了加权,可以较好的抑制(平滑)噪声,降低边缘模糊程度。

Sobel算子对应模板如下:

2.4 二阶微分算子计算原理

图像的边缘不仅可以通过一阶导数进行表述,还可以通过二阶导数进行寻找。边缘是一阶导数的极大值点,对应二阶导数的过零点,求出图像的二阶导数的过零点就能精确地找到图像的边缘点,如下面的图像显示:

在上面一节我们已经得到了图像在(x,y)点处x方向和y方向上的一阶偏导数:

对一阶偏导数求偏导,得到二阶偏导数:

2.5 常见的二阶微分算子

2.5.1 拉普拉斯(Laplace)算子

二维图像的拉普拉斯算子的定义为:

也就是我们在上文中推导出的二阶微分算子的结果,因为图像是离散的二维函数,所以我们也就得到了一个数值近似结果。拉普拉斯算子的模板形式如下:

拉普拉斯算子模板对90°旋转保持旋转不变性(各向同性),其他常用的拉普拉斯算子模板还有:

Laplacian算子一般不以其原始形式用于边缘检测,因为其作为一个二阶导数,Laplacian算子对噪声具有无法接受的敏感性;同时其幅值产生算边缘,这是复杂的分割不希望有的结果;并且Laplacian算子没有边缘方向信息,不能检测边缘的方向。可以明显的看出,Laplace算子虽然解决了一阶微分算子确定阈值的困难,但是却不能克服噪声的干扰。为此,继续介绍其他算子。

2.5.2 LoG算子

1980年,Marr和Hildreth提出将Laplace算子与高斯低通滤波相结合,提出了LoG(Laplace of Guassian)算子。其方法为:首先使用高斯算子对图像进行平滑,抑制噪声,然后对平滑后的图像使用拉普拉斯算子。所以LoG算子等效于:高斯平滑+拉普拉斯算子。

我们常用的二维高斯函数为:

根据前文提到的卷积运算性质,我们可以得到LoG算子:

根据σ的不同以及3σ原则可以建立不同的模板,σ是一个尺度参数,在图像处理中引入尺度以及建立多尺度空间是一个重要的突破,σ越大,图像越模糊滤除噪声效果越好,σ越小,效果相反。

常用LoG模板如下:

LoG算子因其形状,也被称为墨西哥草帽算子。

2.5.3 DoG算子

我们可以通过数学上的关系对LOG的计算进行简化,这边得到了DOG算子。

二维高斯函数对σ求导:

上文我们已经得到:

可以得到:

同时由导数定义知道:

所以:

可以看到,公式右边比LOG算子只是多了一个系数,而在实际应用中没有太大影响。根据上面公式结果,我们可以定义DoG为两个不同参数的高斯滤波结果之差:

当我们用DOG算子代替LoG算子与图像卷积的时候:

而在具体图像处理中,就是将两幅图像在不同参数下的高斯滤波结果相减,得到DoG图。

使用DoG时,近似的LOG算子σ值的选取为:

当使用这个值时,可以保证LoG和DoG的过零点相同,只是幅度大小不同。

2.6 Canny边缘检测

2.6.1 Canny边缘检测简介

Canny边缘检测是JOHN CANNY于1986年在论文《A Computational Approach to Edge Detection》中首次提出的,就此拉开了Canny边缘检测算法的序幕。

Canny边缘检测是从不同视觉对象中提取有用的结构信息并大大减少要处理的数据量的一种技术,目前已广泛应用于各种计算机视觉系统。Canny发现,在不同视觉系统上对边缘检测的要求较为类似,因此,可以实现一种具有广泛应用意义的边缘检测技术。边缘检测的一般标准包括:

  • 以低的错误率检测边缘,也即意味着需要尽可能准确的捕获图像中尽可能多的边缘。
  • 检测到的边缘应要与图像中的实际边缘尽可能的接近。
  • 图像中给定的边缘应只被标记一次,并且在可能存在的图像噪声不应被检测为边缘。

为了满足这些要求,Canny使用了变分法。Canny检测器中的最优函数使用四个指数项的和来描述,它可以由高斯函数的一阶导数来近似。

在目前常用的边缘检测方法中,Canny边缘检测算法是具有严格定义的,可以提供良好可靠检测的方法之一。由于它具有满足边缘检测的三个标准和实现过程简单的优势,成为边缘检测最流行的算法之一。

Canny边缘检测步骤

应用及目的

1. 高斯滤波

去噪声降低错误率,有可能增大边缘宽度

2. 计算梯度幅值和方向

估计每一点处的边缘强度与方向,实际应用中,将梯度幅值大于阈值的点标记为边缘

3. 梯度非极大值抑制(NMS)

对Sobel、Prewitt等算子的结果进一步细化

4. 双阈值(Double-Threshold)提取边缘

确定强边缘和弱边缘

2.6.2 Canny边缘检测原理及流程

①高斯滤波器平滑图像

参照 图像噪声及图像平滑(基于python-opencv实现) 一文

②计算图像梯度幅值和方向

可以采用Sobel算子、Prewitt算子、Roberts算子等进行梯度幅值的计算。计算原理可以参见本文第2.1节部分。我们可以知道图像梯度幅值和方向为:

但有时候我们也可以使用如下的公式进行梯度幅值的简化:

其梯度值越大,表示像素值的变化率越大,变化越明显,在实际的应用中,将梯度幅值大于阈值的点标记为边缘。如下图表示了某像素中心点的梯度向量、方位角以及边缘方向(任一点的边缘与梯度向量正交) :

③梯度非极大值抑制

为了实现图像中的边缘只能被标记一次,并且可能存在的图像噪声不应该被标记为边缘,我们沿着梯度方向对梯度幅值进行非极大值抑制。

如上图,图中波动的曲线为在某方向求得的图像的梯度幅值,小黑点为梯度幅值的局部极值点,粗黑线为某一阈值。我们很容易明白边缘是梯度幅值的局部极值点,并且在实际应用中我们将超过某一阈值的梯度幅值的局部极值点才定义为边缘,因此上图中的边缘点应该选为箭头指向的3个点。但是在局部极值点附近经常存在相近数值的点,如上图最顶端小黑点周围未被指出的曲线上的值,是不能将这些点作为边缘的,要抑制这些点。这也就是为什么要沿梯度方向进行极大值抑制的目的。

我们对图像的的每一个点,在梯度方向和梯度反方向各找n个像素点,比较当前点的和这n个点的梯度幅值大小,若当前点的梯度幅值不是这些点中的最大值,则当前点置0,否则保持当前点。我们以3*3区域为例进一步说明:

3*3区域内,边缘可以划分为垂直、水平、45°、135°4个方向,同样,梯度反向也为四个方向(与边缘方向正交)。因此为了进行非极大值,将所有可能的方向量化为4个方向,如下图:

量化的结果情况为:

非极大值抑制即为沿着上述4种类型的梯度方向,比较3*3邻域内对应邻域梯度幅值的大小:

在每一点上,领域中心 x 与沿着其对应的梯度方向的两个像素相比,若中心点梯度幅值为最大值,则保留,否则中心置0,这样可以抑制非极大值,保留局部梯度最大的点,以得到细化的边缘。

④双阈值提取边缘

我们使用阈值来滤除有噪声引起的梯度值的变化,减少噪声影响,步骤如下:

  • 如果像素的梯度值大于高阈值TH,则将其标记为强边缘点
  • 如果像素的梯度值小于高阈值TH且大于低阈值TL,则将其标记为弱边缘点
  • 如果像素的梯度值小于低阈值TL,则将其抑制

我们将强边缘点的连接记为E1,弱边缘点的连接记为E2。

我们使用边缘连接策略找到图像的边缘,一般认为:

  • 强边缘点是真的边缘;弱边缘点可能是真的边缘,也可能是噪声
  • 通常认为强边缘点连通的弱边缘点是真实边缘
  • 噪声导致的弱边缘点是孤立的
  • 如果弱边缘点的邻域内有强边缘点,将改弱边缘点视为强边缘点

在应用中具体操作如下:

  • 选取系数TH和TL,比率为2:1或3:1(一般取TH=0.3或0.2,TL=0.1)
  • 将小于低阈值的点抛弃,赋0;将大于高阈值的点立即标记(这些点为确定边缘点),赋1或255
  • 将小于高阈值,大于低阈值的点使用8连通区域确定(即:只有与TH像素连接时才会被接受,成为边缘点,赋 1或255)

三、基于python-opencv的实现

3.1 Sobel算子实现

使用cv2.Sobel()实现Sobel算子:

cv2.Sobel(src, # 参数是需要处理的图像;
          ddepth, # 图像的深度,-1表示采用的是与原图像相同的深度。目标图像的深度必须大于等于原图像的深度
          dx, # dx和dy表示的是求导的阶数,0表示这个方向上没有求导,一般为0、1、2。
          dy[, 
          dst[, #输出图片
          ksize[,#Sobel算子的大小,必须为1、3、5、7。
          scale[, #缩放导数的比例常数,默认情况下没有伸缩系数;
          delta[, #可选的增量,将会加到最终的dst中,同样,默认情况下没有额外的值加到dst中;
          borderType #判断图像边界的模式。这个参数默认值为cv2.BORDER_DEFAULT。
          ]]]]])  

Sobel图像测试:

import numpy as np
import maplotlib.pyplot as plt
import cv2

img_gray = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)

# sobel算子计算
sobel_x = cv2.Sobel(img_gray, cv2.CV_64F, 1, 0, ksize=5)
sobel_y = cv2.Sobel(img_gray, cv2.CV_64F, 0, 1, ksize=5)

# 梯度幅值
sobel_M = np.sqrt(sobel_x**2 + sobel_y**2)

# image show
plt.figure('image')
plt.subplot(221), plt.imshow(img_gray, cmap='gray'), plt.title('original')
plt.subplot(222), plt.imshow(sobel_x, cmap='gray'), plt.title('sobel x')
plt.subplot(223), plt.imshow(sobel_y, cmap='gray'), plt.title('sobel y')
plt.subplot(224), plt.imshow(sobel_M, cmap='gray'), plt.title('sobel M')
plt.show()

sobel算子效果:

在上面的例子中,第二个参数使用了cv2.CV_64F。当然我们可以通过参数-1来设定输出图像的深度(数据类型)与原图像保持一致,但是我们没有这么做。这是为什么?想象一下,一个从黑到白的边界的导数是正数,而一个从白到黑的边界的导数却是负数。如果原图像的深度是np.int8时,所有的负值都会被截断变成0。换句话就是把边界丢失掉。

对于处理成64位浮点型的图像,我们可以使用convertScaleAbs()函数将其转回原来的uint8形式。convertScaleAbs()的原型为:

dst = cv2.convertScaleAbs(src[, dst[, alpha[, beta]]])
#其中可选参数alpha是伸缩系数,beta是加到结果上的一个值
#结果返回uint8类型的图片,绝对值超过255的直接截断

代码如下:

# 转成uint8形式的图像
abs_x = cv2.convertScaleAbs(sobel_x)
abs_y = cv2.convertScaleAbs(sobel_y)

# 结合abs_x和abs_y
abs_xy = cv2.addWeighted(abs_x, 0.5, abs_y, 0.5, 0)

# image show
plt.figure('compare result')
plt.subplot(231), plt.imshow(sobel_M, cmap='gray'), plt.title('sobel M')
plt.subplot(234), plt.imshow(abs_xy, cmap='gray'), plt.title('abs xy')
plt.subplot(232), plt.imshow(sobel_x, cmap='gray'), plt.title('sobel x')
plt.subplot(235), plt.imshow(abs_x, cmap='gray'), plt.title('abs x')
plt.subplot(233), plt.imshow(sobel_y, cmap='gray'), plt.title('sobel y')
plt.subplot(236), plt.imshow(abs_y, cmap='gray'), plt.title('abs y')
plt.show()

其函数效果图:

3.2 Laplacian算子实现

使用cv2.Laplacian()函数实现拉普拉斯算子。

dst = cv2.Laplacian(src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]])

第一个参数是需要处理的图像;
第二个参数是图像的深度,-1表示采用的是与原图像相同的深度。目标图像的深度必须大于等于原图像的深度;
其后是可选的参数:
dst不用解释了;
ksize是算子的大小,必须为1、3、5、7。默认为1。
scale是缩放导数的比例常数,默认情况下没有伸缩系数;
delta是一个可选的增量,将会加到最终的dst中,同样,默认情况下没有额外的值加到dst中;
borderType是判断图像边界的模式。这个参数默认值为cv2.BORDER_DEFAULT。

 代码实现:

import numpy as np
import maplotlib.pyplot as plt
import cv2

img_gray = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)

laplacian = cv2.Laplacian(img_gray, cv2.CV_64F, ksize=5)

plt.figure('laplacian')
plt.subplot(121), plt.imshow(img_gray, cmap='gray'), plt.title('original')
plt.subplot(122), plt.imshow(laplacian, cmap='gray'), plt.title('laplacian')
plt.show()

 Laplacian算子效果:

3.3 Canny边缘检测实现

opencv中使用cv2.Canny()函数实现Canny边缘检测。

 

edge = cv2.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient ]]])

image:源图像
threshold1:阈值1 minVal
threshold2:阈值2 maxVal
apertureSize:可选参数,用于查找图像渐变的Sobel内核的大小,默认值为3
L2gradient:用于查找梯度幅度的方程式,默认情况下,它为False,使用简化的x和y方向梯度绝对值之和的公式进行计算,如果为True,则使用上文提到的更精确的公式。

代码实现:

import numpy as np
import maplotlib.pyplot as plt
import cv2
# read image
img_gray = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)
# Canny Edge
edge = cv2.Canny(img_gray, 80, 120, L2gradient=True)
# image show
plt.figure('edge')
plt.subplot(121), plt.imshow(img_gray, cmap='gray'), plt.title('original')
plt.subplot(122), plt.imshow(edge, cmap='gray'), plt.title('Canny edge')
plt.show()

 

Canny边缘检测效果:

 

 

 

 

 

 

 

 

参考

图像边缘和轮廓特征的提取方法

图像中的微分运算总结

一阶微分边缘检测算子

图像边缘检测——二阶微分算子(上)Laplace算子、LOG算子、DOG算子(Matlab实现)

DOG算子

Canny算子边缘检测原理及实现

 

2010-05-14 06:42:00 pyramide 阅读数 1333
  • SIFT特征提取2

    了解Hough变换基本思想及直线检测步骤; 掌握Harris角点检测的基本思想及实现步骤; 了解尺度空间概念及SIFT特征提取的基本思想 了解ORB中快速特征检测及BRIEF特征建立方法 掌握前述算子的OpenCV实现

    2606人学习 CSDN就业班
    免费试看

转于 彩泓的博客

 

   微分算子在图像处理 中扮演重要的角色,其算法实现简单,而且边缘检测的效果又较好,因此这些基本的微分算子是学习图像处理过程中的必备方法,下面着重讨论几种常见的微分算 子。

1.Sobel

 其主要用于边缘检测,在技术上它是 以离散型的差分算子,用来运算图像亮度函数的梯度的近似值,缺点是Sobel算子并没有将图像的主题与背景严格地区分开来,换言之就是Sobel算子并没 有基于图像灰度进行处理,由于Sobel算子并没有严格地模拟人的视觉生理特征,所以提取的图像轮廓有时并不能令人满意,算法具体实现很简单,就是3*3 的两个不同方向上的模板运算,这里不再写出。

2.Robert算子

根据任一相互垂直方向上的差分都用来估计梯 度,Robert算子采用对角方向相邻像素只差

3.Prewitt算子

   该算子与Sobel算子类似,只是权值有所变化,但两者实现起来功能还是有差距的,据经验得知Sobel要比Prewitt更能准确检测图像边缘。

4.Laplacian算子

   拉普拉斯算子是一种二阶微分算子,若只考虑边缘点的位置而不考虑周围的灰度差时可用该算子进行检测。对于阶跃状边缘,其二阶导数在边缘点出现零交叉,并且 边缘点两旁的像素的二阶导数异号。

5.Canny算子

该算子功能比前面几种都要好,但是它实现起来较 为麻烦,Canny算子是一个具有滤波,增强,检测的多阶段的优化算子,在进行处理前,Canny算子先利用高斯平滑滤波器来平滑图像以除去噪 声,Canny分割算法采用一阶偏导的有限差分来计算梯度幅值和方向,在处理过程中,Canny算子还将经过一个非极大值抑制的过程,最后Canny算子 还采用两个阈值来连接边缘。

下面算法是基于的算法不可能直接运行,只是我把 Canny的具体实现步骤写了出来,若需用还要自己写。

图像处理-拉普拉斯

阅读数 1173

边缘检测算子

阅读数 395