OpenCV学习日记(3)

绪言

本篇主要介绍边缘、轮廓检测,以加深大家对滤波器的初步理解。

边缘检测

边缘检测是图像处理中的老问题了,很多时候我们并不关心什么颜色特征,即使是灰度图,我们也不关心某一像素点的灰度是多少。比如在车牌检测的时候,我们只关心我们经过处理后的车牌号边缘是多少,从而可以方便地识别出车牌号(现在有了深度学习之后,车牌的检测正确率比以前更高了)。OpenCV中提供了Laplacian(),sobel()等这些边缘检测滤波函数,但是我们在边缘检测之前,首先要去除噪声。

模糊处理

要准确地勾勒出一幅图像的轮廓,首先要降低某些噪声点的亮度,使其不会被作为轮廓勾勒进去。常用的模糊滤波函数有blur()、medianBlur()、GaussianBlur()。
下列来介绍一下这三个模糊滤波函数:

blur()

也称线性滤波器。
原型:blur(src,ksize,dst=None,anchor=None,borderType=None)
作用:对图像进行算术平均模糊处理。
参数:src,原图像,此处填入一个图像矩阵;ksize,滤波器的大小(也即核的大小);一般没有dst,因为OpenCV的python库里面都是直接返回处理后的图像的。如果有错误是直接抛出异常的。后两个参数一般不用,让CV库自己判断。

medianBlur()

也称中值滤波器。
原型:medianBlur(src,ksize,dst=None)
作用:对图像进行中值模糊处理。

GaussianBlur()

也称高斯滤波器。
原型:GaussianBlur(src,ksize,sigmaX,dst=None,sigmaY=None,borderType=None)
作用:对图像进行高斯模糊滤波处理。
参数:sigmaX:x方向的标准方差,可以设置为0让系统自动计算。

边缘检测函数

Laplacian()

也称拉普拉斯卷积函数。
原型:Laplacian(src,ddepth,dst=None,ksize=None,scale=None,delta=None,borderType=None)
作用:检测图像边缘。
参数:ddepth,图像位深度,对于灰度图来说,其值为:cv2.CV_8U。ksize,希望使用的卷积核的大小。scale,是缩放导数的比例常数。
解释:我们可以知道,一幅图像的拉普拉斯算子处理是这样的:
先把原图像的像素的二阶x和y导数加起来,组成拉普拉斯算子,而该算子的结果是通过Sobel算子实现的。为什么要这样做呢?因为在图像中的边缘区域,像素值会发生“跳跃”,对像素求二阶导,会得到边缘处的导数为0,这就是拉普拉斯算子检测边缘的原理。
l a p l a c e ( I ) = 2 I x 2 + 2 I y 2
OpenCV-跟我一起学数字图像处理之拉普拉斯算子
这一篇对于拉普拉斯算子的解释和证明以及拉普拉斯内核的产生给出了很好的解释。

Laplace算子详解

在数学里面,我们知道,拉普拉斯算子是一种用来计算梯度的散度的一种算子。
对于一个实函数 f 来说(无论其是否离散),我们有:
Δ f = i = 1 n 2 f x i 2 (对于笛卡尔坐标系 x i 来说)
在二维空间中, I 的拉普拉斯算子即为上述表达式。

Sobel()

原型:
Sobel(src,ddepth,dx,dy,dst=None,ksize=None,scale=None,delta=None,borderType=None)
作用:对图像进行Sobel算子计算。检测出其边缘。
参数:dx,x方向上的导数阶数;dy,y方向上的导数阶数。

Sobel算子详解

Sobel算子是边缘检测中最重要的算子。用来计算图像亮度函数的一阶梯度之近似值。在图像的任何一点使用此算子,将会产生该点对应的梯度矢量或是其法矢量。
听着很拗口,反正不是我下的定义。
我就直接说一下Sobel算子的原理吧。
1.分别用两个矩阵对图像进行卷积,得到x方向和y方向上的梯度值
x方向的卷积内核y方向的卷积内核
2.卷积完之后,图像的每一个像素点都有x方向上的梯度值和y方向上的梯度值。根据梯度的定义,我们又知道:
G = G x 2 + G y 2
Θ = a r c t a n ( G y G x )
这一般是高等数学的知识。
CV库给你设置了一个阈值,那么这个梯度值一旦大于这个阈值,就可以判断为边缘。
在以上例子中,如果以上的角度 Θ 等于零,即代表图像该处拥有纵向边缘,左方较右方暗。
通过Sobel算子,我们就可以成功地检测出一幅图像的边缘。

代码示例

import cv2
img=cv2.imread("Mypic.png")
blurredSrc=cv2.medianBlur(img,3)
graySrc=cv2.cvtColor(blurredSrc,cv2.COLOR_BGR2GRAY)
LaplacianSrc=cv2.Laplacian(graySrc,cv2.CV_8U,ksize=5)
Sobel3Src=cv2.Sobel(graySrc,cv2.CV_8U,1,1,ksize=3)
Sobel5Src=cv2.Sobel(graySrc,cv2.CV_8U,1,1,ksize=5)
cv2.imshow("original",img)
cv2.imshow("blurred",blurredSrc)
cv2.imshow("grayed",graySrc)
cv2.imshow("Laplacian",LaplacianSrc)
cv2.imshow("Sobel3",Sobel3Src)
cv2.imshow("Sobel5",Sobel5Src)
cv2.waitKey()
cv2.destroyAllWindows()

代码结果如下:
原图
模糊化
灰度图
3x3下的Sobel算子
5x5下的Sobel算子
5x5下的拉普拉斯算子
可以看到,卷积所用核数越小,丢失的边缘信息也就越多。但核数过大会加重卷积计算量,此时可以通过GPU加速(没错,说的就是CUDA计算)来获得更好的边缘检测效果。

Canny边缘检测

OpenCV还提供了一个边缘检测算法,叫作Canny算法。Canny边缘检测算法分为5个步骤:
1.使用高斯滤波器去噪
2.计算梯度
3.在边缘上使用非最大抑制
4.使用双阈值去除假阳性
5.分析边缘及其连接
Canny Edge Detector
这个算法非常复杂,我们不展开来讲,有兴趣的可以点击上方的超链接阅读其原理。

import cv2
import numpy as np
img=cv2.imread("test.jpg",0)
cv2.imwrite("canny.jpg",cv2.Canny(img,200,300))
cv2.imshow("canny",cv2.imread("canny.jpg"))
cv2.waitKey()
cv2.destroyAllWindows()

实现效果:
边缘检测
其实还是有部分的边缘缺失,但对于自动处理算法来讲,这个效果已经非常到位了。
原图:
我的大本营

猜你喜欢

转载自blog.csdn.net/weixin_40427089/article/details/81434657