准备
下面的所有示例使用图片均为如下:
所有绘图函数都会修改源图像
边缘检测
OpenCV提供了许多边缘检测滤波函数,包括Laplacian()
、Sobel()
以及Scharr()
。这些滤波函数都会将非边缘区域转化为黑色,边缘区域转化为白色或其他饱和的颜色(故在进行滤波画线过后需要进行归一化处理,将边缘部分编程黑色,然后使用卷积核进行卷积寻找边缘)。但是,这些函数都很容易将噪声错误的识别为边缘。缓解这个问题的方法是在找到边缘前对图像进行模糊处理(降噪)。OpenCV也提供了许多用于模糊滤波函数,包括blur()
(简单的算术平均)、medianBlur()
(中位值模糊)以及GaussianBlur()
(高斯模糊)。边缘检测和模糊处理都有很多参数,但是他们都有一个Ksize参数,为奇数,表示滤波核的宽高。
降噪
不管什么信号,或多或少都会引入噪声,噪声为小部分,但是全部都用均值降噪 势必会造成图像模糊,只要是噪声处理都会或多或少的造成模糊问题,中值滤波是使用选取中位置的方法进行滤波,如果噪声是椒盐噪声(只有黑白二值),那么中值滤波就可以达到很好的效果,因为噪声一般都处于两极,使用中值滤波可以很好的达到降噪的目的,但是如果是高斯噪声分布(正态分布),这个时候使用均值滤波的效果会更好
边缘检测过程:
- 先进行模糊处理进行降噪
- 将图像转化为灰度图
- 使用边缘检测滤波函数将边缘转化为白色或其他饱和颜色,非边缘转化为黑色
- 在进行归一化处理,然后乘以源图像使原图像边缘部分变黑
- 使用边缘检测卷积核进行卷积,产生白色边缘
卷积核
OpenCV定义的许多滤波函数都会使用核。核可以看作一组权重,他决定如何通过邻近的点来计算新的像素点。核也可以称为卷积矩阵。卷积矩阵有奇数行、奇数列,感兴趣的像素对应于最中间个元素,其他元素对应于周围其他邻近的像素点,有如下核:
kernel=numpy.array([[-1,-1,-1],
[-1,9,-1],
[-1,-1,-1]
])
其中感兴趣的像素点的权重为9,周围为0,对感兴趣的像素点*9减去8个相邻的像素点,如果卷积之前,感兴趣的像素点与周围存在差异,经过卷积核处理过后差距会越来越来,就可以达到锐化的效果了
不同的核可以达到不同的有趣的效果,如权重和为0的卷积核可以达到检测边缘的目的。
卷积过程:
可以预先定义一些常用的卷积核备用
卷积方法
OpenCV使用filter2D()
方法对图像与核做卷积矩阵
cv2.filter2D(src,-1,kernel,dst)
第一个参数为源图像,第二个参数指定目标图像每个通道的位深度(如,位深度cv2.CV_8U 表示每个通道8位),如果为-1表示与源图像相同,第三个参数为使用的卷积核,最后一个参数为指向的目标图像。
对其做如下操作(需先使用边缘检测处理在做如下操作):
import numpy as np
import cv2
image=cv2.imread('hello.jpg')
kernel=np.array([[-1,-1,-1],
[-1,8,-1],
[-1,-1,-1]
])
cv2.filter2D(image,-1,kernel,image)
cv2.imshow('findEdge',image)
cv2.waitKey()
cv2.destroyAllWindows()
结果:
Canny边缘检测
OpenCV还提供了一个非常方便的Canny函数(以算法发明人命名)进行边缘检测
#使用双阈值去除假阳性
cv2.Canny( image, edges, threshold1,threshold2, aperture_size=3 );
轮廓检测
主要使用OpenCV中的阈值处理函数(cv2.threshold)和查找轮廓函数(cv2.findContours)
在对图像查找轮廓之前必须对图像进行二值化处理(转化为只有黑白二值),使用threshold 函数处理
img=cv2.imread('hello.jpg',cv2.IMREAD_UNCHANGED)
# 转化为贵都图像
grayImage=cv2.cvtColor(img.copy(),cv2.COLOR_BGR2GRAY)
# 黑白二值 大于127 的变为255,最后一个参数为转化为黑白二值
# 返回阈值,二值处理后的图像
ret,thread=cv2.threshold(grayImage,127,255,cv2.THRESH_BINARY)
# 寻找轮廓,第二个参数代表检测外轮廓,第三个参数指定使用的算法
# 返回值 轮廓,层级
# 层级代表各轮廓之间的关系
contours,hier=cv2.findContours(thread,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
# 寻找边界矩形
x,y,w,h=cv2.boundingRect(c)
cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0))
#最小矩形轮廓
rect=cv2.minAreaRect(c)
box=cv2.boxPoints(rect)
box=np.int0(box)
cv2.drawContours(img,[box],0,(0,0,255),1)
#最小圆形轮廓
(x,y),radius=cv2.minEnclosingCircle(c)
center=(int(x),int(y))
radius=int(radius)
cv2.circle(img,center,radius,(255,0,0),1)
# 画轮廓 在img上 第三个参数为-1代表画所有轮廓,其余值代表相应的轮廓
# 第三个值为轮廓颜色 本例子中使用了绿色
# 第四个参数代表画轮廓的线宽
cv2.drawContours(img,contours,-1,(255,255,0))
cv2.imshow('findEdge',img)
cv2.waitKey()
cv2.destroyAllWindows()
结果:
说明:
蓝色:最小闭圆轮廓
绿色:边界矩形
红色:最小矩形轮廓
浅蓝色:轮廓