本文学习资源来自《机器学习实践指南》
运动侦测,英文翻译为“Motion detection technology”,一般也叫移动检测,常用于无人值守监控录像和自动报警。通过摄像头按照不同帧率采集得到的图像会被CPU按照一定算法进行计算和比较,当画面有变化时,如有人走过,镜头被移动,计算比较结果得出的数字会超过阈值并指示系统能自动作出相应的处理。
-----百度百科
示例中首先设置捕获设备,然后每15毫秒更新一次画面显示,并检测是否退出。
# -*- coding: utf-8 -*-
import cv2
mycap = cv2.VideoCapture(0)
id=0
while True:
ret , im=mycap.read()
cv2.imshow('myvideo',im)
# 每15毫秒采集1次
key = cv2.waitKey(15)
# 空格键退出
if key ==32:
break
elif key == ord('c'):
cv2.imwrite('vd_'+str(id)+'.png',im)
id += 1
每次按c键后,采集连接图像。
可按帧生成视频图像序列数组。
# -*- coding: utf-8 -*-
import cv2
import numpy as np
mycap = cv2.VideoCapture(0)
myframes = []
while True:
ret, im=mycap.read()
cv2.imshow('myvideo',im)
# 采集
myframes.append(im)
# 每15ms采集1次
key = cv2.waitKey(15)
# 空格键退出
if key ==32:
break
# 生成视频帧数组
myframes = np.array(myframes)
print(myframes)
mycapture = cv2.VideoCapture("视频文件")
差分检测根据当前图像与参考图像的差别分析来判断序列图像中是否有运动的物体。在环境亮度变化不大的情况下,如果对应像素灰度值的差异小于某个阈值,则认为画面静止无运动变化,如果图像区域某处的灰度变化大于某个阈值,则认为这是由于图像中运动 的物体所引起的,然后求出运动目标在图像中的位置。
帧差法的特点是实现简单,运算速度快,对于动态环境自适应性是很强的,对光线的变化不是十分的敏感。但是在运动体内易产生空洞.特别是目标运动速度较快时,影响目标区域准确提取。我们以年辆检测为例,车辆检测除了要检测出运动车辆.同时还要检测出暂时停止的车辆,在这个方面,此类方法无能为力。而且如果车辆的体积较大,那么车辆在前后帧中根容易产生重叠部分,尤其是大货车,这使得帧问差分的结果主要为车头和车尾。车辆中间部分的差分值相对报小.形成空洞,不利于检测。
算法过程:
其中,fk(i,j)f_k(i,j)fk(i,j) 表示第 kkk 个图像矩阵(i,j)(i,j)(i,j) 处的灰度值,D(i,j)D(i,j)D(i,j) 表示差分矩阵(i,j)(i,j)(i,j) 处的值。
2. 如果差分矩阵不全为0,则表示检测到运动 。如果有必要,可按一定的运动检测次数对运动画面进行分组,并融合叠加形成多组运动轨迹图。
3. 取下一帧图像,转到(1),直到所有帧图像全部处理退出。
程序示例
# -*- coding: utf-8 -*-
import cv2
import numpy as np
fn=[]
for i in range(7):
fn.append("vd_"+str(i) + ".png")
img = [] # 灰度图像数组
colorimg =[] # 彩色图像数组
myimg =[] # 临时变量
for i in range(len(fn) -1):
tmpimg = (cv2.imread(fn[i]))
colorimg.append(tmpimg)
myimg = cv2.cvtColor(tmpimg,cv2.COLOR_BGR2GRAY)
img.append(myimg)
# 差分计算
myimg1 = colorimg[0].copy()
myimg2 = myimg1.copy()
w = myimg1.shape[1]
h = myimg1.shape[0]
moveimg1 = np.zeros((h, w),np.uint8)
moveimg2 = np.zeros((h,w,3),np.uint8)
for ii in range(len(fn)-2):
print (u'开始分析第' + str(ii+2) + u'个运动图像')
myd = img[ii+1] -img[ii]
# 生成差分矩阵
THRESHOLD = int(np.median(abs(myd))) # 取中位数做为阈值
mymove = np.ones([h,w],np.uint8)
for i in range(h):
for j in range(w):
if abs(myd[i,j]) < THRESHOLD or myd[i,j]==0:
mymove[i,j]=0
# 如果有物体运动
if np.sum(mymove)>0:
print(u"第"+str(ii+2)+u"个运动图像发生了变化 ")
moveimg1 = img[ii+1]*(1-mymove)*0.16+img[ii]*(1-mymove)*0.16+moveimg1
moveimg2 = colorimg[ii+1]*0.16 + colorimg[ii]*0.16+moveimg2
moveimg1 = np.array(moveimg1,np.uint8)
moveimg2 = np.array(moveimg2,np.uint8)
# 显示移动部分
moveimg1 = moveimg1-img[0]
# 灰度图二值化以更好地显示运动的效果
retval, showimg1 = cv2.threshold(moveimg1, 140,255,cv2.THRESH_BINARY)
showimg1=moveimg1
showimg2=moveimg2
cv2.imshow("move1", showimg1)
cv2.imshow("move2", showimg2)
cv2.waitKey()
cv2.destroyAllWindows()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1h8unCdr-1574725721409)(https://img-blog.csdn.net/20171111234913638?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveHVuZGg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)]
# -*- coding: utf-8 -*-
import cv2
import numpy as np
fn=[]
for i in range(7):
fn.append("vd_"+str(i) + ".png")
img = [] # 灰度图像数组
colorimg =[] # 彩色图像数组
myimg =[] # 临时变量
for i in range(len(fn) -1):
tmpimg = (cv2.imread(fn[i]))
colorimg.append(tmpimg)
myimg = cv2.cvtColor(tmpimg,cv2.COLOR_BGR2GRAY)
img.append(myimg)
# 差分计算
myimg = colorimg[0].copy()
w = myimg.shape[1]
h = myimg.shape[0]
moveimg = np.zeros((h, w, 3),np.uint8)
for ii in range(len(fn)-2):
print (u'开始分析第' + str(ii+2) + u'个运动图像')
myd = img[ii+1] -img[0]
# 生成差分矩阵
THRESHOLD = int(np.median(abs(myd))) # 取中位数做为阈值
mymove = np.ones([h,w],np.uint8)
for i in range(h):
for j in range(w):
if abs(myd[i,j]) < THRESHOLD or myd[i,j]==0:
mymove[i,j]=0
# 如果有物体运动
if np.sum(mymove)>0:
print(u"第"+str(ii+2)+u"个运动图像发生了变化 ")
moveimg = colorimg[ii+1]*0.16 + colorimg[ii] * 0.16 + moveimg
moveimg = np.array(moveimg, np.uint8)
# 显示移动部分
showimg = moveimg
cv2.imshow("move", showimg)
cv2.waitKey()
cv2.destroyAllWindows()
## 光流法
光流的概念是Gibson在1950年首先提出来的。它是空间运动物体在观察成像平面上的像素运动的瞬时速度,是利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应关系,从而计算出相邻帧之间物体的运动信息的一种方法。一般而言,光流是由于场景中前景目标本身的移动、相机的运动,或者两者的共同运动所产生的。其计算方法可以分为三类:
(1)基于区域或者基于特征的匹配方法;
(2)基于频域的方法;
(3)基于梯度的方法;
简单来说,光流是空间运动物体在观测成像平面上的像素运动的“瞬时速度”。光流的研究是利用图像序列中的像素强度数据的时域变化和相关性来确定各自像素位置的“运动”。研究光流场的目的就是为了从图片序列中近似得到不能直接得到的运动场。
光流法的前提假设:
(1)相邻帧之间的亮度恒定;
(2)相邻视频帧的取帧时间连续,或者,相邻帧之间物体的运动比较“微小”;
(3)保持空间一致性;即,同一子图像的像素点具有相同的运动
这里有两个概念需要解释:
运动场,其实就是物体在三维真实世界中的运动;
光流场,是运动场在二维图像平面上的投影。
示例代码:
# -*- coding: utf-8 -*-
import cv2
from numpy import *
def draw_flow(im,flow,step=16):
h,w = im.shape[:2]
y,x = mgrid[step/2:h:step,step/2:w:step].reshape(2,-1)
fx,fy = flow[y,x].T
# create line endpoints
lines = vstack([x,y,x+fx,y+fy]).T.reshape(-1,2,2)
lines = int32(lines)
# create image and draw
vis = cv2.cvtColor(im,cv2.COLOR_GRAY2BGR)
for (x1,y1),(x2,y2) in lines:
cv2.line(vis,(x1,y1),(x2,y2),(0,255,0),1)
cv2.circle(vis,(x1,y1),1,(0,255,0), -1)
return vis
# 设置需要采集视频的设备ID为0,从第0个摄像头采集
cap = cv2.VideoCapture(0)
# 前一个图像
ret,im = cap.read()
prev_gray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
while True:
# get grayscale image
ret, im = cap.read()
gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# compute flow
# flow = cv2.calcOpticalFlowFarneback(prev_gray,gray,None,0.5,3,15,3,5,1.2,0)
flow = cv2.calcOpticalFlowFarneback(prev_gray, gray, float(0), float(0), 3, 15, 3, 5, float(1), 0)
prev_gray = gray
# plot the flow vectors
cv2.imshow('Optical flow', draw_flow(gray, flow))
if cv2.waitKey(10) == 32:
break
代码在python3下未执行成功。
参考:
http://blog.csdn.net/carson2005/article/details/7581642
https://baike.baidu.com/item/%E5%85%89%E6%B5%81%E6%B3%95/180688?fr=aladdin
http://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_video/py_lucas_kanade/py_lucas_kanade.html