机器视觉OpenCV—python⽬标跟踪(光流)
⽂章⽬录
⼀、运动检测
1.1 检测思路
⽬标跟踪是对摄像头视频中的移动⽬标进⾏定位的过程。实时⽬标跟踪是许多计算机视觉应⽤的重要任务,如监控、基于感知的⽤户界⾯、增强现实、基于对象的视频压缩以及辅助驾驶等。
好久之前做过⼀次⼈脸检测,⾥⾯涉及到了⽬标跟踪。
这次实现⼀般的运动物体检测,关于实现视频⽬标跟踪的⽅法有很多,当跟踪所有移动⽬标时,帧之间的差异会变的有⽤;当跟踪视频中移动的⼿时,基于⽪肤颜⾊的均值漂移⽅法是最好的解决⽅案;当知道跟踪对象的⼀⽅⾯时,模板匹配是不错的技术。
常⽤的⽬标跟踪⽅法有:
背景法(本次⽤的⽅法)是:将⼀幅图作为背景,让后和每⼀帧对⽐;缺点是⼀开始存⼊的背景可能随光照变法⽽造成错误,但是可以⽤在光照环境稳定的地⽅,优点是可以检测之前背景没有的景象;
差帧法是:将前⼀帧和后⼀帧进⾏对⽐;缺点是⽆法对运动后突然⼜静⽌的景象进⾏识别,优点是光照不影响;
1.2 代码
import cv2
import numpy as np
camera = cv2.VideoCapture(0)# 参数0表⽰第⼀个摄像头
if(camera.isOpened()):# 判断视频是否打开
print('Open')
else:
print('摄像头未打开')
#测试⽤,查看视频size
size =((cv2.CAP_PROP_FRAME_WIDTH)),
(cv2.CAP_PROP_FRAME_HEIGHT)))
print('size:'+repr(size))
# 构建椭圆结果
es = StructuringElement(cv2.MORPH_ELLIPSE,(9,4))
kernel = np.ones((5,5), np.uint8)
background =None
while True:
# 读取视频流
grabbed, frame_lwpCV = ad()
# 对帧进⾏预处理,>>转灰度图>>⾼斯滤波(降噪:摄像头震动、光照变化)。
gray_lwpCV = cv2.cvtColor(frame_lwpCV, cv2.COLOR_BGR2GRAY)
gray_lwpCV = cv2.GaussianBlur(gray_lwpCV,(21,21),0)
# 将第⼀帧设置为整个输⼊的背景
if background is None:
background = gray_lwpCV
continue
# 对⽐背景之后的帧与背景之间的差异,并得到⼀个差分图(different map)。
# 阈值(⼆值化处理)>>膨胀(dilate)得到图像区域块
diff = cv2.absdiff(background, gray_lwpCV)
diff = cv2.threshold(diff,25,255, cv2.THRESH_BINARY)[1]
diff = cv2.dilate(diff, es, iterations=2)
# 显⽰矩形框:计算⼀幅图像中⽬标的轮廓
image, contours, hierarchy = cv2.py(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for c in contours:
urArea(c)<1500:# 对于矩形区域,只显⽰⼤于给定阈值的轮廓(去除微⼩的变化等噪点)
continue
(x, y, w, h)= cv2.boundingRect(c)# 该函数计算矩形的边界框
cv2.imshow('contours', frame_lwpCV)
cv2.imshow('dis', diff)
key = cv2.waitKey(1)&0xFF
if key ==ord('q'):# 按'q'健退出循环
break
# 释放资源并关闭窗⼝
cv2.destroyAllWindows()
⼆、运动⽅向预测
2.1 关键点(⾓点)追踪 goodFeaturesToTrack()
maxCorners , #⾓点数⽬最⼤值,若检测的⾓点超过此值,则只返回前maxCorners 个强⾓点
qualityLevel , #⾓点的品质因⼦
minDistance , #如果在其周围minDistance 范围内存在其他更强⾓点,则将此⾓点删除
corners #存储所有⾓点
mask , #指定感兴趣区,若⽆指定,寻全图
blockSize , #计算协⽅差矩阵时的窗⼝⼤⼩
useHarrisDetector , #bool 是否使⽤Harris ⾓点检测,如不指定,则计算shi-tomasi ⾓点
k ) #Harris ⾓点检测需要的k 值
2.2 光流法
光流法的⼯作原理基于如下假设:
1. 连续的两帧图像之间,⽬标像素亮度不变。
2. 相邻的像素之间有相似的运动。
考虑第⼀帧的像素 ,表⽰在时间t时像素 的值。在经过时间 后,此像素在下⼀帧移动了 。因为这些像素是相同的,⽽且亮度不变,表⽰成,。
假设移动很⼩,使⽤泰勒公式可以表⽰成:
H.O.T是⾼阶⽆穷⼩。由第⼀个假设和使⽤泰勒公式展开的式⼦可以得到:
设: 同理得 和 令 ; 光流⽅程: 其中 和 分别是图像的梯度, 是是图像沿着时间的梯度。但是 和 是未知的,我们没办法⽤⼀个⽅程解两个未知数,那么就有了lucas-kanade这个⽅法来解决这个问题。光
流是进⾏视频中运动对象轨迹标记的⼀种很常⽤的⽅法,在OpenCV中实现光流也很容易。
cv2.calcOpticalFlowPyrLK 函数计算⼀个稀疏特征集的光流,使⽤⾦字塔中的迭代 Lucas-Kanade ⽅法。
nextPts ,status ,err = cv2.calcOpticalFlowPyrLK (prevImg , #上⼀帧图⽚
nextImg , #当前帧图⽚
prevPts , #上⼀帧到的特征点向量
nextPts #与返回值中的nextPtrs 相同
[, status [, err [, winSize
[, maxLevel [, criteria
[, flags [, minEigThreshold ]]]]]]])返回值:
nextPtrs 输出⼀个⼆维点的向量,这个向量可以是⽤来作为光流算法的输⼊特征点,也是光流算法在当前帧到特征点的新位置(浮点数)status 标志,在当前帧当中发现的特征点标志status==1,否则
为0
err 向量中的每个特征对应的错误率
其他输⼊值:
I (x ,y ,t )I (x ,y )d t (d ,d )x y I (x ,y ,t )=I (x +d ,y +x d ,t +y d )t I (x +Δx ,y +Δy ,t +Δt )=I (x ,y ,t )+Δx +∂x ∂I Δy +∂y ∂I Δt +∂t ∂I
H .O .T
Δx +∂x ∂I Δy +∂y ∂I Δt =∂t ∂I 0 改写成: +∂x ∂I Δt Δx +∂y ∂I Δt Δy =∂t ∂I Δt Δt
=∂x ∂I f x =∂y ∂I f y =∂t ∂I
f t
=Δt Δx u =Δt Δy v
f u +x f v +y f =t 0f x f y f t u v
status 与返回的status相同
err 与返回的err相同
winSize 在计算局部连续运动的窗⼝尺⼨(在图像⾦字塔中)
maxLevel 图像⾦字塔层数,0表⽰不使⽤⾦字塔
criteria 寻光流迭代终⽌的条件
flags 有两个宏,表⽰两种计算⽅法,
OPTFLOW_USE_INITIAL_FLOW表⽰使⽤估计值作为寻到的初始光流,
OPTFLOW_LK_GET_MIN_EIGENVALS表⽰使⽤最⼩特征值作为误差测量
minEigThreshold 该算法计算光流⽅程的2×2规范化矩阵的最⼩特征值,除以窗⼝中的像素数; 如果此值⼩于minEigThreshold,则会过滤掉相应的功能并且不会处理该光流,因此它允许删除坏点并获得性能提升。
实现原理:
⾸先选取第⼀帧,在第⼀帧图像中检测Shi-Tomasi⾓点,
然后使⽤LK算法来迭代的跟踪这些特征点。迭代的⽅式就是不断向cv2.calcOpticalFlowPyrLK()中传⼊上⼀帧图⽚的特征点以及当前帧的图⽚。
函数会返回当前帧的点,这些点带有状态1或者0,如果在当前帧到了上⼀帧中的点,那么这个点的状态就是1,否则就是0。
实现流程:
1. 加载视频。
2. 调⽤ GoodFeaturesToTrack 函数寻兴趣点(关键点)。
3. 调⽤ CalcOpticalFlowPyrLK 函数计算出两帧图像中兴趣点的移动情况。
4. 删除未移动的兴趣点。
5. 在两次移动的点之间绘制⼀条线段。
import numpy as np
import cv2
cap = cv2.VideoCapture('./IMG_1521.mp4')
# ShiTomasi corner detection的参数
feature_params =dict(maxCorners=100,
qualityLevel=0.3,
minDistance=7,rectangle函数opencv
blockSize=7)
# 光流法参数
# maxLevel 未使⽤的图像⾦字塔层数
lk_params =dict(winSize=(15,15),
maxLevel=2,
criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT,10,0.03)) # 创建随机⽣成的颜⾊
color = np.random.randint(0,255,(100,3))
ret, old_frame = ad()# 取出视频的第⼀帧
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)# 灰度化
p0 = dFeaturesToTrack(old_gray, mask=None,**feature_params)
mask = np.zeros_like(old_frame)# 为绘制创建掩码图⽚
while True:
_, frame = ad()
frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 计算光流以获取点的新位置
p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0,None,**lk_params)
# 选择good points
good_new = p1[st ==1]
good_old = p0[st ==1]
# 绘制跟踪框
for i,(new, old)in enumerate(zip(good_new, good_old)):
a, b = new.ravel()
c, d = old.ravel()
mask = cv2.line(mask,(a, b),(c, d), color[i].tolist(),2)
frame = cv2.circle(frame,(a, b),5, color[i].tolist(),-1)
img = cv2.add(frame, mask)
cv2.imshow('frame', img)
k = cv2.waitKey(30)# & 0xff
if k ==27:
break
old_gray = py()
p0 = shape(-1,1,2)
cv2.destroyAllWindows()
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论