目录
1、数学基础
2、图像微分知识
3、滤波器
4、微分算子
4.1、一阶微分算子
4.1.1、Sobel算子
4.1.2、scharr算子
4.1.3、 Roberts交叉梯度算子
4.1.4、Prewitt算子
4.1.5、 Isotropic Sobel算子
函数一阶导数对应的微分称为一阶微分;
一阶微分的微分称为二阶微分;
二阶微分及以上的微分称为高阶微分;
首先,图像是离散的数据,若求其导数就要用差分的方法,常用的差分方法是前向差分(forward differencing)与中心差分(central differencing)。一阶导本质上求的是斜率,二阶导求的是拐点。
一阶导数:
图像梯度:
平滑滤波器(低通滤波器),是用来平滑图像和抑制噪声的;而锐化空间滤波器恰恰相反,主要用来增强图像的突变信息,图像的细节和边缘信息。平滑滤波器主要是使用邻域的均值(或者中值)来代替模板中心的像素,消弱和邻域间的差别,以达到平滑图像和抑制噪声的目的;相反,锐化滤波器则使用邻域的微分作为算子,增大邻域间像素的差值,使图像的突变部分变的更加明显。
不同图像灰度不同,边界处一般会有明显的边缘,利用此特征可以分割图像。需要说明的是:边缘和物体间的边界并不等同,边缘指的是图像中像素的值有突变的地方,而物体间的边界指的是现实场景中的存在于物体之间的边界。有可能有边缘的地方并非边界,也有可能边界的地方并无边缘,因为现实世界中的物体是三维的,而图像只具有二维信息,从三维到二维的投影成像不可避免的会丢失一部分信息;另外,成像过程中的光照和噪声也是不可避免的重要因素。
对于一阶微分的任何定义都必须保证以下几点:
其主要用于边缘检测,在技术上它是以离散型的差分算子,用来运算图像亮度函数的梯度的近似值, Sobel算子是典型的基于一阶导数的边缘检测算子,由于该算子中引入了类似局部平均的运算,因此对噪声具有平滑作用,能很好的消除噪声的影响。Sobel算子对于象素的位置的影响做了加权,与Prewitt算子、Roberts算子相比因此效果更好。
Sobel算子是计算不同方向的梯度,比如说计算x方向的梯度,我们使用下方的卷积核(用卷积核与原始图像相乘操作):(中间的这一行离P5特别近所以给他加了一个系数2)
水平方向的梯度:就是右边一列的值减去左边一列的值,再乘以适当的系数,就可以计算出p5这一点他到底有没有差值,差值越大,那就意味着p5这一点是边界。
上述计算的是P5这一个点X方向或者水平方向这一个点的梯度(简单说就是从右边向左边有没有边界)。(挨个点都用卷积核去计算)
垂直方向的梯度:下边减去上边的值。(中间的这一列离P5特别近所以给他加了一个系数2)
如果计算的梯度值很大,那么它很可能就是一个边界。
整个图像两个方向的梯度就是:
故,P5点的Sobel的边界值或者梯度值
每一个点都是这样去算的,然后就把整个图像的梯度值计算出来了。(记得边界补充的方法)
Sobel算子的函数:
dst:是梯度图像,就是计算结果。
ddepth: 是处理结果图像深度。通常情况下可以将该参数的值设为1,让处理结果与原始图像保持一致。
dx:表示计算x轴方向的梯度(或者说X轴上的边界)。(计算X方向的梯度,我们就让dx=1,dy=0)
dy:表示我计算y轴上的边界。(计算Y轴方向的梯度,我们就让dx=0,dy=1)
ksize:这个参数一般不用(默认为3,表示3行3列);如果使用的话设置为奇数。
左图为:水平方向(梯度); 右图为:垂直方向(梯度) ;
(1)第一种处理模式:直接处理左边界处理为0 (计算出来为负数直接处理为0),那就是没有这个边界了,0梯度没有梯度。
(2)第二种处理模式:取绝对值(计算为负数,我们取绝对值)这样边界就出来了。一般是采用这种处理方式,计算结果为负值的话,取他的绝对值。
PS:OpenCV官网:计算水平方向的梯度值,给出来的是垂直方向的,(这是因为我们考虑的是某一点,很多个水平方向的梯度值组成一条线,刚好是一个垂直线。)
所以为了既能处理正数又能处理负数,在ddepth这个参数的时候,我们没有使用默认的-1,而是使用的是cv2.CV_64F,就表明我们要使用他那个负数的值:
所以进一步的如果我们出现了负数,在256色位图中要怎么办呢?必须通过下边的函数,表示把我们的负数的值取绝对值:
虽然上面的公式中用到了系数和修正值来计算即下图左边的方法;但是一般在计算时我们没有这么的复杂而是使用下图右边的方式,直接输入的是图像。
------------------上面是对于ddepth参数的解释(不能直接设置为-1,因为边界会丢失)-----------------
在计算梯度的时候:
计算方式分为两种:第一种一起计算;第二种分开计算再求和。下图是计算Sobel的两种方式:
但是第一种方式不太严谨,更多的时候使用的是第二种方式。 第二种方式为了确保在相加时比如我们我们两个方向上计算结果都很大,超过了255,他就会溢出,所以把每一个都乘以一个系数,这个系数一般是0.5,最后得到一个比较不错的图像。
针对于上述的第二种必须要我们自己去加计算,CV里边提供了一个函数如下:
上述函数的关系就是:
原图像1乘上他的系数+原图像2乘上他的系数,最后再加上修正值,最后得到一个目标图像。
下面是Sobel算子CV代码的使用:
下面参数设置为-1只取到了右侧边界,因为左侧边界为负数,将其强制置为0。
下面这个虽然改变了参数不是-1了,你把它的范围扩大了,但是在运算的时候还是它的负数仍然设置为0了,所以还是只有右侧边界:
下边如果让左边界出现,必须调用函数,添加一行代码就会出现左边界:
接下来再求Y方向的梯度:
PS:减法的顺序和我们检测出来的边缘信息是正交的。
把X轴和Y轴的梯度一块计算出来:
下面再进行调整把dx和dy都设置为1:
直接计算两者的方式并没有把边界找出来或者即使找出来效果也不好,所以为了更好地找出边界,我们一般是使用分开计算,然后求和的方式来计算。
Scharr作为一阶微分算子被提出的原因,因为我们在使用3x3的Sobel算子的时候,可能会出现不太精准的情况,就是计算出来的梯度可能不太精确,导致边缘不是很精准,Scharr算子效果更好,他的卷积核如下:
计算方法和Sobel算子一样,在水平方向仍然是左侧的像素减去右侧的像素,在垂直方向是下边的像素值减去上边的像素值,只是系数不一样。离中心点稍微远一点的系数是3,近一点的系数值是10。 Scharr和Sobel从运算量上来说两者的运算量是一样的,只是 Scharr的准确率更高,他可以说是我们对Sobel算子的一种改进,所以一般计算梯度的时候经常使用的是 Scharr算子。
Scharr算子在OpenCV中的使用:
在参数设置上和Sobel一样,一般处理深度不使用-1。
Scharr算子计算水平方向的梯度:
计算垂直方向的梯度:
计算两个方向上的提顿:
Sobel算子与Scharr 比较:
(1)大小一样,意味着计算起来计算量是一样的。
(2)计算的准确度不同,Scharr算子更高(更够计算出相邻像素更小的细小差异)。(精确度体现在系数差别上)
上述几个暂时未使用到。