python光流算法学习

本文介绍了一个基于Python和OpenCV的光流算法实现案例,详细解释了如何使用角点检测和光流跟踪技术来追踪视频中的运动物体,并展示了具体的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

某次随便写代码时遇到了光流算法,就简单的看了看代码,对它有了一点点了解,记录一下。

其实代码在python opencv里的例子里就有,路径为:
D:\Program Files\opencv\sources\samples\python2\lk_track.py

网上很多这方面的资料,不过没有给出详细的注释,于是我自己看了看代码,把一些看懂的地方再加上注释,不对的地方望指教。

import numpy as np
import cv2
from common import anorm2, draw_str
from time import clock

#光流检测的参数
lk_params = dict( winSize  = (15, 15),#搜索窗口的大小
                  maxLevel = 2,#最大的金字塔层数
                  # 指定停止条件,具体没懂
                  criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))

#角点检测的参数
feature_params = dict( maxCorners = 500,#最大角点数
                       qualityLevel = 0.3,#角点最低质量
                       minDistance = 7,#角点间最小欧式距离
                       blockSize = 7 )#这个没懂,我做角点检测时只设置了上面几个参数,望指教

class App:
    def __init__(self, video_src):
        self.track_len = 10
        self.detect_interval = 5
        self.tracks = []
        self.cam = video.create_capture(video_src)
        self.frame_idx = 0

    def run(self):
        while True:
            ret, frame = self.cam.read()#通过摄像头获取一张图片
            frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)#转化为灰度图
            vis = frame.copy()#赋值frame的值,不覆盖frame本身

            if len(self.tracks) > 0:#检测到角点后进行光流跟踪 
                img0, img1 = self.prev_gray, frame_gray
                p0 = np.float32([tr[-1] for tr in self.tracks]).reshape(-1, 1, 2)#对np数组进行重塑
                #前一帧的角点和当前帧的图像作为输入来得到角点在当前帧的位置,有点绕,具体实现有兴趣就去看源码吧
                p1, st, err = cv2.calcOpticalFlowPyrLK(img0, img1, p0, None, **lk_params)
                #当前帧跟踪到的角点及图像和前一帧的图像作为输入来找到前一帧的角点位置  
                p0r, st, err = cv2.calcOpticalFlowPyrLK(img1, img0, p1, None, **lk_params) 
                d = abs(p0-p0r).reshape(-1, 2).max(-1)#得到角点回溯与前一帧实际角点的位置变化关系
                good = d < 1#判断d内的值是否小于1,大于1跟踪被认为是错误的跟踪点,为什么是1不知道
                new_tracks = []
                #将跟踪正确的点列入成功跟踪点
                for tr, (x, y), good_flag in zip(self.tracks, p1.reshape(-1, 2), good):
                    if not good_flag:
                        continue
                    tr.append((x, y))
                    if len(tr) > self.track_len:
                        del tr[0]
                    new_tracks.append(tr)
                    cv2.circle(vis, (x, y), 2, (0, 255, 0), -1)#画圆
                self.tracks = new_tracks

                #以上一振角点为初始点,当前帧跟踪到的点为终点划线
                cv2.polylines(vis, [np.int32(tr) for tr in self.tracks], False, (0, 255, 0))

                draw_str(vis, (20, 20), 'track count: %d' % len(self.tracks))

            if self.frame_idx % self.detect_interval == 0:#每5帧检测一次特征点
                mask = np.zeros_like(frame_gray)#初始化和视频大小相同的图像
                mask[:] = 255#将mask赋值255也就是算全部图像的角点
                for x, y in [np.int32(tr[-1]) for tr in self.tracks]:#跟踪的角点画圆
                    cv2.circle(mask, (x, y), 5, 0, -1)
                p = cv2.goodFeaturesToTrack(frame_gray, mask = mask, **feature_params)#角点检测
                if p is not None:
                    for x, y in np.float32(p).reshape(-1, 2):
                        self.tracks.append([(x, y)])#将检测到的角点放在待跟踪序列中


            self.frame_idx += 1
            self.prev_gray = frame_gray
            cv2.imshow('lk_track', vis)

            ch = 0xFF & cv2.waitKey(1)#按esc退出
            if ch == 27:
                break

def main():
    import sys
    try: video_src = sys.argv[1]
    except: video_src = 0

    print __doc__
    App(video_src).run()
    cv2.destroyAllWindows()

if __name__ == '__main__':
    main()

其实有很多地方都还没弄明白,等以后需要用到在去仔细了解了,以上内容参考http://blog.youkuaiyun.com/gjy095/article/details/9226883(应该不算抄袭吧,如果有,提醒我删帖)。

之后我在具体应用中,作了一些修改,发现源代码中有一些地方可有可无,实在没明白这么写的意义,总之贴出我修改后的代码做参考,有明白的人麻烦指点一下。

from PIL import ImageGrab
import numpy as np
import cv2
import time


lk_params = dict( winSize  = (15, 15),
                  maxLevel = 2,
                  criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))

track_len = 10
detect_interval = 5
tracks = []
frame_idx = 0
#time.sleep(10)
while(True):
    #bbox specifies specific region (bbox= x,y,width,height *starts top-left)
    #把原来的调用摄像头改成屏幕截图了,其实这样子看不出光流的效果,只是我的具体应用里有需求
    img = ImageGrab.grab(bbox=(600,300,800,500))

    #this is the array obtained from conversion
    img_np = np.array(img)#转化为np数组
    frame_gray = cv2.cvtColor(img_np, cv2.COLOR_BGR2GRAY) 
    vis = img_np.copy()


    # 原来的goodfeature改成了fastfeature,为了提高效率
    fast = cv2.FastFeatureDetector()

    value_x=[]
    if len(tracks) > 0:#检测到角点后进行光流跟踪 
        img0, img1 = prev_gray, frame_gray

        p0 = np.float32([tr[-1] for tr in tracks]).reshape(-1, 1, 2)

        #自己写的一段角点筛选代码,具体意义忘了
        for i in range(0,len(p0)):
            temp=10
            for j in range(i+1,len(p0)):              
                distance_x=abs(p0[i][0][0]-p0[j][0][0])
                if distance_x<temp:
                    temp=distance_x
            if temp==10:
                value_x.append(p0[i])


        new_value_x=np.float32([tr[-1] for tr in value_x]).reshape(-1, 1, 2)
        new_p1, st, err = cv2.calcOpticalFlowPyrLK(img0, img1, new_value_x, None, **lk_params)
        new_p0r, st, err = cv2.calcOpticalFlowPyrLK(img1, img0, new_p1, None, **lk_params)
        new_d = abs(new_value_x-new_p0r).reshape(-1, 2).max(-1)#得到角点回溯与前一帧实际角点的位置变化关系
        mean=np.mean(new_d)

        p1, st, err = cv2.calcOpticalFlowPyrLK(img0, img1, p0, None, **lk_params)
        p0r, st, err = cv2.calcOpticalFlowPyrLK(img1, img0, p1, None, **lk_params)

        d = abs(p0-p0r).reshape(-1, 2).max(-1)#得到角点回溯与前一帧实际角点的位置变化关系

        good = d <=0.5* mean#判断d内的值是否小于1,大于1跟踪被认为是错误的跟踪点

        new_tracks = []

        for tr, (x, y), good_flag in zip(tracks, p1.reshape(-1, 2), good):#将跟踪正确的点列入成功跟踪点
            if not good_flag:
                continue
            tr.append((x, y))
            if len(tr) > track_len:
                del tr[0]
            new_tracks.append(tr)
            cv2.circle(vis, (x, y), 2, (0, 255, 0), -1)
        tracks = new_tracks
        #cv2.polylines(vis, [np.int32(tr) for tr in tracks], False, (0, 255, 0))

    if frame_idx % detect_interval == 0:#每5帧检测一次特征点
        p = fast.detect(frame_gray,  None)# fast角点检测
        lenght_p=len(p)
        if p is not None:
            for i in range(0,lenght_p):
                tracks.append([ p[i].pt])#将检测到的角点放在待跟踪序列中

    frame_idx += 1
    prev_gray = frame_gray
    cv2.imshow('lk_track', vis)
    ch = 0xFF & cv2.waitKey(1)  
    if ch == 27:  
        break


cv2.destroyAllWindows()

主体没变,改了一些地方,对比一下就可以发现。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lsjweiyi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值