24

Python 图像处理 OpenCV (9):图像处理形态学开运算、闭运算以及梯度运算

 3 years ago
source link: http://www.cnblogs.com/babycomeon/p/13112687.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

AFBVfia.png!web

前文传送门:

「Python 图像处理 OpenCV (1):入门」

「Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像」

「Python 图像处理 OpenCV (3):图像属性、图像感兴趣 ROI 区域及通道处理」

「Python 图像处理 OpenCV (4):图像算数运算以及修改颜色空间」

「Python 图像处理 OpenCV (5):图像的几何变换」

「Python 图像处理 OpenCV (6):图像的阈值处理」

「Python 图像处理 OpenCV (7):图像平滑(滤波)处理」

「Python 图像处理 OpenCV (8):图像腐蚀与图像膨胀」

引言

前面介绍了图像形态学的两种基础算法,图像腐蚀和图像膨胀,本篇接着介绍图像形态学中的开运算、闭运算以及梯度运算。

由于内容的连贯性,请先阅读前文 「Python 图像处理 OpenCV (8):图像腐蚀与图像膨胀」 ,了解清楚图像的腐蚀与膨胀基础原理。

不然真的没办法理解开运算和闭运算。

第一件事情还是给图像增加噪声,思路沿用之前加噪声的思路,使用 Numpy 给图片添加黑白两种噪声点,代码如下:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

# 读取图片
img = cv.imread("demo.png", cv.IMREAD_UNCHANGED)
source = cv.cvtColor(img, cv.COLOR_BGR2RGB)
rows, cols, chn = source.shape

# 加噪声-白点噪声
for i in range(500):
    x = np.random.randint(0, rows)
    y = np.random.randint(0, cols)
    source[x, y, :] = 255

# 图像保存 白点噪声图像
cv.imwrite("demo_noise_white.jpg", source)
print("白点噪声添加完成")

# 重新读取图像
img1 = cv.imread("demo.png", cv.IMREAD_UNCHANGED)
source1 = cv.cvtColor(img1, cv.COLOR_BGR2RGB)

# 加噪声-黑点噪声
for i in range(1000):
    x = np.random.randint(0, rows)
    y = np.random.randint(0, cols)
    source1[x, y, :] = 0

# 图像保存 黑点噪声图像
cv.imwrite("demo_noise_black.jpg", source1)
print("黑点噪声添加完成")

# 显示结果
titles = ['White Img','Black Img']
images = [source, source1]

# matplotlib 绘图
for i in range(2):
   plt.subplot(1, 2, i+1), plt.imshow(images[i],'gray')
   plt.title(titles[i])
   plt.xticks([]),plt.yticks([])

plt.show()

fUfURn6.png!web

形态学开运算

图像开运算实际上是一个组合运算,开运算是图像先进行腐蚀,再进行膨胀的运算。

图像被腐蚀后,去除了噪声,但是也压缩了图像;接着对腐蚀过的图像进行膨胀处理,使得刚才在腐蚀过程中被压缩的图像得以恢复原状。

下面是一个图像开运算的流程图:

jeQzEb7.png!web

开运算的一些特性:

  • 开运算能够除去孤立的小点,毛刺和小桥,而总的位置和形状不便。
  • 开运算是一个基于几何运算的滤波器。
  • 结构元素大小的不同将导致滤波效果的不同。
  • 不同的结构元素的选择导致了不同的分割,即提取出不同的特征。

我们先不管开运算 OpenCV 为我们提供的函数是什么,先使用前面介绍过的图像腐蚀与膨胀处理看下结果:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

# 读取图片
source = cv.imread("demo_noise_white.jpg", cv.IMREAD_GRAYSCALE)

# 设置卷积核
kernel = np.ones((5, 5),np.uint8)

# 图像腐蚀
erode_img = cv.erode(source, kernel)

# 图像膨胀
dilate_result = cv.dilate(erode_img, kernel)

# 显示结果
titles = ['Source Img','Erode Img','Dilate Img']
images = [source, erode_img, dilate_result]

# matplotlib 绘图
for i in range(3):
   plt.subplot(1, 3, i+1), plt.imshow(images[i],'gray')
   plt.title(titles[i])
   plt.xticks([]),plt.yticks([])

plt.show()

qeYJZvQ.png!web

可以看到降噪的效果还是不错的。

接着看 OpenCV 为开运算提供的函数。

图像开运算主要使用到的函数是 morphologyEx() 它是形态学扩展的一组函数,而其中的 cv.MORPH_OPEN 对应的是开运算。

使用时语法如下:

dst = cv.morphologyEx(src, cv.MORPH_OPEN, kernel)
  • src: 原图形
  • cv2.MORPH_OPEN: 表示开运算
  • kernel: 卷积核

我们再使用 morphologyEx() 函数去重新实现下刚才的图像开运算,看下和之前的结果有啥区别:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

# 读取图片
source = cv.imread("demo_noise_white.jpg", cv.IMREAD_GRAYSCALE)

# 设置卷积核
kernel = np.ones((5, 5),np.uint8)

#图像开运算
dst = cv.morphologyEx(source, cv.MORPH_OPEN, kernel)

# 显示结果
titles = ['Source Img','Dst Img']
images = [source, dst]

# matplotlib 绘图
for i in range(2):
   plt.subplot(1, 2, i+1), plt.imshow(images[i],'gray')
   plt.title(titles[i])
   plt.xticks([]),plt.yticks([])

plt.show()

6ZfQ7rY.png!web

至少从肉眼的角度上看不出来和之前的方式有啥区别,实际上也没啥区别。

形态学闭运算

与开运算相反的是闭运算,闭运算是图像先膨胀,后腐蚀,它有助于关闭前景物体内部的小孔,或物体上的小黑点。

先看下图像闭运算的流程图:

QZ3ENjR.png!web

闭运算的一些特性:

  • 闭运算能够填平小湖(即小孔),弥合小裂缝,而总的位置和形状不变。
  • 闭运算是通过填充图像的凹角来滤波图像的。
  • 结构元素大小的不同将导致滤波效果的不同。
  • 不同结构元素的选择导致了不同的分割。

首先还是用 dilate()erode() 函数实现一下图像闭运算,代码如下:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

# 读取图片
source = cv.imread("demo_noise_black.jpg", cv.IMREAD_GRAYSCALE)

# 设置卷积核
kernel = np.ones((5, 5),np.uint8)

# 图像膨胀
dilate_result = cv.dilate(source, kernel)

# 图像腐蚀
erode_img = cv.erode(dilate_result, kernel)

# 显示结果
titles = ['Source Img','Dilate Img','Erode Img']
images = [source, dilate_result, erode_img]

# matplotlib 绘图
for i in range(3):
   plt.subplot(1, 3, i+1), plt.imshow(images[i],'gray')
   plt.title(titles[i])
   plt.xticks([]),plt.yticks([])

plt.show()

ae6Z32Y.png!web

如果想要使用形态学扩展的函数 morphologyEx() 则需要把里面的参数换成 MORPH_CLOSE ,同样,既然是形态学扩展函数,那么图像腐蚀和图像膨胀也有对应的参数:

MORPH_ERODE
MORPH_DILATE

接着还是使用 MORPH_CLOSE 参数来实现下图像的闭运算:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

# 读取图片
source = cv.imread("demo_noise_black.jpg", cv.IMREAD_GRAYSCALE)

# 设置卷积核
kernel = np.ones((5, 5),np.uint8)

# 图像闭运算
dst = cv.morphologyEx(source, cv.MORPH_CLOSE, kernel)

# 显示结果
titles = ['Source Img','Dst Img']
images = [source, dst]

# matplotlib 绘图
for i in range(2):
   plt.subplot(1, 2, i+1), plt.imshow(images[i],'gray')
   plt.title(titles[i])
   plt.xticks([]),plt.yticks([])

plt.show()

7zEnquy.png!web

形态学梯度运算

图像形态学的梯度运算和前面的开运算闭运算是一样的,都是组合函数。

梯度运算实际上是图像膨胀减去图像腐蚀后的结果,最终我们得到的是一个类似于图像轮廓的图形。

zMZBzuQ.png!web

梯度运算在 morphologyEx() 函数中的参数是 MORPH_GRADIENT ,示例代码如下:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

# 读取图片
source = cv.imread("demo.png", cv.IMREAD_GRAYSCALE)

# 设置卷积核
kernel = np.ones((5, 5), np.uint8)

# 图像梯度运算
dst = cv.morphologyEx(source, cv.MORPH_GRADIENT, kernel)

# 显示结果
titles = ['Source Img','Dst Img']
images = [source, dst]

# matplotlib 绘图
for i in range(2):
   plt.subplot(1, 2, i+1), plt.imshow(images[i],'gray')
   plt.title(titles[i])
   plt.xticks([]),plt.yticks([])

plt.show()

baqI73y.png!web

示例代码

如果有需要获取源码的同学可以在公众号回复「OpenCV」进行获取。

参考

http://www.woshicver.com/

https://blog.csdn.net/Eastmount/article/details/83651172

https://blog.csdn.net/hanshanbuleng/article/details/80657148


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK