回到首页 返回首页
回到顶部 回到顶部
返回上一页 返回上一页
best-icon

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

头像 auroraAA 2024.06.05 122 0

一、实践目标

 

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

 

二、知识目标

 

1、学习使用opencv库的feature homography方法来检测目标物并进行跟踪的方法。

 

三、实践准备

 

硬件清单:

截屏2024-06-05 上午10.39.11.png

软件使用:Mind+编程软件x1

 

四、实践过程

 

1、硬件搭建

 

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

 

image.png

 

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

 

image.png

 

2、软件编写

 

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

 

image.png

 

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

 

image.png

 

第三步:编写程序

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

示例程序:

代码
#!/usr/bin/env python

'''
Feature homography
==================

Example of using features2d framework for interactive video homography matching.
ORB features and FLANN matcher are used. The actual tracking is implemented by
PlaneTracker class in plane_tracker.py

Inspired by http://www.youtube.com/watch?v=-ZNYoL8rzPY

video: http://www.youtube.com/watch?v=FirtmYcC0Vc

Usage
-----
feature_homography.py [<video source>]

Keys:
   SPACE  -  pause video

Select a textured planar object to track by drawing a box with a mouse.
'''

# Python 2/3 compatibility
from __future__ import print_function

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

# 导入其他模块
import video
from video import presets
import common
from common import getsize, draw_keypoints
from plane_tracker import PlaneTracker

class App:
    def __init__(self, src):
        # 创建视频捕获对象
        self.cap = video.create_capture(src, presets['book'])
        self.frame = None
        self.paused = False
        # 创建平面跟踪器对象
        self.tracker = PlaneTracker()

        # 创建全屏窗口
        cv.namedWindow('plane',cv.WND_PROP_FULLSCREEN)
        cv.setWindowProperty('plane', cv.WND_PROP_FULLSCREEN, cv.WINDOW_FULLSCREEN)

        # 创建矩形选择器对象,用于用户选择待跟踪的平面区域
        self.rect_sel = common.RectSelector('plane', self.on_rect)

    def on_rect(self, rect):
        # 当用户选择了一个矩形区域后的回调函数
        # 清除跟踪器中的所有目标
        self.tracker.clear()
        # 添加新的跟踪目标
        self.tracker.add_target(self.frame, rect)

    def run(self):
        while True:
            # 判断是否需要读取新的视频帧
            playing = not self.paused and not self.rect_sel.dragging
            if playing or self.frame is None:
                # 读取新的视频帧
                ret, frame = self.cap.read()
                if not ret:
                    break
                self.frame = frame.copy()
            # 创建用于显示的图像
            w, h = getsize(self.frame)
            vis = np.zeros((h*2, w, 3), np.uint8)
            vis[:h,:w] = self.frame

            # 如果有跟踪目标,显示目标的特征点和矩形框
            if len(self.tracker.targets) > 0:
                target = self.tracker.targets[0]
                vis[h:,:] = target.image
                draw_keypoints(vis[h:,:], target.keypoints)
                x0, y0, x1, y1 = target.rect
                cv.rectangle(vis, (x0, y0+h), (x1, y1+h), (0, 255, 0), 2)

            if playing:
                # 进行跟踪
                tracked = self.tracker.track(self.frame)
                if len(tracked) > 0:
                    # 绘制跟踪结果
                    tracked = tracked[0]
                    cv.polylines(vis, [np.int32(tracked.quad)], True, (255, 255, 255), 2)
                    for (x0, y0), (x1, y1) in zip(np.int32(tracked.p0), np.int32(tracked.p1)):
                        cv.line(vis, (x0, y0+h), (x1, y1), (0, 255, 0))

            # 绘制所有跟踪点
            draw_keypoints(vis, self.tracker.frame_points)

            # 绘制矩形选择框
            self.rect_sel.draw(vis)
            # 显示图像
            cv.imshow('plane', vis)

            ch = cv.waitKey(1)
            # 按下空格键暂停/播放
            if ch == ord(' '):
                self.paused = not self.paused
            # 按下ESC键退出
            if ch == 27:
                break


if __name__ == '__main__':
    print(__doc__)
    import sys
    try:
        video_src = sys.argv[1]
    except:
        video_src = 0

    # 运行程序
    App(video_src).run()

3. 运行调试

 

第一步:运行主程序

 

运行“main.py”程序,可以看到初始时屏幕分为了上下两个区域,上方显示着摄像头拍摄到的实时画面,下方初始时显示黑色背景,之后将摄像头画面对准一个物体(这里为小车),用鼠标将画面中的物体(小车)框出,可以看到框出的小车作为被标记物显示在了下方,轻轻移动小车,可以看到上方的画面中小车始终被框出,并且与下方之间通过光流保持着连接,达到了追踪的目的。

image.png

 

4、程序解析

 

在上述的“main.py”文件中,我们主要通过opencv库来调用摄像头,获取实时视频流,然后借助计算机视觉中的ORB特征和FLANN匹配器来实现对视频中特定平面的跟踪。用户可以通过鼠标在视频中选择一个区域,然后程序会在之后的视频帧中跟踪这个区域的位置和姿态。整体流程如下,

 

①初始化视频源和跟踪器:程序首先打开视频源,并创建一个PlaneTracker对象用于跟踪。

 

②用户选择跟踪区域:用户通过鼠标在视频中选择一个区域,选择的区域将被添加到PlaneTracker中作为跟踪目标。

 

③跟踪处理:程序会逐帧读取视频,并将每一帧传递给PlaneTracker进行处理。PlaneTracker会使用ORB特征和FLANN匹配器找到当前帧中与目标相匹配的特征,并计算出目标在当前帧中的位置和姿态。

 

④显示结果:程序会将跟踪的结果(包括目标的位置和姿态)实时地显示在视频上。如果跟踪成功,目标区域会被高亮显示。

 

⑤用户交互:用户可以通过按下空格键来暂停或继续视频的播放。如果用户在视频暂停时选择了新的区域,这个区域将会替换原来的跟踪目标。

 

五、知识园地

 

1. 了解ORB特征(Oriented FAST and Rotated BRIEF)

ORB特征,全称为Oriented FAST and Rotated BRIEF,是一种高效的特征检测和描述算法,由Ethan Rublee等人在2011年的论文"ORB: An efficient alternative to SIFT or SURF"中提出。

ORB特征算法主要包含两个部分:特征点检测和特征描述。

1、特征点检测:ORB使用了FAST角点检测器进行特征点的检测。FAST角点检测器是一种高效的角点检测算法,可以快速地在图像中找到角点。然而,FAST角点检测器检测到的角点没有方向信息,为了解决这个问题,ORB算法引入了角点的方向信息,从而得到了带有方向信息的特征点。

2、特征描述:ORB使用了rBRIEF描述子进行特征描述。BRIEF是一种二进制的特征描述符,它通过比较图像中一个小区域内的像素对的亮度,生成一串二进制串作为该区域的描述子。然而,BRIEF描述子不具有旋转不变性,即当图像旋转时,BRIEF描述子会发生变化。ORB通过在BRIEF的基础上引入了旋转不变性,得到了rBRIEF描述子。

ORB特征算法的主要优点是计算速度快,内存占用少,适合于实时应用和嵌入式设备。它的性能与SIFT和SURF等算法相当,但计算速度更快,内存占用更少。

 

2. 了解FLANN匹配器(Fast Library for Approximate Nearest Neighbors)

FLANN(Fast Library for Approximate Nearest Neighbors)是一个用于进行大规模数据集中的快速近邻搜索的库。在很多计算机视觉和机器学习的任务中,我们经常需要在高维空间中找到某个点的最近邻点,这是一个在计算上非常昂贵的任务。FLANN库提供了一种快速和高效的方法来进行这个操作。

FLANN支持多种类型的数据和距离度量,包括欧几里得距离、曼哈顿距离、汉明距离等,并且可以自动选择最适合你数据的算法。它提供了一种称为索引的数据结构,可以将数据预处理成特定的格式,以便在搜索时更快地找到最近邻。

在计算机视觉中,FLANN常常被用来进行特征匹配。比如说,我们在两张图片中分别提取出了一些特征点,然后需要找出在两张图片中对应的特征点。这时候,我们就可以使用FLANN来快速找到每个特征点的最近邻,从而实现特征匹配。

在OpenCV中,FLANN匹配器可以通过cv2.FlannBasedMatcher类来使用。这个类提供了knnMatch和radiusMatch等方法,可以进行k-近邻匹配和半径匹配。

 

3. 了解光流法(Optical Flow)

光流(Optical Flow)是计算机视觉中的一种重要技术,它主要用于从视频序列中估计物体的运动。光流描述的是图像序列中的像素在时间维度上的运动变化,即每个像素点随时间在图像平面上的移动轨迹。

光流的基本假设是图像的亮度在短时间内是恒定不变的,即一个像素点在当前帧和下一帧中的亮度是相同的。另外,光流还假设相邻像素具有相似的运动,即物体的运动是连续的。

光流法通常用于估计视频中物体的速度或者运动方向。例如,在自动驾驶、视频监控、运动检测等领域,光流法都有广泛的应用。

在计算方法上,光流法主要有两类:稀疏光流法和稠密光流法。稀疏光流法只在一些特定的点(例如特征点)上计算光流,而稠密光流法则在每个像素点上都计算光流。

在OpenCV中,有函数cv2.calcOpticalFlowPyrLK和cv2.calcOpticalFlowFarneback等可以用于计算光流。其中,cv2.calcOpticalFlowPyrLK是一种基于Lucas-Kanade方法的稀疏光流法,而cv2.calcOpticalFlowFarneback则是一种稠密光流法。

评论

user-avatar