腐蚀:
图像的腐蚀和膨胀都是相对于像素值高(白色方向)说的,腐蚀简单的说就是白色”被腐蚀“了,也就是像素值低(黑色方向)的变多,白色变少。
腐蚀的原理是利用一个内核对图像进行卷积(扫描),内核中有一个点被定义为锚点,然后提取内核覆盖区域的像素最小值(黑色方向)来替换锚点位置的像素值,所以扫描过后黑色变多。
Mat img = imread("img.jpg");
imshow("src", img);
Mat erodeElement = getStructuringElement(MORPH_RECT, Size(10, 10)); // 获得内核
erode(img, img, erodeElement); // 腐蚀函数
imshow("erode", img);
waitKey(0);
膨胀:
和腐蚀一样,也是相对于白色来说,膨胀就是像素值高的(白色方向)变多了(膨胀了),和腐蚀相反,膨胀是提取内核区域的最大值(白色方向)来替换锚点位置的像素值。
Mat img = imread("img.jpg");
imshow("src", img);
Mat dilateElement = getStructuringElement(MORPH_RECT, Size(10, 10)); // 获得内核
dilate(img, img, dilateElement); // 膨胀函数
imshow("dilate", img);
import cv2 as cv
import numpy as np
def erode(img):
gray=cv.cvtColor(img,cv.COLOR_RGB2GRAY)
ret,binary=cv.threshold(gray,0,255,cv.THRESH_BINARY_INV | cv.THRESH_OTSU)
#获得结构元素
#第一个参数:结构元素形状,这里是矩形
#第二个参数:结构元素大小
kernel=cv.getStructuringElement(cv.MORPH_RECT,(5,5))
#执行腐蚀
dst=cv.erode(binary,kernel)
cv.imshow("erode",dst)
def dilate(img):
gray=cv.cvtColor(img,cv.COLOR_RGB2GRAY)
ret,binary=cv.threshold(gray,0,255,cv.THRESH_BINARY_INV | cv.THRESH_OTSU)
#获得结构元素
#第一个参数:结构元素形状,这里是矩形
#第二个参数:结构元素大小
kernel=cv.getStructuringElement(cv.MORPH_RECT,(5,5))
#执行膨胀
dst=cv.dilate(binary,kernel)
cv.imshow("dilate",dst)
src=cv.imread('num.jpg')
cv.imshow('def',src)
erode(src)
dilate(src)
cv.waitKey(0)
cv.destroyAllWindows()
目标
- 了解形态学操作的概念
- 学习膨胀、腐蚀、开运算和闭运算等形态学操作
- OpenCV函数:cv2.erode(), cv2.dilate(), cv2.morphologyEx()
教程
啥叫形态学操作
形态学操作其实就是改变物体的形状,比如腐蚀就是”变瘦”,膨胀就是”变胖”,看下图就明白了:
形态学操作一般作用于二值化图,来连接相邻的元素或分离成独立的元素。腐蚀和膨胀是针对图片中的白色部分!
腐蚀
腐蚀的效果是把图片”变瘦”,其原理是在原图的小区域内取局部最小值。因为是二值化图,只有0和255,所以小区域内有一个是0该像素点就为0:
这样原图中边缘地方就会变成0,达到了瘦身目的(小胖福利(●ˇ∀ˇ●))
OpenCV中用cv2.erode()
函数进行腐蚀,只需要指定核的大小就行:
img = cv2.imread('j.bmp', 0)
kernel = np.ones((5, 5), np.uint8)
erosion = cv2.erode(img, kernel) # 腐蚀
这个核也叫结构元素,因为形态学操作其实也是应用卷积来实现的。结构元素可以是矩形/椭圆/十字形,可以用
cv2.getStructuringElement()
来生成不同形状的结构元素,比如:
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) # 矩形结构
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)) # 椭圆结构
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5)) # 十字形结构
膨胀
膨胀与腐蚀相反,取的是局部最大值,效果是把图片”变胖”:
dilation = cv2.dilate(img, kernel) # 膨胀
开/闭运算
先腐蚀后膨胀叫开运算(因为先腐蚀会分开物体,这样容易记住),其作用是:分离物体,消除小区域。这类形态学操作用cv2.morphologyEx()
函数实现:
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) # 定义结构元素
img = cv2.imread('j_noise_out.bmp', 0)
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel) # 开运算
闭运算则相反:先膨胀后腐蚀(先膨胀会使白色的部分扩张,以至于消除/”闭合”物体里面的小黑洞,所以叫闭运算)
img = cv2.imread('j_noise_in.bmp', 0)
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel) # 闭运算
经验之谈:很多人对开闭运算的作用不是很清楚(好吧,其实是比较容易混◑﹏◐),但看上图↑,不用怕:如果我们的目标物体外面有很多无关的小区域,就用开运算去除掉;如果物体内部有很多小黑洞,就用闭运算填充掉。
接下来的3种形态学操作并不常用,大家有兴趣可以看看(因为较短,没有做成番外篇):
其他形态学操作
- 形态学梯度:膨胀图减去腐蚀图,
dilation - erosion
,这样会得到物体的轮廓:
img = cv2.imread('school.bmp', 0)
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
- 顶帽:原图减去开运算后的图:
src - opening
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
- 黑帽:闭运算后的图减去原图:
closing - src
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
小结
- 形态学操作就是改变物体的形状,如腐蚀使物体”变瘦”,膨胀使物体”变胖”
- 先腐蚀后膨胀会分离物体,所以叫开运算,常用来去除小区域物体
- 先膨胀后腐蚀会消除物体内的小洞,所以叫闭运算。开/闭理解了之后很容易记忆噢(⊙o⊙)
# ex2tron's blog:
# http://ex2tron.wang
import cv2
import numpy as np
# 1.腐蚀与膨胀
img = cv2.imread('j.bmp', 0)
kernel = np.ones((5, 5), np.uint8)
erosion = cv2.erode(img, kernel) # 腐蚀
dilation = cv2.dilate(img, kernel) # 膨胀
cv2.imshow('erosion/dilation', np.hstack((img, erosion, dilation)))
cv2.waitKey(0)
# 2.定义结构元素
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) # 矩形结构
print(kernel)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)) # 椭圆结构
print(kernel)
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5)) # 十字形结构
print(kernel)
# 3.开运算与闭运算
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) # 定义结构元素
# 开运算
img = cv2.imread('j_noise_out.bmp', 0)
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
cv2.imshow('opening', np.hstack((img, opening)))
cv2.waitKey(0)
# 闭运算
img = cv2.imread('j_noise_in.bmp', 0)
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
cv2.imshow('closing', np.hstack((img, closing)))
cv2.waitKey(0)
# 4.形态学梯度
img = cv2.imread('school.bmp', 0)
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
cv2.imshow('morphological gradient', np.hstack((img, gradient)))
cv2.waitKey(0)
# 5.顶帽
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
cv2.imshow('top hat', np.hstack((img, tophat)))
cv2.waitKey(0)
# 6.黑帽
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
cv2.imshow('black hat', np.hstack((img, blackhat)))
cv2.waitKey(0)
参考网址:
https://www.cnblogs.com/whlook/p/6476826.html
https://blog.csdn.net/jacke121/article/details/75331799
https://www.cnblogs.com/Undo-self-blog/p/8436389.html