• 机器学习进阶-光流估计 1.cv2.goodFeaturesToTrack(找出光流估计所需要的角点) 2.cv2.calcOpticalFlowPyrLK(获得光流检测后的角点位置) 3.cv2.add(进行像素点的加和)


    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()

  • 相关阅读:
    网络流
    KMP算法
    光现象
    物理学习须知
    声现象
    常见物理量测量方法
    洛谷 P1373 小a和uim之大逃离
    洛谷 P1242 新汉诺塔
    电磁现象
    磁化
  • 原文地址:https://www.cnblogs.com/my-love-is-python/p/10447917.html
Copyright © 2020-2023  润新知