目录
2. 腐蚀(越有值的区域越被腐蚀 API是 cv2.erode())
8.形态学梯度
———————————————————————————————————————————
形态学变换(Morphological Transformations)是一种基于形状的简单变换,它的处理对象通常是二值化图像。形态学变换有两个输入,一个输出:输入为原图像、核(结构化元素),输出为形态学变换后的图像。其基本操作有腐蚀和膨胀等,其中腐蚀和膨胀这两种操作是相反的,即较亮的像素会被腐蚀和膨胀。
1.核
在自适应二值化操作的时候要框一个n*n的小区域,其中心点要将图中的每个像素点都遍历完,这个小区域就是“”核“”,小区域内每个位置的值就是核值。核有很多结构,矩阵、十字形、五角形等,通过不同的结构可以对不同特征的图像进行形态学操作的处理。
以下操作的核默认是3*3的矩形结构,全部用1填充,且都是针对前景色是白色的图。
2. 腐蚀(越有值的区域越被腐蚀 API是 cv2.erode())
腐蚀操作就是使用核在原图(二值化图)上进行从左到右、从上到下的滑动(也就是从图像的左上角开始,滑动到图像的右下角)。在滑动过程中,将被核覆盖区域的像素值与对应核值进行相乘,得到该区域内的最小值,该值就是卷积核覆盖区域的中心像素点的新像素值,接着继续滑动。由于操作图像为二值图,所以不是黑就是白,这就意味着,在被核值覆盖的区域内,只要有黑色(像素值为0),那么该区域的中心像素点必定为黑色(0)。这样做的结果就是会将二值化图像中的白色部分尽可能的压缩,如下图所示,该图经过腐蚀之后“变瘦”了。
核心代码展示:
def test1():
#腐蚀操作
img = cv2.imread("./src/long.png", cv2.IMREAD_GRAYSCALE) #读取图片为灰度图
kernel = np.ones((3,3), np.uint8) #定义核
img_er = cv2.erode(img, kernel) #参数1是需要操作的灰度图,参数2是核
cv2.imshow("img", img)
cv2.imshow("img_er", img_er)
cv2.waitKey(0)
还有一个参数是iterations,即腐蚀次数,如iterations=2,就是腐蚀两次,效果更明显
3.膨胀 (越有值的区域越扩展 dilate)
与腐蚀相反,在滑动过程中,将被核覆盖区域的像素值与对应核值进行相乘,得到该区域内的最大值,该值就是卷积核覆盖区域的中心像素点的新像素值,因为是二值图,像素点中最大值就是255.这就意味着白色的区域会扩展,如下图所示:
主要代码如下:
def test2():
#膨胀操作
img = cv2.imread("./src/long.png", cv2.IMREAD_GRAYSCALE) #读取图片为灰度图
kernel = np.ones((3,3), np.uint8) #定义核
img_di = cv2.dilate(img, kernel)
cv2.imshow("img", img)
cv2.imshow("img_di", img_di)
cv2.waitKey(0)
总结就是二值图经过膨胀操作后白色像素会变多
如果将两个操作结合到一起,比如先腐蚀再膨胀:
代码如下:
def test3():
img = cv2.imread("./src/csdntest1.png", cv2.IMREAD_GRAYSCALE) #读取图片为灰度图
kernel = np.ones((3,3), np.uint8) #定义核
img_er = cv2.erode(img, kernel) #先腐蚀
img_er_di = cv2.dilate(img_er, kernel) #再膨胀
cv2.imshow("img", img)
cv2.imshow("img_er", img_er)
cv2.imshow("img_er_di", img_er_di)
运行图片显示:
可以看到,原图先经过腐蚀操作后,有一些细小的白色像素点消失不见,再膨胀后也不会出现(图中红色圆圈部分),所以很适合消除背景色有很多雪花点那种图片。
这种先腐蚀后膨胀的操作有一个运算可以同时完成,即下面的开运算。
4.开运算(cv2.MORPH_OPEN)
开运算就是先腐蚀后膨胀,其作用是:分离物体,消除小区域。特点:消除噪点,去除小的干扰块,而不影响原来的图像。
与下面几个运算的API都为 cv2.morphologyEx(参数1,参数2,参数3),参数1为要操作的图,参数2为运算类型,参数3为核
代码如下:
def test4():
img = cv2.imread("./src/csdntest1.png", cv2.IMREAD_GRAYSCALE) #读取图片为灰度图
kernel = np.ones((3,3), np.uint8) #定义核
img_open = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel) #(参数1,参数2,参数3)
cv2.imshow("img_open", img_open)
cv2.imshow("img", img)
cv2.waitKey(0)
运行如图所示:
可以看到与上图一致。
5.闭运算(cv2.MORPH_CLOSE)
闭运算与开运算相反,是先膨胀后腐蚀,作用是消除/“闭合”物体里面的孔洞,特点:可以填充闭合区域
主要代码如下:
def test5():
#闭运算
img = cv2.imread("./src/csdntest2.png", cv2.IMREAD_GRAYSCALE)
kernel = np.ones((3,3), np.uint8)
img_close = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
cv2.imshow("img", img)
cv2.imshow("img_close", img_close)
cv2.waitKey(0)
cv2.MORPH_CLOSE 是闭运算的方法名字
运行结果图示:
可以看到,原本的黑色噪声点消失不见,因为周围的白色区域膨胀。虽然这里的前景色是黑色,但是运算还是以白色为主体。
6.顶帽运算(cv2.MORPH_TOPHAT)
原图像与“开运算“的结果图之差,因为开运算带来的结果是放大了裂缝或者局部低亮度的区域,因此,从原图中减去开运算后的图,得到的效果图突出了比原图轮廓周围的区域更明亮的区域,且这一操作和选择的核的大小相关。
当一幅图像具有大幅的背景,而微小物品比较有规律的情况下,可以使用顶帽运算进行背景提取,可以突出比背景亮的细小区域(如白噪声、亮斑、纹理等)。
主要代码如下:
def test6():
#顶帽运算
img = cv2.imread("./src/csdntest1.png", cv2.IMREAD_GRAYSCALE) #读取图片为灰度图
kernel = np.ones((3,3), np.uint8) #定义核
img_top = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
cv2.imshow("img", img)
cv2.imshow("img_top", img_top)
cv2.waitKey(0)
当然也可以直接用 原始图像 - 开运算图像
运行图示:
7.黑帽运算(cv2.MORPH_BLACKHAT)
与顶帽运算相反,是“”闭运算“”图像与原图之差,更适合提取暗细节(如黑色文字、指纹的谷线、医学图像中的血管)。
代码如下:
def test7():
#黑帽运算
img = cv2.imread("./src/csdntest2.png", cv2.IMREAD_GRAYSCALE)
kernel = np.ones((3,3), np.uint8)
img_black = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
cv2.imshow("img", img)
cv2.imshow("img_black", img_black)
cv2.waitKey(0)
运行结果图示:
可以看到,经过黑帽运算后的图像,只剩下噪声点,且变成了黑底白字,至于为什么会这样,是因为:首先原图经过闭运算(先膨胀后腐蚀)后会消除黑色的噪声点,结果图比原图更白,此时闭运算结果图约等于255,所以
黑帽图像 = 闭运算图像(255) - 原图白底(255)黑字(0)= 黑底(0)白字(255),
用数组表示更明显:
原图:
[255, 255, 255]
[255, 0, 255] ← 中心的黑像素点是文字
[255, 255, 255]
闭运算后(白色区域先膨胀将中间的黑色像素点填充,文字变白):
[255, 255, 255]
[255, 255, 255]
[255, 255, 255]
黑帽 = 闭运算 - 原图:
[ 0, 0, 0]
[ 0, 255, 0] ← 背景色由白变黑,白色的文字保留
[ 0, 0, 0]
总结顶帽和黑帽:
-
顶帽显示亮特征(原图减开运算),像揭掉帽子露出顶部灯光;
-
黑帽显示暗特征(闭运算减原图),像从帽子底下挖出隐藏的洞。
对比表格如下:
运算类型 | 公式 | 突出区域 | 典型应用场景 |
---|---|---|---|
顶帽 | 原图 - 开运算 | 亮细节(白点) | 文本增强、亮斑检测 |
黑帽 | 闭运算 - 原图 | 暗细节(黑点) | 医学图像、缺陷检测 |
8.形态学梯度(cv2.MORPH_GRADIENT)
形态学梯度是一个基于结构元素的图像处理方法,它通过比较原图像与膨胀图和腐蚀图之间的差异来突出图像边缘特征。具体来说,对于图像中的每个像素点,其形态学梯度值是该像素点在膨胀后的图像值与其在腐蚀后的图像值之差。这样得到的结果通常能够强化图像的边缘信息,并且对噪声有一定的抑制作用。
其实就是提取图像的轮廓或边缘。(边缘是轮廓的基础,只是局部像素变化,而轮廓是全局物体形状,必须是闭合的边界)
代码如下:
def test8():
#形态学梯度
img = cv2.imread("./src/csdntest2.png", cv2.IMREAD_GRAYSCALE)
kernel = np.ones((3,3), np.uint8)
img_tidu = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
cv2.imshow("img", img)
cv2.imshow("img_tidu", img_tidu)
cv2.waitKey(0)
运行图示:
可以看到,都是显示的物体的轮廓
(后期还会学到Canny边缘检测算法,同样也是提取图像边缘,二者区别在于形态学梯度适合提取字母、粗线条图形的轮廓,就像用马克笔描边时画出的粗线,内外边缘都被包括,而Canny算法更适合提取人脸、风景照片中的精细边缘,相当于铅笔描边,只保留最明显的单像素边缘)
形态学变换相关操作就到此结束,下一步:图片颜色识别。