一、背景建模
1、帧差法(了解一下就可以,一般不用)
2、混合高斯模型
一般新建的高斯分布不超过5个,即3~5个。高斯模型的参数有个学习的过程。
识别视屏流中运动的人代码实现:
import numpy as np
import cv2
cap=cv2.VideoCapture('test.avi')
#形态学操作需要使用
kernel=cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(3,3)) #MORPH_ELLIPSE为椭圆
#创建混合高斯模型用于背景建模
fgbg=cv2.createBackgroundSubtractorMOG2()
while(True):
ret, frame=cap.read()
fgmask=fgbg.apply(frame)
#形态学开运算去噪点
fgmask=cv2.morphologyEx(fgmask,cv2.MORPH_OPEN,kernel)
#寻找视屏中的轮廓
im,contours,hierarchy=cv2.findContours(fgmask,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#因为行人有差不多的身高,所以用周长来确定行人
for c in contours:
#j计算轮廓的周长
perimeter=cv2.arcLength(c,True)
if perimeter > 190:
#找到一个直矩形
x,y,w,h=cv2.boundingRect(c)
#画出这个矩形
cv2.rectangle(frame,(x,y),(x+w,y+h),(0,0,255),2)
cv2.imshow('frame',frame)
cv2.imshow('fgmask',fgmask)
k=cv2.waitKey(100) &0xff
if k==27:
break
cap.release()
cv2.destroyAllWindows()
二、光流估计
光流估计即目标跟踪。光流估计要满足下面三个条件:
根据上面三个关系式列矩阵方程,过程如下
把A的转置与A相乘再取逆,把这个矩阵对角化为特征值x1,x2,当两个特征值都很大时,矩阵才可逆,即为角点时矩阵才可逆。图片中80%以上的像素点都是不可逆的,只有角点才可逆。所以在做光流估计时,输入要是角点。
算法实现:Lucas-Kanade 算法
调用OpenCV中的函数cv2.calcOpticalFlowPyrLK():
参数:
- prevImage 前一帧图像
- nextImage 当前帧图像
- prevPts 待跟踪的特征点向量
- winSize 搜索窗口的大小
- maxLevel 最大的金字塔层数
返回:
- nextPts 输出跟踪特征点向量
- status 特征点是否找到,找到的状态为1,未找到的状态为0
import cv2
import numpy as np
cap=cv2.VideoCapture('test.avi')
#角点检测所需参数
feature_params=dict(
maxCorners=100, #最大角点数
qualityLevel = 0.3,#角点最低质量
minDistance=7)#角点间最小欧氏距离
#lincas_canada参数
lk_params=dict(
winSize=(15,15), #搜索串口大小
maxLevel=2) #最大的金字塔层数
#随机颜色条
color=np.random.randint=(0,255,(100,3))
#那到第一帧图像
ret,old_frame=cap.read()
old_gray=cv2.cvtColor(old_frame,cv2.COLOR_BGR2GRAY)
# 返回所有检测特征点,需要输入图像,角点最大数量(效率),品质因子(特征值越大的越好,来筛选)
# 距离相当于这区间有比这个角点强的,就不要这个弱的了
p0 = cv2.goodFeaturesToTrack(old_gray, mask = None, **feature_params)
#创建一个mask
mask=np.zeros_like(old_frame)
while(True):
ret,frame=cap.read()
frame_gray=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
# 需要传入前一帧和当前图像以及前一帧检测到的角点
p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)
#st=1表示找到特征点
good_news=p1[st==1]
good_old=p0[st==1]
#绘制轨迹
for i,(new,old) in enumerate(zip(good_news,good_old)):
a,b=new.ravel() #变成一维
c,d=old.ravel()
mask = cv2.line(mask, (a, b), (c, d), (0,0,255), 2)
frame = cv2.circle(frame, (a, b), 5, (0,0,255), -1)
img=cv2.add(frame,mask)
cv2.imshow('img',img)
k=cv2.waitKey(150) & 0xff
if k==27:
break
#更新
old_gray=frame_gray.copy()
p0=good_news.reshape(-1,1,2)
cap.release()
cv2.destroyAllWindows()
轨迹图如下面所示,可以跟踪物体的运动轨迹
不能实现的地方:因为是以第一帧图像为原始图像,所以后来进来的人都没办法跟踪,而且只要前面的人经过障碍物之后,也没办法跟踪了。