目标
在这一章,
我们将学习不同的形态操作,如侵蚀、扩张、打开、关闭等。
我们将看到不同的功能,如 cv.erode(), cv.dilate(), cv.morphologyEx()等。
理论
形态转换是基于图像形状的一些简单操作。它通常是在二进制图像上执行的。它需要两个输入,一个是我们的原始图像,第二个是构造元素或内核,它决定了操作的性质。两种基本的形态运算符是侵蚀和扩张。然后它的变形形式,如开口,闭合,梯度等也开始发挥作用。我们将逐一看到它们,并提供以下图片:
- 1。侵蚀
侵蚀的基本思想就像土壤侵蚀一样,它侵蚀了前景物体的边界(总是试图将前景保持在白色)。它是怎么做的呢?内核在图像中滑动(就像在二维卷积中一样)。原始图像中的一个像素(1或0)只有在内核下的所有像素都是1时才会被认为是1,否则它就会被侵蚀(变成0)。
所以发生的是,边界附近的所有像素都将根据内核的大小而被丢弃。因此,前景对象的厚度或大小会减少或简单地减少图像中的白色区域。它有助于消除小的白色噪音(正如我们在彩色空间章节中看到的),分离两个连接的物体,等等。
在这里,作为一个例子,我将使用一个包含满1的5x5内核。让我们看看它是如何工作的:
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('j.png',0)
kernel = np.ones((5,5),np.uint8)
erosion = cv.erode(img,kernel,iterations = 1)
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(erosion ),plt.title('erosion')
plt.xticks([]), plt.yticks([])
plt.show()
- 2。扩张
它正好与侵蚀相反。在这里,一个像素元素是“1”,如果内核下至少有一个像素是“1”。所以它增加了图像的白色区域或者前景物体的大小增加了。通常情况下,在噪音去除的情况下,侵蚀之后是扩张。因为,侵蚀消除了白色的噪音,但它也使我们的物体收缩。所以我们扩张。既然噪音消失了,它们就不会回来了,但是我们的目标区域会增加。它在连接一个物体的破碎部分时也很有用。
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('oj.png',0)
kernel = np.ones((5,5),np.uint8)
dilation = cv.dilate(img,kernel,iterations = 1)
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(dilation ),plt.title('dilation')
plt.xticks([]), plt.yticks([])
plt.show()
- 3。开放
开放只是侵蚀的另一个名字,接着是扩张。正如我们上面所解释的,它在消除噪声方面很有用。这里我们使用的是函数,cv.morphologyEx()
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('oj.png',0)
kernel = np.ones((5,5),np.uint8)
opening = cv.morphologyEx(img, cv.MORPH_OPEN, kernel)
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(opening ),plt.title('opening')
plt.xticks([]), plt.yticks([])
plt.show()
- 图像
- 4所示。关闭
封闭是开放的逆转,扩张之后是侵蚀。它对于关闭前台对象中的小洞或对象上的小黑点是很有用的。
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('cj.png',0)
kernel = np.ones((5,5),np.uint8)
closing = cv.morphologyEx(img, cv.MORPH_CLOSE, kernel)
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(closing ),plt.title('closing')
plt.xticks([]), plt.yticks([])
plt.show()
- 5。形态学梯度
这就是图像的扩张和侵蚀的区别。
结果看起来就像这个物体的轮廓。
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('j.png')
kernel = np.ones((5,5),np.uint8)
gradient = cv.morphologyEx(img, cv.MORPH_GRADIENT, kernel)
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(gradient ),plt.title('gradient')
plt.xticks([]), plt.yticks([])
plt.show()
- 6。高顶礼帽
它是输入图像和图像的打开之间的区别。下面的例子是为9x9内核完成的。
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('j.png')
kernel = np.ones((5,5),np.uint8)
tophat = cv.morphologyEx(img, cv.MORPH_TOPHAT, kernel)
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(tophat ),plt.title('tophat')
plt.xticks([]), plt.yticks([])
plt.show()
- 7。黑帽
这是输入图像的关闭和输入图像之间的区别。
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('j.png')
kernel = np.ones((5,5),np.uint8)
blackhat = cv.morphologyEx(img, cv.MORPH_BLACKHAT, kernel)
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(blackhat ),plt.title('blackhat ')
plt.xticks([]), plt.yticks([])
plt.show()
结构化元素
我们在前面的例子中手动创建了一个结构化的元素,帮助Numpy。它是矩形。但在某些情况下,你可能需要椭圆/圆形的内核。因此,OpenCV有一个函数,cv.getstruct ingelement()。你只要传递内核的形状和大小,就会得到想要的内核。
# Rectangular Kernel >>> cv.getStructuringElement(cv.MORPH_RECT,(5,5)) array([[1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1]], dtype=uint8) # Elliptical Kernel >>> cv.getStructuringElement(cv.MORPH_ELLIPSE,(5,5)) array([[0, 0, 1, 0, 0], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [0, 0, 1, 0, 0]], dtype=uint8) # Cross-shaped Kernel >>> cv.getStructuringElement(cv.MORPH_CROSS,(5,5)) array([[0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [1, 1, 1, 1, 1], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0]], dtype=uint8) |