滤波是图像预处理降噪环节不可缺少的一部分,其可在不影响原图像主要特征的情况下,去除大部分噪音,决定了后续的图像质量,极大降低了后续图像处理的复杂程度。
OpenCV python中常用的3种滤波操作为均值滤波、中值滤波、高斯滤波,其各自的函数如下:
cv2.blur(img, (x, x)) # 均值滤波
cv2.medianBlur(img, x) # 中值滤波
cv2.GaussianBlur(img, (x, x), 0) # 高斯滤波
在该篇文章中有详细的介绍和案例,包括个人对于滤波方法选择的理解,有需要可以小小的看一下:OpenCV python(四)图像预处理:二值化 && 滤波操作
效果如下:
如上图所示,当我们使用滤波操作对图像进行降噪后,我们仍然无法得到一张单纯的太阳的二值化图像,即图像中仍然存在有一些噪声点。接下来就是本篇文章的正文,通过腐蚀膨胀,我们将得到一张只有太阳的二值化图像。
腐蚀操作和滤波一样,首先要选择一个奇数卷积核,核里非0的点则为感兴趣的点,和滤波操作一样,将此核遍历整张图像。当感兴趣的点为0时,则把中心点置为0,否则保持原状。
cv2.erode函数为opencv-python提供的腐蚀函数,具体如下所示:
img_erode = cv2.erode(img_bin, (x, x), iterations=number) # 腐蚀
img_bin为二值化图像,(x, x)为卷积核,因此x为奇数,number为次数,即连续腐蚀number次。(此处x为偶数,opencv也不会报错)
同腐蚀操作一样,膨胀操作也需要选择一个奇数卷积核,核里非0的点则为感兴趣的点,将核遍历整张图像。然后和腐蚀操作相反,当感兴趣点为非0值时,则把中心点置为255,否则保持原状。
cv2.dilate函数为opencv-python提供的膨胀函数,具体如下所示:
img_dilate = cv2.dilate(img_bin, (x, x), iterations=number) # 膨胀
img_bin为二值化图像,(x, x)为卷积核,因此x为奇数,number为次数,即连续膨胀number次。(此处x为偶数,opencv也不会报错)
以 一、滤波操作程序中的高斯滤波得到的二值化图像为基础,对其进行腐蚀和膨胀操作。
具体程序如下所示:
import cv2 # 导入opencv库
if __name__ == '__main__':
while True:
img_g = cv2.imread('img/6.jpg', 0) # 获取路径img/0.jpg的图像,图像类型为RGB图像
img_g = cv2.resize(img_g, (0, 0), fx=0.5, fy=0.5) # 改变图像shape
img_GaussianBlur = cv2.GaussianBlur(img_g, (5, 5), 0) # 高斯滤波
t1, img_g_bin = cv2.threshold(img_g, 170, 255, cv2.THRESH_BINARY) # 二值化
t4, img_GaussianBlur_bin = cv2.threshold(img_GaussianBlur, 170, 255, cv2.THRESH_BINARY) # 二值化
img_erode = cv2.erode(img_GaussianBlur_bin, (3, 3), iterations=5) # 腐蚀
cv2.imshow("img_g", img_g) # 显示RGB图像
cv2.imshow("img_g_bin", img_g_bin) # 显示二值化图像
cv2.imshow("img_GaussianBlur", img_GaussianBlur) # 显示高斯滤波后的图像
cv2.imshow("img_GaussianBlur_bin", img_GaussianBlur_bin) # 显示高斯滤波后的二值化图像
cv2.imshow("img_erode", img_erode) # 显示腐蚀后的图像
cv2.waitKey(1) # 等待时间
效果如下所示:
如上图所示,我们可以看到除太阳以外的噪声点确实被去掉了,但是太阳也被腐蚀掉了5个大圈。要想解决这个问题,要先看下膨胀操作该如何实现。
具体程序如下所示:
import cv2 # 导入opencv库
if __name__ == '__main__':
while True:
img_g = cv2.imread('img/6.jpg', 0) # 获取路径img/0.jpg的图像,图像类型为RGB图像
img_g = cv2.resize(img_g, (0, 0), fx=0.5, fy=0.5) # 改变图像shape
img_GaussianBlur = cv2.GaussianBlur(img_g, (5, 5), 0) # 高斯滤波
t1, img_g_bin = cv2.threshold(img_g, 170, 255, cv2.THRESH_BINARY) # 二值化
t4, img_GaussianBlur_bin = cv2.threshold(img_GaussianBlur, 170, 255, cv2.THRESH_BINARY) # 二值化
img_dilate = cv2.dilate(img_GaussianBlur_bin, (3, 3), iterations=5) # 膨胀
cv2.imshow("img_g", img_g) # 显示RGB图像
cv2.imshow("img_g_bin", img_g_bin) # 显示二值化图像
cv2.imshow("img_GaussianBlur", img_GaussianBlur) # 显示高斯滤波后的图像
cv2.imshow("img_GaussianBlur_bin", img_GaussianBlur_bin) # 显示高斯滤波后的二值化图像
cv2.imshow("img_dilate", img_dilate) # 显示膨胀后的图像
cv2.waitKey(1) # 等待时间
效果如下所示:
如上图所示,我们可以看到包括太阳、噪声点在内的光点都被膨胀了5大圈,很明显这并不是我们想要看到的效果,但是如果我们在腐蚀后再加入膨胀操作,那是不是就能让太阳恢复到原本的状态呢?
具体程序如下所示:
import cv2 # 导入opencv库
if __name__ == '__main__':
while True:
img_g = cv2.imread('img/6.jpg', 0) # 获取路径img/0.jpg的图像,图像类型为RGB图像
img_g = cv2.resize(img_g, (0, 0), fx=0.5, fy=0.5) # 改变图像shape
img_GaussianBlur = cv2.GaussianBlur(img_g, (5, 5), 0) # 高斯滤波
t1, img_g_bin = cv2.threshold(img_g, 170, 255, cv2.THRESH_BINARY) # 二值化
t4, img_GaussianBlur_bin = cv2.threshold(img_GaussianBlur, 170, 255, cv2.THRESH_BINARY) # 二值化
img_erode = cv2.erode(img_GaussianBlur_bin, (3, 3), iterations=5) # 腐蚀
img_dilate = cv2.dilate(img_erode, (3, 3), iterations=5) # 膨胀
cv2.imshow("img_g", img_g) # 显示RGB图像
cv2.imshow("img_g_bin", img_g_bin) # 显示二值化图像
cv2.imshow("img_GaussianBlur", img_GaussianBlur) # 显示高斯滤波后的图像
cv2.imshow("img_GaussianBlur_bin", img_GaussianBlur_bin) # 显示高斯滤波后的二值化图像
cv2.imshow("img_end", img_dilate) # 显示腐蚀膨胀后的图像
cv2.waitKey(1) # 等待时间
效果如下所示:
如上图所示,噪声点已经全部消失,而太阳也恢复了原本的特征,形状和最初的二值化后的图像没有太大的差异。从代码中可以看到,我们先使用了(3, 3)的卷积核对二值化图像进行了5次腐蚀操作,此时噪声点已经被腐蚀掉了,但是太阳也少了大半截,这时候我们再使用(3, 3)的卷积核对腐蚀后的图像进行5次膨胀操作,因之前噪声点已经被腐蚀掉,所以起到膨胀效果的只有太阳这一特征物体。最后得到的二值化图像则是太阳恢复了,噪声点也消失了。
开运算其实就是上述的腐蚀膨胀操作,简单来说,开运算 = 先腐蚀后膨胀。
以下为opencv-python提供的开运算函数(cv2.MORPH_OPEN):
img_open = cv2.morphologyEx(img_GaussianBlur_bin, cv2.MORPH_OPEN, (x, x)) # 开运算
与开运算相反,闭运算 = 先膨胀后腐蚀。
以下为opencv-python提供的闭运算函数(cv2.MORPH_CLOSE):
img_close = cv2.morphologyEx(img_GaussianBlur_bin, cv2.MORPH_CLOSE, (x, x)) # 闭运算
具体程序如下所示:
import cv2 # 导入opencv库
if __name__ == '__main__':
while True:
img_g = cv2.imread('img/6.jpg', 0) # 获取路径img/0.jpg的图像,图像类型为RGB图像
img_g = cv2.resize(img_g, (0, 0), fx=0.5, fy=0.5) # 改变图像shape
img_GaussianBlur = cv2.GaussianBlur(img_g, (5, 5), 0) # 高斯滤波
t1, img_g_bin = cv2.threshold(img_g, 170, 255, cv2.THRESH_BINARY) # 二值化
t4, img_GaussianBlur_bin = cv2.threshold(img_GaussianBlur, 170, 255, cv2.THRESH_BINARY) # 二值化
img_open = cv2.morphologyEx(img_GaussianBlur_bin, cv2.MORPH_OPEN, (3, 3)) # 开运算
cv2.imshow("img_g", img_g) # 显示RGB图像
cv2.imshow("img_g_bin", img_g_bin) # 显示二值化图像
cv2.imshow("img_GaussianBlur", img_GaussianBlur) # 显示高斯滤波后的图像
cv2.imshow("img_GaussianBlur_bin", img_GaussianBlur_bin) # 显示高斯滤波后的二值化图像
cv2.imshow("img_open", img_open) # 显示开运算后的图像
cv2.waitKey(1) # 等待时间
以之前的案例为基础,这次改变了二值化的模式,改为cv2.THRESH_BINARY_INV,即大于阈值的部分取0,小于等于阈值的部分取最大值。如何再进行闭运算可观察出闭运算的作用。
关于二值化的其他模式可在此篇文章中查到,这里就不再赘述了:OpenCV python(四)图像预处理:二值化 && 滤波操作
具体程序如下所示:
import cv2 # 导入opencv库
if __name__ == '__main__':
while True:
img_g = cv2.imread('img/6.jpg', 0) # 获取路径img/0.jpg的图像,图像类型为RGB图像
img_g = cv2.resize(img_g, (0, 0), fx=0.5, fy=0.5) # 改变图像shape
img_GaussianBlur = cv2.GaussianBlur(img_g, (5, 5), 0) # 高斯滤波
t4, img_GaussianBlur_bin = cv2.threshold(img_GaussianBlur, 170, 255, cv2.THRESH_BINARY_INV) # 二值化
img_close = cv2.morphologyEx(img_GaussianBlur_bin, cv2.MORPH_CLOSE, (5, 5)) # 闭运算
cv2.imshow("img_GaussianBlur", img_GaussianBlur) # 显示高斯滤波后的图像
cv2.imshow("img_GaussianBlur_bin", img_GaussianBlur_bin) # 显示高斯滤波后的二值化图像
cv2.imshow("img_close", img_close) # 显示闭运算后的图像
cv2.waitKey(1) # 等待时间
效果如下所示:
可以看到,虽然不明显,但是确实是降噪了,道理还是差不多的,先膨胀将小黑洞膨胀掉,然后再腐蚀复原其他地方,这样子就能保证其他地方不变,同时实现降噪功能。如果是想要去掉另外两个小黑洞的话,可以将 (3)、腐蚀膨胀案例 中的腐蚀膨胀倒过来,然后用在如上的二值化图像中,效果会更加明显。
如下所示,此函数实现的效果类似于寻找边缘线:
img_GRADIENT = cv2.morphologyEx(img_GaussianBlur_bin, cv2.MORPH_GRADIENT, (x, x)) # 形态学梯度
具体案例程序如下所示:
import cv2 # 导入opencv库
if __name__ == '__main__':
while True:
img_g = cv2.imread('img/6.jpg', 0) # 获取路径img/0.jpg的图像,图像类型为RGB图像
img_g = cv2.resize(img_g, (0, 0), fx=0.5, fy=0.5) # 改变图像shape
img_GaussianBlur = cv2.GaussianBlur(img_g, (5, 5), 0) # 高斯滤波
t4, img_GaussianBlur_bin = cv2.threshold(img_GaussianBlur, 170, 255, cv2.THRESH_BINARY) # 二值化
img_GRADIENT = cv2.morphologyEx(img_GaussianBlur_bin, cv2.MORPH_GRADIENT, (3, 3)) # 形态学梯度
cv2.imshow("img_GaussianBlur", img_GaussianBlur) # 显示高斯滤波后的图像
cv2.imshow("img_GaussianBlur_bin", img_GaussianBlur_bin) # 显示高斯滤波后的二值化图像
cv2.imshow("img_GRADIENT", img_GRADIENT) # 显示形态学梯度后的图像
cv2.waitKey(1) # 等待时间
效果如下所示:
如上图所示,可以看到边缘断断续续,效果不佳。关于边缘检测,后续我会再写一篇关于图像边缘检测的文章。
顶帽操作是指开运算与原二值化图作差后再得到一张图像,即消除的噪声点汇总成的图像。opencv-python提供的函数如下所示:
img_TOPHAT = cv2.morphologyEx(img_GaussianBlur_bin, cv2.MORPH_TOPHAT, (x, x)) # 顶帽
黑帽操作和顶帽类似,是指闭运算与原二值化图作差后再得到的一张图像,也是一张消除的噪声点汇总成的图像。opencv-python提供的函数如下所示:
img_BLACKHAT = cv2.morphologyEx(img_GaussianBlur_bin, cv2.MORPH_BLACKHAT, (x, x)) # 黑帽
具体程序如下所示:
import cv2 # 导入opencv库
if __name__ == '__main__':
while True:
img_g = cv2.imread('img/6.jpg', 0) # 获取路径img/0.jpg的图像,图像类型为RGB图像
img_g = cv2.resize(img_g, (0, 0), fx=0.5, fy=0.5) # 改变图像shape
img_GaussianBlur = cv2.GaussianBlur(img_g, (5, 5), 0) # 高斯滤波
t4, img_GaussianBlur_bin = cv2.threshold(img_GaussianBlur, 170, 255, cv2.THRESH_BINARY) # 二值化
img_TOPHAT = cv2.morphologyEx(img_GaussianBlur_bin, cv2.MORPH_TOPHAT, (3, 3)) # 顶帽
img_BLACKHAT = cv2.morphologyEx(img_GaussianBlur_bin, cv2.MORPH_BLACKHAT, (3, 3)) # 黑帽
cv2.imshow("img_GaussianBlur", img_GaussianBlur) # 显示高斯滤波后的图像
cv2.imshow("img_GaussianBlur_bin", img_GaussianBlur_bin) # 显示高斯滤波后的二值化图像
cv2.imshow("img_TOPHAT", img_TOPHAT) # 显示顶帽后的图像
cv2.imshow("img_BLACKHAT", img_BLACKHAT) # 显示黑帽后的图像
cv2.waitKey(1) # 等待时间
图像对应上述程序的imshow,效果如下所示:
本人是一名学生,目前正在学习中,本篇文章也算是我的学习笔记,如有错误的话还请指正。