1.cv2.goodFeaturesToTrack(old_gray, mask=None, **feature_params)  用于获得光流估计所需要的角点
参数说明:old_gray表示输入图片,mask表示掩模,feature_params:maxCorners=100角点的最大个数,qualityLevel=0.3角点品质,minDistance=7即在这个范围内只存在一个品质最好的角点
2. pl, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)  用于获得光流检测后的角点位置

参数说明:pl表示光流检测后的角点位置,st表示是否是运动的角点,err表示是否出错,old_gray表示输入前一帧图片,frame_gray表示后一帧图片,p0表示需要检测的角点,lk_params:winSize表示选择多少个点进行u和v的求解,maxLevel表示空间金字塔的层数

3. cv2.add(frame, mask) # 将两个图像的像素进行加和操作

参数说明:frame表示输入图片,mask表示掩模

光流估计:通过当前时刻与前一时刻的亮度不变的特性I(x, y, t) = I(x+∆x, y+∆y, t+∆t) 使用lucas-kanade算法进行求解问题, 我们需要求得的是x,y方向的速度

下面是lucas-kanade的推导公式, 即位置发生变动时,其像素点的大小没有发生变化, 

I(x, y, t) = I(x+dx, y+dy, t+dt)  

             = I(x, y, t) + Ixdx + Iydy + Itdt 使用泰勒基数进行展开
       对上式进行化解即: 

                               Ixdx + Iydy + Itdt = 0  Ix表示x轴的梯度方向,Iy表示y轴的梯度方向,It表示单位时间上的像素点的变化
                               如果我们使用前后两帧的变化, 那么dx和dy也就是表示x轴和y轴的速度,返回的结果是dx和dy,即在x轴和y轴方向上移动的步数,我们就可以知道目标的位置了

下面是实际求解u和v的过程,根据上述的空间一致性,我们选择出关键点周围的25个点进行求解,即(5, 5)的方框, 构造Au = b 进行求解,我们可以看出(A^T*A)^-1

但是当前像素点不一定可逆,如果保证可逆呢,即A^T*A的特征值λ1和λ2接近相等且较大,符合条件的就是角点, 因此使用角点去求解u和v

代码:

第一步:使用cv2.capture读入视频

第二步:构造角点检测所需参数, 构造lucas kanade参数

第三步:拿到第一帧图像,并做灰度化, 作为光流检测的前一帧图像

第四步:使用cv2.goodFeaturesToTrack获得光流检测所需要的角点

第五步:构造一个mask用于画直线

第六步:读取一张图片,进行灰度化,作为光流检测的后一帧图像

第七步:使用cv2.caclOpticalFlowPyrLK进行光流检测

第八步:使用st==1获得运动后的角点,原始的角点位置

第九步:循环获得角点的位置,在mask图上画line,在后一帧图像上画角点

第十步:使用cv2.add()将mask和frame的像素点相加并进行展示

第十一步:使用后一帧的图像更新前一帧的图像,同时使用运动的后一帧的角点位置来代替光流检测需要的角点

import numpy as np
import cv2


# 第一步:视频的读入
cap = cv2.VideoCapture('test.avi')

# 第二步:构建角点检测所需参数
feature_params = dict(maxCorners=100,
                      qualityLevel=0.3,
                      minDistance=7)

# lucas kanade参数
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)
# 第四步:返回所有检测特征点,需要输入图片,角点的最大数量,品质因子,minDistance=7如果这个角点里有比这个强的就不要这个弱的
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)

    # 第七步:进行光流检测需要输入前一帧和当前图像及前一帧检测到的角点
    pl, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)

    # 第八步:读取运动了的角点st == 1表示检测到的运动物体,即v和u表示为0
    good_new = pl[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(150) & 0xff
    if k == 27:
        break

    # 第十一步:更新前一帧图片和角点的位置
    old_gray = frame_gray.copy()
    p0 = good_new.reshape(-1, 1, 2)
    # p0 = cv2.goodFeaturesToTrack(old_gray, mask=None, **feature_params)

cv2.destroyAllWindows()
cap.release()

 

posted on 2019-02-28 00:07  python我的最爱  阅读(7223)  评论(0编辑  收藏  举报