OpenCV 形态学、模板匹配和运动检测
- 5. 形态学变换
- 5.1 膨胀
- 5.2 腐蚀
- 5.3 开操作
- 5.4 闭操作
- 5.5 示例
- 6. 模板匹配
- 7. 运动检测
5. 形态学变换
首先放上形态学变换的官方文档:[官网文档]
形态学变化是基于图像形状的一些简单操作。操作对象一般是二值图像,需要两个输入,一个是输入图像,另一个是3x3的结构元素(内核),决定了膨胀操作的本质。常见的操作是图像的膨胀和腐蚀。以及他们的进阶操作注入Opening、Closing、Gradient等等。
结构元素的形状
MORPH_RECT 矩形 MORPH_ELLIPSE 椭圆形 MORPH_CROSS 十字型
5.1 膨胀
跟卷积操作非常类似,有图像A和3x3的结构元素,结构元素在A上进行滑动。计算结构元素在A上覆盖的最大像素值来替换当前结构元素对应的正中间的元素
膨胀的作用:
- 对象边缘增加一个像素
- 使对象边缘平滑
- 减少了对象与对象之间的距离
dst = cv.dilate(src, kernel)
5.2 腐蚀
腐蚀和膨胀过程类似,唯一不同的是以覆盖的最小值替换当前的像素值
侵蚀的作用:
- 对象边缘减少一个像素
- 对象边缘平滑
- 弱化了对象与对象之间连接
dst = cv.erode(src, kernel)
5.3 开操作
先腐蚀,后膨胀,主要应用在二值图像或灰度图像
先腐蚀: 让当前窗口中最小的颜色值替换当前颜色值
后膨胀: 让当前窗口中最大的颜色值替换当前颜色值
作用:
- 一般用于消除小的干扰或噪点(验证码图的干扰线)
- 可以通过此操作配合结构元素,提取图像的横线和竖线
dst_open = cv.morphologyEx(src, cv.MORPH_OPEN, kernel)
5.4 闭操作
先膨胀,后侵蚀
一般用于填充内部缝隙
代码语言:javascript复制dst_close = cv.morphologyEx(src2, cv.MORPH_CLOSE, kernel)
5.5 示例
代码语言:javascript复制import cv2 as cv
src = cv.imread("../img/morph-opening.jpg")
src2 = cv.imread("../img/morph-closing.jpg")
# 定义结构元素
kernel = cv.getStructuringElement(cv.MORPH_RECT, (3, 3))
print kernel
# 腐蚀操作
dst_erode = cv.erode(src, kernel)
# 膨胀操作
dst_dilate = cv.dilate(dst_erode, kernel)
# 开操作:先腐蚀再膨胀
dst_open = cv.morphologyEx(src, cv.MORPH_OPEN, kernel)
# 闭操作:先膨胀再腐蚀
dst_close = cv.morphologyEx(src2, cv.MORPH_CLOSE, kernel)
cv.imshow("j", src)
cv.imshow("dst_erode", dst_erode)
cv.imshow("dst_dilate", dst_dilate)
cv.imshow("dst_open", dst_open)
cv.imshow("j", src2)
cv.imshow("dst_close", dst_close)
cv.waitKey()
6. 模板匹配
模板匹配就是在整个图像区域发现与给定子图像匹配的小块区域。
在OpenCV中提供了6种匹配度量方法。
- 平方差匹配法CV_TM_SQDIFF
- 归一化平方差匹配法CV_TM_SQDIFF_NORMED
- 相关匹配法CV_TM_CCORR
- 归一化相关匹配法CV_TM_CCORR_NORMED
- 系数匹配法CV_TM_CCOEFF
- 化相关系数匹配法CV_TMCCOEFF_NORMED
通常来讲,随着从简单测量方法(平方差)到更复杂的测量方法(相关系数法),我们可以获得越来越准确的匹配。然而这同时也会以越来越大的计算量为代价。对于选取何种方法,针对不同的匹配情况进行对此分析比较,选取更适合自己应用场景同时兼顾速度和精度的最佳方案。 注意 :对于方法SQDIFF和SQDIFF_NORMED两种方法来讲,越小的值就有着更高的匹配结果,而其余的方法则是数值越大匹配效果越好。
代码示例:
代码语言:javascript复制import cv2 as cv
# 加载原图
src = cv.imread("../img/zhaonimei.jpg")
cv.imshow("src", src)
# 加载模板
temp = cv.imread("../img/mei.jpg")
cv.imshow("template", temp)
# 输入参数:原图,模板,匹配度量方法
result = cv.matchTemplate(src, temp, cv.TM_SQDIFF)
# 将结果进行归一化处理
cv.normalize(result, result, 0, 1, cv.NORM_MINMAX)
print(result)
# 求最大值最小值
m_min, m_max, minLoc, maxLoc = cv.minMaxLoc(result)
print(minLoc, maxLoc, m_min, m_max)
cv.rectangle(src, (minLoc[0], minLoc[1]), (minLoc[0] temp.shape[1], minLoc[1] temp.shape[0]), (0, 0, 255), 2)
cv.imshow("dst", src)
cv.waitKey()
7. 运动检测
代码示例:
代码语言:javascript复制import cv2 as cv
capture = cv.VideoCapture("../img/vtest.avi")
flag = capture.isOpened()
print(flag)
flag, frame = capture.read()
# 初始化BS模型
mog2 = cv.createBackgroundSubtractorMOG2(detectShadows=True)
# 形态学变换去掉噪声
kernel = cv.getStructuringElement(cv.MORPH_RECT, (3, 3))
# frame = None
# Mask = None
while flag:
flag, frame = capture.read()
if not flag:
break
cv.imshow("frame", frame)
Mask = mog2.apply(frame)
# thresh, mogMask = cv.threshold(Mask, 120, 255, cv.THRESH_BINARY)
Mask = cv.morphologyEx(Mask, cv.MORPH_OPEN, kernel)
_, contours, _ = cv.findContours(Mask, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
for i, contour in enumerate(contours):
area = cv.contourArea(contour)
if area > 500:
cv.drawContours(frame, contours, i, (0, 0, 255), 2, cv.LINE_AA)
rect = cv.boundingRect(contour)
print(rect)
cv.rectangle(frame, (rect[0], rect[1]), (rect[0] rect[2], rect[1] rect[3]), (255, 0, 0), 2)
cv.imshow("frame", frame)
cv.imshow("mog2", Mask)
key = cv.waitKey(100)
if key == 27:
break
capture.release()
cv.destroyAllWindows()