物体运动检测的一个思想流程以及实现
直接上代码
# coding: utf-8
import cv2
import psutil
import threading
video = cv2.VideoCapture(0)
# video = cv2.VideoCapture(r'E:\AIcamera\6773897721212085802.MP4')
# KNN背景分割器,设置阴影检测
background = None
while True:
# 读取视频每一帧
ret, frame = video.read()
#将第一帧作为背景图像
if background is None:
background = frame
continue
frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
background_gray = cv2.cvtColor(background, cv2.COLOR_BGR2GRAY)
cv2.imshow('frame-gray', frame_gray)
cv2.imshow('background-gray', background_gray)
#图像与背景做减法
diff = cv2.absdiff(frame_gray, background_gray)
cv2.imshow('diff', diff)
#求做了减法之后的二值化处理
threshold = cv2.threshold(diff, 20, 255, cv2.THRESH_BINARY)[1]
cv2.imshow('threshold', threshold)
#图像腐蚀滤波降噪----取出图像中的小噪点,使得颜色更加突出
"""
src 输入的图像名字;信道的数目可以是任意的,但深度应该是cv_8u、cv_16u、cv_16、cv_32f或cv_64f。
dst 输出与输入相同大小和类型的图像.
kernel 用于侵蚀的结构元素;如果元素=mat(),则使用3 x 3矩形结构元素。可以使用getStructuringElement来创建结构元素。。
anchor 结构元素的锚点位置,默认值value(-1,-1)表示锚点位于结构元素中心
iterations 腐蚀操作被递归执行的次数
borderType 推断边缘类型,可参考BorderTypes
borderValue 在边框不变的情况下的边界值
getStructuringElement()
矩形:MORPH_RECT;
交叉形:MORPH_CROSS;
椭圆形:MORPH_ELLIPSE;
第二和第三个参数分别是内核的尺寸以及锚点的位置。一般在调用erode以及dilate函数之前,先定义一个Mat类型的变量来获得
"""
kernel_ercode = cv2.getStructuringElement(cv2.MORPH_RECT,(11, 11))
kernel_dilate = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
# ercode = cv2.erode(threshold, None)
# cv2.imshow('ercode', ercode)
#高斯平滑滤波
gas = cv2.GaussianBlur(threshold, (25, 25), 0)
cv2.imshow('gas', gas)
#膨胀图像
dilate = cv2.dilate(gas, kernel_dilate, iterations=5)
cv2.imshow('dilate', dilate)
#查找轮廓并且绘制出轮廓
contours, hierarchy = cv2.findContours(diff.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
if cv2.contourArea(c) > 2500:
# 绘制目标矩形框
(x, y, w, h) = cv2.boundingRect(c)
cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 255, 0), 2)
cv2.imshow('frame', frame)
if cv2.waitKey(10) & 0xff == ord('q'):
break
video.release()
cv2.destroyAllWindows()
使用KNN算法做物体运动检测
可参考此文章:
https://rinetd.gitlab.io/language/python/opencv/opencv-erode-dilate/
“”“
知识点:
腐蚀 :
腐蚀操作会把前景物体的边缘腐蚀掉。原理是卷积核沿着图像滑动,如果与卷积核对应的原图像像素值都是1,那么中心元素保持原值,否则为0.
效果,靠近前景的像素被腐蚀为0,前景物体变小,图像白色区域减少,对于去除白噪声很有用,可以断开两个连接在一起的物体。
膨胀 :
与腐蚀相反,卷积核当中只要有一个值是1,中心元素值就是1。此操作会增加前景中的白色区域,一般在去噪声的时候都是先腐蚀再膨胀,腐蚀的过程会使得前景变小,使用膨胀操作使前景变换回来。膨胀也可以使相互分离的物体连接。
腐蚀的作用是消除物体的边界点,使目标缩小,这个根据操作的过程可以显然的想到,物体的边界处像素值肯定是有0和1,腐蚀操作后这些紧邻着为1的像素点都会变成0,所以腐蚀操作会消除那些小的且无意义的物体,使边界向内部收缩的过程。
相反,膨胀(dilate)的作用当然是使目标增大,填充物体内细小的空洞,并且平滑物体的边界,边界向外部扩张的作用。
开运算是先腐蚀(erode)后膨胀(dilate)的过程,可以消除图像上细小的噪声,并平滑物体的边界
闭运算是先膨胀(dilate)后腐蚀(erode)的过程,可以填充物体内细小的空洞,并平滑物体边界
”“”
import cv2
# 获取视频
video = cv2.VideoCapture(0)
# video = cv2.VideoCapture(r'E:\AIcamera\6773897721212085802.MP4')
# KNN背景分割器,设置阴影检测
bs = cv2.createBackgroundSubtractorKNN(detectShadows=True)
while True:
# 读取视频每一帧
ret, frame = video.read()
# 计算视频的前景掩码
fgmask = bs.apply(frame)
# 图像阈值化
th = cv2.threshold(fgmask.copy(), 244, 255, cv2.THRESH_BINARY)[1]
erode = cv2.erode(th, (21, 21), iterations=1)
# 膨胀图像,减少错误
dilated = cv2.dilate(erode, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)), iterations=2)
# 得到图像中的目标轮廓
contours, hier = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
if cv2.contourArea(c) > 1500:
# 绘制目标矩形框
(x, y, w, h) = cv2.boundingRect(c)
cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 255, 0), 2)
# 显示差异视频
cv2.imshow('mog', fgmask)
cv2.imshow('thresh', th)
cv2.imshow('erode', erode)
cv2.imshow('dilated', dilated)
# 显示检测视频
cv2.imshow('detection', frame)
if cv2.waitKey(10) & 0xff == ord('q'):
break
video.release()
cv2.destroyAllWindows()