回到首页 返回首页
回到顶部 回到顶部
返回上一页 返回上一页

基于行空板的opencv lk_track目标追踪 简单

头像 auroraAA 2024.05.14 71 0

一、实践目标

本项目在行空板上外接USB摄像头,通过摄像头来检测目标,并进行跟踪。

 

二、知识目标

学习使用opencv的Lucas-Kanade tracker方法来检测目标并进行跟踪的方法。

 

三、实践准备

硬件清单:

截屏2024-05-14 上午10.45.58.png

 

软件使用:

Mind+编程软件x1

 

四、实践过程

1、硬件搭建

1、将摄像头接入行空板的USB接口。

image.png

 

2、通过USB连接线将行空板连接到计算机。

image.png

 

2、软件编写

第一步:打开Mind+,远程连接行空板

image.png

 

第二步:在“行空板的文件”中新建一个名为AI的文件夹,在其中再新建一个名为“基于行空板的opencv lk_track目标追踪”的文件夹,导入本节课的依赖文件。

image.png

 

第三步:编写程序

在上述文件的同级目录下新建一个项目文件,并命名为“main.py”。

 

示例程序:

代码
#!/usr/bin/env python
'''
Lucas-Kanade tracker
====================

Lucas-Kanade sparse optical flow demo. Uses goodFeaturesToTrack
for track initialization and back-tracking for match verification
between frames.

Usage
-----
lk_track.py [<video_source>]


Keys
----
ESC - exit
'''

# Python 2/3 compatibility
from __future__ import print_function

# 导入所需库
import numpy as np
import cv2 as cv

# 导入其他模块
import video
from common import anorm2, draw_str

# 设置Lucas-Kanade光流跟踪参数
lk_params = dict( winSize  = (15, 15),
                  maxLevel = 2,
                  criteria = (cv.TERM_CRITERIA_EPS | cv.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
        # 创建全屏窗口
        cv.namedWindow('lk_track',cv.WND_PROP_FULLSCREEN)
        cv.setWindowProperty('lk_track', cv.WND_PROP_FULLSCREEN, cv.WINDOW_FULLSCREEN)

    def run(self):
        while True:
            # 读取一帧图像
            _ret, frame = self.cam.read()
            # 转为灰度图像
            frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
            vis = frame.copy()

            # 如果有跟踪点
            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)
                # 计算光流
                p1, _st, _err = cv.calcOpticalFlowPyrLK(img0, img1, p0, None, **lk_params)
                # 反向计算光流
                p0r, _st, _err = cv.calcOpticalFlowPyrLK(img1, img0, p1, None, **lk_params)
                # 计算反向光流误差
                d = abs(p0-p0r).reshape(-1, 2).max(-1)
                # 筛选出误差小于1的跟踪点
                good = d < 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)
                    # 在图像上绘制跟踪点
                    cv.circle(vis, (int(x), int(y)), 2, (0, 255, 0), -1)
                # 更新跟踪路径
                self.tracks = new_tracks
                # 在图像上绘制跟踪路径
                cv.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:
                # 创建掩码
                mask = np.zeros_like(frame_gray)
                mask[:] = 255
                # 对已有跟踪点周围区域进行掩蔽
                for x, y in [np.int32(tr[-1]) for tr in self.tracks]:
                    cv.circle(mask, (x, y), 5, 0, -1)
                # 检测新的特征点
                p = cv.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
            # 显示图像
            cv.imshow('lk_track', vis)

            # 按下ESC键退出
            ch = cv.waitKey(1)
            if ch == 27:
                break

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

    # 运行程序
    App(video_src).run()
    print('Done')


if __name__ == '__main__':
    print(__doc__)
    main()
    # 关闭所有窗口
    cv.destroyAllWindows()

 

3、运行调试

第一步:运行主程序

运行“main.py”程序,可以看到初始时屏幕上显示着摄像头拍摄到的实时画面,将小车放入画面中,小车随即被检测出并用绿色光点标记,轻轻移动小车,可以看到绿色的光点随着小车而移动,并留下了移动的轨迹,实现了目标追踪的效果。

image.png

 

4、程序解析

在上述的“main.py”文件中,我们主要通过opencv库来调用摄像头,获取实时视频流,在视频的每一帧中检测特征点,然后使用光流法对这些特征点进行跟踪,并将跟踪的结果显示出来。特征点的检测和跟踪是在一个无限循环中进行的,直到用户选择退出程序。整体流程如下,

① 视频源获取和处理:程序首先打开指定的视频源,可以是摄像头或者视频文件。然后以帧为单位读取视频,并对每一帧进行处理。

② 特征点检测和跟踪:对于每一帧,程序首先检查是否需要进行特征点检测。如果需要,就在当前帧中检测新的特征点,并将这些点添加到跟踪点列表中。然后,无论是否检测了新的特征点,程序都会对列表中已有的跟踪点进行跟踪。跟踪的过程是使用Lucas-Kanade光流法计算这些点在当前帧和前一帧之间的运动,得到这些点在当前帧中的位置。

③ 结果验证和显示:跟踪完成后,程序会使用反向光流进行一次验证,确保跟踪的准确性。然后在原视频帧的副本上绘制跟踪点的位置,并将结果显示在全屏窗口中。

④ 用户交互:程序会检查用户是否按下了ESC键,如果按下,则退出主循环,并结束程序。

 

五、知识园地

1. 了解opencv的Lucas-Kanade光流法

Lucas-Kanade(LK)光流法是一种用于估计图像序列中物体运动的经典算法。它由Bruce D. Lucas和Takeo Kanade在1981年的论文"An Iterative Image Registration Technique with an Application to Stereo Vision"中提出。

LK光流法的主要思想是在小的邻域内,所有像素的运动速度都是相同的。这个假设使得我们可以在邻域内建立一个线性系统,然后通过求解这个线性系统来得到像素的运动速度。

 

LK光流法的基本步骤如下:

选择特征点:在第一帧图像中选择一些特征点。这些特征点通常是角点,因为角点具有丰富的纹理信息,适合用于跟踪。

建立线性系统:对于每个特征点,选择一个小的邻域(例如5x5或7x7的窗口),然后在这个邻域内建立一个线性系统。这个线性系统由以下公式给出:

I_x * u + I_y * v = -I_t

其中,I_x和I_y分别是图像在x和y方向上的梯度,I_t是图像在时间方向上的梯度,u和v是像素在x和y方向上的运动速度。

求解线性系统:由于线性系统是过定的(即未知数的数量少于方程的数量),我们无法直接求解。因此,我们需要使用最小二乘法来求解这个线性系统,得到像素的近似运动速度。

迭代优化:由于LK光流法假设像素的运动速度在邻域内是恒定的,这个假设在实际情况中可能并不成立。因此,我们需要通过迭代优化来改进运动速度的估计。具体来说,我们可以将当前帧的特征点按照估计的运动速度进行移动,然后在新的位置重复上述步骤,直到运动速度收敛。

通过以上步骤,LK光流法可以估计出图像序列中物体的运动。在计算机视觉中,LK光流法被广泛用于各种任务,如视频压缩、视频稳定、运动跟踪等。

 

 

2. 了解opencv的goodFeaturesToTrack特征点检测

goodFeaturesToTrack是OpenCV中的一个函数,用于在图像中检测角点。它基于一种叫做Shi-Tomasi角点检测方法,这种方法是Harris角点检测方法的改进版。

角点是图像中的一种特征,具有在所有方向上变化的强度变化。在视觉任务中,角点因具有丰富的纹理信息,常被用作特征点。

goodFeaturesToTrack函数的工作原理如下:

计算图像的每个像素点的最小特征值(也就是Shi-Tomasi得分)。

对所有像素点的得分进行排序,并选取最高的几个。

为了保证选取的角点分布均匀,函数会根据设定的最小距离参数,剔除过于接近的角点。

 

函数的主要参数如下:

· maxCorners:要检测的角点数量的最大值。如果实际检测到的角点数量超过这个值,函数会只返回得分最高的角点。

· qualityLevel:角点质量水平的阈值。这个参数用于剔除得分低于最高得分乘以此阈值的角点。

· minDistance:可接受的最小角点间距。

通过这个函数,我们可以在图像中快速地找到一些具有代表性的特征点,用于后续的图像处理任务,如特征匹配、光流跟踪等。

评论

user-avatar