OpenCV-Python 笔记(三)形态学转换,图像梯度

形态学转换

侵蚀

侵蚀的原理是,一个卷积核,当它在图片上滑动的时候,只有在卷积核内所有像素都是1时,才被认为是1,如果有一个是0,则全部像素被替换成0。直观感受就是,黑色会向外扩散,从而导致黑色区域的边缘向外扩展。

img=cv.imread("text.jpg")

#创建一个卷积核
kernel=np.ones((5,5),np.uint8)
#侵蚀
erosion=cv.erode(img,kernel,iterations=1)

plt.subplot(121),plt.imshow(img),plt.title("Original")
plt.subplot(122),plt.imshow(erosion),plt.title("erosion")
plt.show()

在这里插入图片描述

扩张

它和侵蚀相反,白色会向白色区域边界扩展。因为侵蚀会将噪音去掉,也会导致图像缩小,所以采用扩张,对图像进行放大。

img=cv.imread("text.jpg")

kernel=np.ones((3,3),np.uint8)
#(图片,卷积核,迭代次数)
dilation=cv.dilate(img,kernel,iterations=1)

plt.subplot(121),plt.imshow(img),plt.title("Original")
plt.subplot(122),plt.imshow(dilation),plt.title("erosion")
plt.show()

在这里插入图片描述

开运算

开运算就是结合了侵蚀和扩张的滤波器,它先是对图像进行侵蚀,然后再进行扩张,对去噪声很有效。

img=cv.imread("text.jpg")

kernel=np.ones((3,3),np.uint8)
opening=cv.morphologyEx(img,cv.MORPH_OPEN,kernel)

plt.subplot(121),plt.imshow(img),plt.title("Original")
plt.subplot(122),plt.imshow(opening),plt.title("erosion")
plt.show()

注意观察红框内变化
在这里插入图片描述

闭运算

闭运算和开运算相反,先进行扩张,然后再侵蚀,因此,在图像上表现为黑色区域会减少,甚至被白色取代。

img=cv.imread("text.jpg")

kernel=np.ones((3,3),np.uint8)
closing=cv.morphologyEx(img,cv.MORPH_CLOSE,kernel)

plt.subplot(121),plt.imshow(img),plt.title("Original")
plt.subplot(122),plt.imshow(closing),plt.title("erosion")
plt.show()

在这里插入图片描述

形态学梯度

它有点类似于电脑上的高对比度模式,也有点开运算与闭运算交集的样子,从图像上看,白色会变成黑色,黑色变成白色,不同颜色仅保留边界的一部分,其余变成黑色。

img=cv.imread("text.jpg")

kernel=np.ones((2,2),np.uint8)
gradient=cv.morphologyEx(img,cv.MORPH_GRADIENT,kernel)

plt.subplot(121),plt.imshow(img),plt.title("Original")
plt.subplot(122),plt.imshow(gradient),plt.title("erosion")
plt.show()

在这里插入图片描述

顶帽

它是输入图片和开运算的差(隐隐约约有一种水平边缘检测的味道哈哈哈)

img=cv.imread("text.jpg")

kernel=np.ones((2,2),np.uint8)
tophat=cv.morphologyEx(img,cv.MORPH_TOPHAT,kernel)

plt.subplot(121),plt.imshow(img),plt.title("Original")
plt.subplot(122),plt.imshow(tophat),plt.title("erosion")
plt.show()

在这里插入图片描述

黑帽

它是输入图像与闭运算的差值(这个又像彩色版的垂直边缘检测。。。)

img=cv.imread("text.jpg")

kernel=np.ones((2,2),np.uint8)
blackhat=cv.morphologyEx(img,cv.MORPH_BLACKHAT,kernel)

plt.subplot(121),plt.imshow(img),plt.title("Original")
plt.subplot(122),plt.imshow(blackhat),plt.title("erosion")
plt.show()

在这里插入图片描述

结构函数

numpy可以建立ones,zeros这类矩形矩阵,但是有时候需要椭圆或者圆型,或者十字矩阵,numpy就会显得比较复杂。openCV提供了一个函数getStrcturingElement来快速创建这些特殊的矩阵,只需要输入矩阵大小就可以创建。

print(cv.getStructuringElement(cv.MORPH_RECT,(5,5)))
print(cv.getStructuringElement(cv.MORPH_ELLIPSE,(5,5)))
print(cv.getStructuringElement(cv.MORPH_CROSS,(5,5)))

矩形
[[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]]

椭圆
[[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]]

十字
[[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]]

图像梯度

Sobel

图像梯度的Sobel操作,是结合高斯函数平滑和Sobel算子的过滤操作,更加抗噪音,效果更好。一般Sobel算子是一个3*3的卷积核,它的形式为(Gy方向):
1,0,-1
2,0,-2
1,0,-1
实际上,Sobel就是将普通的边缘滤波器的中间行或者列,添加了权重。它在深度学习中也同样有用,作为滤波器,它的作用是进行垂直边缘检测。
注意它的图像是从左往右从亮到暗的。
而将它顺时针旋转90°,可以得到水平边缘检测器,同时也是图像梯度的Gx方向。
1,2, 1
0,0 ,0
-1,-2,-1
注意它的图像是从上往下,逐渐变暗.

Sobel_y=np.float32([[1,0,-1],[2,0,-2],[1,0,-1]])
Sobel_x=np.float32([[1,2,1],[0,0,0],[-1,-2,-1]])
plt.subplot(121),plt.imshow(Sobel_y),plt.title("Sobel_y")
plt.gray()
plt.subplot(122),plt.imshow(Sobel_x),plt.title("Sobel_x")
plt.gray()
plt.show()

在这里插入图片描述
在openCV中,可以指定卷积核的大小,ksize就是卷积核的大小。

Scharr

Scharr算子是Sobel的进阶版,它给每个元素都添加权重,它的表示形式和Sobel一样,但是数字进行了改变,3 X 3卷积核内元素之间的差值更大,从而更好地进行垂直和水平边缘检测。当ksize=-1时,使用 3 X 3 Scharr算子。它的形式:
3,0, -3
10,0,-10
3,0, -3
同样的,它的图像和Sobel表现一致。

Sobel_y=np.float32([[1,0,-1],[2,0,-2],[1,0,-1]])
Sobel_x=np.float32([[1,2,1],[0,0,0],[-1,-2,-1]])
Scharr_y=np.float32([[3,0,-3],[10,0,-10],[3,0,-3]])
Scharr_x=np.float32([[3,10,3],[0,0,0],[-3,-10,-3]])
plt.subplot(221),plt.imshow(Sobel_y),plt.title("Sobel_y")
plt.gray()
plt.subplot(222),plt.imshow(Sobel_x),plt.title("Sobel_x")
plt.gray()
plt.subplot(223),plt.imshow(Scharr_y),plt.title("Scharr_y")
plt.gray()
plt.subplot(224),plt.imshow(Scharr_x),plt.title("Scharr_x")
plt.gray()
plt.show()

在这里插入图片描述

Laplacian

它的每阶导数有Sobel算子计算,然后再用一个特殊的十字滤波器过滤。这个滤波器是:
0,1,0
1,-4,1
0,1,0

Laplacian=np.float32([[0,1,0],[1,-4,1],[0,1,0]])
plt.imshow(Laplacian),plt.title("Laplacian")
plt.gray()
plt.show()

在这里插入图片描述

在图片上的效果

彩色图片必须转换成灰色,它们只是一个2D滤波器。

img=cv.imread("text.jpg",0)
laplacian=cv.Laplacian(img,cv.CV_64F)
sobel_x=cv.Sobel(img,cv.CV_64F,1,0,ksize=3)
sobel_y=cv.Sobel(img,cv.CV_64F,0,1,ksize=3)
plt.subplot(221),plt.imshow(img,cmap="gray"),plt.title("Original")
plt.subplot(222),plt.imshow(laplacian,cmap="gray"),plt.title("Laplacian")
plt.subplot(223),plt.imshow(sobel_x,cmap="gray"),plt.title("Sobel_x")
plt.subplot(224),plt.imshow(sobel_y,cmap="gray"),plt.title("Sobel_y")
plt.show()

在这里插入图片描述
细节:
在这里插入图片描述

注意
在我们的示例中,输出数据类型为cv.CV_8U 或np.uint8 。但这有一个小问题。黑色到白色的过渡被视为正斜率(具有正值),而白色到黑色的过渡被视为负斜率(具有负值)。因此,当您将数据转换np.uint8时,所有负斜率均设为零。简而言之,您会错过这一边缘信息。

如果要检测两个边缘,更好的选择是将输出数据类型保留为更高的形式,例如cv.CV_16S ,cv.CV_64F 等,取其绝对值,然后转换回cv.CV_8U 。 下面的代码演示了用于水平Sobel滤波器和
结果差异的此过程。

©️2020 CSDN 皮肤主题: 1024 设计师:上身试试 返回首页