【opencv】dnn示例-vit_tracker.cpp 使用OpenCV库和ViTTrack模型实现的视频追踪程序

news2024/12/23 9:19:51

65e0bcc15f7c222f50af0787fdd9b984.png

这段代码是一个使用OpenCV库和ViTTrack模型实现的视频追踪程序。程序通过摄像头或视频文件获取图像序列,并对选定的目标对象进行实时追踪。

代码主要分为以下几个部分:

导入必要的库:程序开始时先导入了iostream,cmath以及相关OpenCV的库。

参数解析:通过定义一个参数字典keys来解析命令行输入的参数,这些参数包括输入的视频源、模型的路径以及计算后端等。

追踪器的创建与设置:使用给定的模型文件以及命令行参数中的后端和目标设备选项,创建一个ViT追踪器对象。

视频捕获:程序尝试打开摄像头或读取视频文件。如果指定了摄像头或视频文件但不能成功打开,程序将输出错误信息。

目标对象的选择:获取视频的第一帧,并让用户选择一个区域作为追踪的初始目标。

追踪循环:程序进入一个循环,不断从视频源获取新的帧,并使用追踪器更新目标位置。每一次追踪完成后,都会输出框架的计数、预测分数、目标位置方框以及每帧追踪耗时。

追踪结果展示:将追踪的结果(目标位置的矩形框及其分数)覆盖在原图像上,并在窗口中展示出来。

退出处理:程序会在按下ESC键后退出追踪循环,并关闭程序。

整体而言,代码实现了一个基于ViT追踪模型的视频目标追踪系统,包含了从视频源获取图像、初始化追踪目标、连续追踪目标以及展示追踪结果等功能。程序使用OpenCV的DNN模块加载ONNX格式的深度学习模型,并通过选择合适的后端(例如CUDA)和目标设备来加速计算过程。

// VitTracker
// model: https://github.com/opencv/opencv_zoo/tree/main/models/object_tracking_vittrack


#include <iostream> // 引入输入输出流库
#include <cmath> // 引入数学运算库


#include <opencv2/dnn.hpp> // 引入OpenCV深度神经网络模块
#include <opencv2/imgproc.hpp> // 引入OpenCV图像处理模块
#include <opencv2/highgui.hpp> // 引入OpenCV高级用户界面模块
#include <opencv2/video.hpp> // 引入OpenCV视频处理模块


using namespace cv; // 使用cv命名空间简化代码
using namespace cv::dnn; // 使用cv::dnn命名空间简化代码


const char *keys = // 定义命令行参数
        "{ help     h  |   | Print help message }" // 打印帮助信息
        "{ input    i  |   | Full path to input video folder, the specific camera index. (empty for camera 0) }" // 输入视频路径或摄像头索引(默认为0)
        "{ net    | object_tracking_vittrack_2023sep.onnx | Path to onnx model of vitTracker.onnx}" // vitTracker.onnx模型的路径
        "{ backend     | 5 | Choose one of computation backends: " // 选择计算后端
                            "0: automatically (by default), " // 自动选择
                            "1: Halide language (http://halide-lang.org/), " // Halide语言
                            "2: Intel's Deep Learning Inference Engine (https://software.intel.com/openvino-toolkit), " // 英特尔深度学习推理引擎
                            "3: OpenCV implementation, " // OpenCV实现
                            "4: VKCOM, " // VKCOM
                            "5: CUDA }," // CUDA
        "{ target      | 6 | Choose one of target computation devices: " // 选择目标计算设备
                            "0: CPU target (by default), " // CPU
                            "1: OpenCL, " // OpenCL
                            "2: OpenCL fp16 (half-float precision), " // OpenCL fp16 (半精度浮点)
                            "3: VPU, " // VPU
                            "4: Vulkan, " // Vulkan
                            "6: CUDA, " // CUDA
                            "7: CUDA fp16 (half-float preprocess) }" // CUDA fp16 (半精度预处理)
;


static
int run(int argc, char** argv) // 定义主要运行函数
{
    // Parse command line arguments.
    CommandLineParser parser(argc, argv, keys); // 命令行参数解析


    if (parser.has("help")) // 如果存在帮助参数
    {
        parser.printMessage(); // 打印帮助信息
        return 0;
    }


    std::string inputName = parser.get<String>("input"); // 获取输入源
    std::string net = parser.get<String>("net"); // 获取模型路径
    int backend = parser.get<int>("backend"); // 获取后端参数
    int target = parser.get<int>("target"); // 获取目标计算设备参数


    Ptr<TrackerVit> tracker; // 声明一个ViT跟踪器的智能指针
    try // 尝试加载跟踪器和模型
    {
        TrackerVit::Params params; // 创建跟踪器参数结构
        params.net = samples::findFile(net); // 找到或保持模型文件路径
        params.backend = backend; // 设置后端参数
        params.target = target; // 设置目标计算设备参数
        tracker = TrackerVit::create(params); // 创建跟踪器实例
    }
    catch (const cv::Exception& ee) // 如果捕获到异常
    {
        std::cerr << "Exception: " << ee.what() << std::endl; // 打印异常信息
        std::cout << "Can't load the network by using the following files:" << std::endl; // 说明无法加载网络
        std::cout << "net : " << net << std::endl; // 打印网络路径
        return 2;
    }


    const std::string winName = "vitTracker"; // 窗口名称
    namedWindow(winName, WINDOW_AUTOSIZE); // 创建具有自动大小的窗口


    // Open a video file or an image file or a camera stream.
    VideoCapture cap; // 创建视频捕获对象


    if (inputName.empty() || (isdigit(inputName[0]) && inputName.size() == 1)) // 如果输入为空或仅有单个数字(表示摄像头索引)
    {
        int c = inputName.empty() ? 0 : inputName[0] - '0'; // 默认为0或转换数字为摄像头索引
        std::cout << "Trying to open camera #" << c << " ..." << std::endl;
        if (!cap.open(c)) // 尝试打开摄像头
        {
            std::cout << "Capture from camera #" << c << " didn't work. Specify -i=<video> parameter to read from video file" << std::endl; // 打开失败提示
            return 2;
        }
    }
    else if (inputName.size()) // 如果输入非空
    {
        inputName = samples::findFileOrKeep(inputName); // 查找或保持文件路径
        if (!cap.open(inputName)) // 尝试打开视频文件
        {
            std::cout << "Could not open: " << inputName << std::endl; // 打开失败提示
            return 2;
        }
    }


    // Read the first image.
    Mat image; // 创建一个Mat对象用于存放图像
    cap >> image; // 捕获一帧图像
    if (image.empty()) // 如果图像为空
    {
        std::cerr << "Can't capture frame!" << std::endl; // 抓取图像失败提示
        return 2;
    }


    Mat image_select = image.clone(); // 克隆捕获的图像以便用户选择跟踪区域
    putText(image_select, "Select initial bounding box you want to track.", Point(0, 15), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0)); // 在图像上添加文字指导用户选择跟踪区域
    putText(image_select, "And Press the ENTER key.", Point(0, 35), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0)); // 提示用户按下回车键确认选择


    Rect selectRect = selectROI(winName, image_select); // 让用户选择一个区域并返回矩形坐标
    std::cout << "ROI=" << selectRect << std::endl; // 输出用户选择的区域


    tracker->init(image, selectRect); // 初始化跟踪器并使用用户选择的区域


    TickMeter tickMeter; // 创建一个时钟计时器对象


    for (int count = 0; ; ++count) // 循环处理视频帧
    {
        cap >> image; // 捕获一帧图像
        if (image.empty()) // 如果图像为空
        {
            std::cerr << "Can't capture frame " << count << ". End of video stream?" << std::endl; // 抓取图像失败提示
            break;
        }


        Rect rect; // 创建一个矩形对象


        tickMeter.start(); // 开始计时
        bool ok = tracker->update(image, rect); // 更新跟踪器状态并返回跟踪框的位置
        tickMeter.stop(); // 停止计时


        float score = tracker->getTrackingScore(); // 获取跟踪评分


        std::cout << "frame " << count << // 输出当前帧数
            ": predicted score=" << score << // 输出预测评分
            "  rect=" << rect << // 输出跟踪框位置
            "  time=" << tickMeter.getTimeMilli() << "ms" << // 输出计时时间
            std::endl;


        Mat render_image = image.clone(); // 克隆当前帧以便绘制跟踪结果


        if (ok) // 如果跟踪成功
        {
            rectangle(render_image, rect, Scalar(0, 255, 0), 2); // 在渲染图像上绘制跟踪框


            std::string timeLabel = format("Inference time: %.2f ms", tickMeter.getTimeMilli()); // 格式化输出计时标签
            std::string scoreLabel = format("Score: %f", score); // 格式化输出评分标签
            putText(render_image, timeLabel, Point(0, 15), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0)); // 将计时标签绘制在图像上
            putText(render_image, scoreLabel, Point(0, 35), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0)); // 将评分标签绘制在图像上
        }


        imshow(winName, render_image); // 显示渲染后图像


        tickMeter.reset(); // 重置计时器


        int c = waitKey(1); // 等待按键
        if (c == 27 /*ESC*/) // 如果按下ESC键
            break; // 退出循环
    }


    std::cout << "Exit" << std::endl; // 输出退出提示
    return 0; // 返回成功
}


int main(int argc, char **argv) // 主程序入口函数
{
    try // 尝试运行主功能函数
    {
        return run(argc, argv); // 调用run函数并返回结果
    }
    catch (const std::exception& e) // 捕获任何抛出的异常
    {
        std::cerr << "FATAL: C++ exception: " << e.what() << std::endl; // 输出异常信息
        return 1; // 返回失败
    }
}

该代码是使用OpenCV库实现的一个简单的视频跟踪应用程序。它主要通过解析命令行输入不同的参数来调整视频输入源、选择神经网络模型、计算后端以及目标计算设备。代码首先尝试加载一个基于ViT(Vision Transformer)的目标跟踪器模型。接下来,它通过用户选择的图像区域初始化跟踪器并开始对视频流中的目标进行跟踪。每个循环中,都会更新跟踪器并计算其评分以及跟踪目标的位置,然后将跟踪结果绘制在每帧上并实时显示给用户。如果用户按下ESC键,则会退出循环结束程序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1606274.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

每日两题 / 53. 最大子数组和 56. 合并区间(LeetCode热题100)

53. 最大子数组和 - 力扣&#xff08;LeetCode&#xff09; 经典dp题&#xff0c;dp[i]表示以nums[i]为结尾的所有子数组中&#xff0c;最大的和 将i从左到右遍历&#xff0c;考虑dp[i]如何维护&#xff1f; 以nums[i]结尾的子数组只有两种情况&#xff0c;子数组只有nums[i]…

[Qt网络编程]之UDP通讯的简单编程实现

hello&#xff01;欢迎大家来到我的Qt学习系列之网络编程之UDP通讯的简单编程实现。希望这篇文章能对你有所帮助&#xff01;&#xff01;&#xff01; 本篇文章的相关知识请看我的上篇文章: http://t.csdnimg.cn/UKyeM 目录 UDP通讯 基于主窗口的实现 基于线程的实现 UDP通讯…

小黄脸404自动跳转源码

源码介绍 小黄脸404自动跳转源码&#xff0c;源码由HTMLCSSJS组成&#xff0c;记事本打开源码文件可以进行内容文字之类的修改&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务器里面&#xff0c;重定向这个界面 效果截图 源码下载 小黄脸404自动跳转…

网络防火墙技术知多少?了解如何保护您的网络安全

在当前以网络为核心的世界中&#xff0c;网络安全成为了至关重要的议题。网络防火墙是一种常见的保护网络安全的技术&#xff0c;用于监控和控制网络流量&#xff0c;阻止未经授权的访问和恶意活动。今天德迅云安全就带您了解下防火墙的一些相关功能和类型。 防火墙的五个功能…

【EI会议征稿通知】2024年图像处理、机器学习与模式识别国际学术会议(IPMLP 2024)

2024年图像处理、机器学习与模式识别国际学术会议&#xff08;IPMLP 2024) 2024 International Conference on Image Processing, Machine Learning and Pattern Recognition 重要信息 大会官网&#xff1a;www.ipmlp.net&#xff08;点击参会/投稿/了解会议详情&#xff09;…

【操作系统】(Operator System)

目录 1.概念2.系统调用和库函数 1.概念 1.操作系统是什么呢&#xff1f;&#xff1f; 操作系统是一款进行软硬件资源管理的软件&#xff0c;我们打开电脑第一个加载的软件就是操作系统。 2.为什么要有操作系统呢&#xff1f; 操作系统通过将软硬件资源管理好(手段)&#xf…

axios的封装理解和基本使用

axios的配置 ruoyi的前端对axios进行了封装&#xff0c;让我们发get请求或者是post请求更加方便了。 ruoyi对axios的封装在下面文件中&#xff1a;打开文件&#xff0c;可以看到它有三个显眼的方法&#xff0c;分别是request拦截器、response拦截器和通用下载方法。ruoYi接口地…

ansible进阶-剧本调试方法

目录 1、调试方法 2、实例 2.1 Debug模块 2.2 tags标签 2.3 忽略错误 1、调试方法 具体方法应用场景debug标签执⾏剧本的时候输出剧本的执⾏流程,⼀般配合register⼀起使⽤. 输出facts变量自定义变量tags标签给⼀些模块加上标签,运⾏剧本的时候可以运⾏指定标签的…

基于非线性控制策略的电力电子电路——DC-DC电路的3种滑模控制器【MATLAB/simulink】

第一种&#xff0c;滞环滑模控制器Buck电路 在滑模控制系统中&#xff0c;采用滞环技术&#xff0c;直接将切换函数转换成开关控制信号&#xff0c;滞环技术被看做一种降低系统结构的切换频率的调制方法&#xff0c;业界也把基于滞环滑模技术实现的滑模控制称为直接滑模控制技…

【ESP32 手机配网教程】

【ESP32 手机配网教程】 1. 前言2. 先决条件2.1 环境配置2.2 所需零件3.3 硬件连接步骤 3. Web热点手动配网3.1. 准备工作3.2. 编译上传程序3.3. 进行手动配网 4. BLE无线配网4.1. 准备工作**4.2. 编译上传程序4.3. 使用手机APP进行无线配网 5. 总结 1. 前言 欢迎使用ESP32进行…

【C++】list的介绍及使用说明

目录 00.引言 01.list的介绍 模版类 独立节点存储 list的使用 1.构造函数 2.迭代器的使用 分类 运用 3.容量管理 empty()&#xff1a; size(): 4.元素访问 5.增删查改 00.引言 我们学习数据结构时&#xff0c;学过两个基本的数据结构&#xff1a;顺序表和链表。顺…

基于simulink的模拟锁相环和数字锁相环建模与对比仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1 模拟锁相环&#xff08;PLL&#xff09;的基本原理 4.2 数字锁相环&#xff08;DPLL&#xff09;的基本原理 5.完整工程文件 1.课题概述 模拟锁相环和数字锁相环建模的simulink建模&#xff0c;对…

深度剖析哈希

目录 一. 哈希概念 1.1 哈希概念 1.2 哈希冲突 1.3 哈希函数 二. 闭散列 2.1 线性探测法 2.2 引进状态 2.3 闭散列的查找、插入、删除操作 2.4 闭散列插入时的扩容 2.4 仿函数 2.5 整体代码 三. 开散列 ​编辑 2.1 闭散列节点定义 2…

HBuilder真机调试检测不到荣耀Magic UI系列(包括手机和电脑)解决办法

HBuilder真机调试检测不到荣耀Magic UI系列&#xff08;包括手机和电脑&#xff09;解决办法解决方法&#xff1a; 1.在开发人员选项中开启USB调试 如何进入开发者选项&#xff1f; 设置->关于->版本号&#xff0c;点击版本号直至出现您已处于开发者模式 2.选择USB配置…

Swin Transformer 浅析

Swin Transformer 浅析 文章目录 Swin Transformer 浅析引言Swin Transformer 的网络结构W-MSA 窗口多头注意力机制SW-MSA 滑动窗口多头注意力机制Patch Merging 图块合并 引言 因为ViT无法实现CNN中的层次化构建以及局部信息&#xff0c;由此微软团队提出了Swin Transformer来…

【论文阅读】YOLO-World | 开集目标检测

Date&#xff1a;2024.02.22&#xff0c;Tencent AI Lab&#xff0c;华中科技大学Paper&#xff1a;https://arxiv.org/pdf/2401.17270.pdfGithub&#xff1a;https://github.com/AILab-CVC/YOLO-World 论文解决的问题&#xff1a; 通过视觉语言建模和大规模数据集上的预训练来…

【QT+OpenCV】车牌号检测 学习记录 遇到的问题

【QTOpenCV】车牌号检测 学习记录 首先在QT里面配置好OpenCV .pro文件中加入&#xff1a; INCLUDEPATH G:/opencv/build/include LIBS -L"G:/opencv/build/x64/vc14/lib"\-lopencv_core \-lopencv_imgproc \-lopencv_highgui \-lopencv_ml \-lopencv_video \-lo.c…

展览展会媒体媒体邀约执行应该怎么做?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 展览展会邀请媒体跟其他活动邀请媒体流程大致相同&#xff0c;包括 制定媒体邀约计划&#xff0c;准备新闻稿&#xff0c;发送邀请函&#xff0c;确认媒体参会&#xff0c;现场媒体接待及…

页缓存(PageCache)和预读机制(readahead )

页缓存&#xff08;PageCache)和预读机制&#xff08;readahead &#xff09; 页缓存&#xff08;PageCache)是操作系统&#xff08;OS&#xff09;对文件的缓存&#xff0c;用于加速对文件的读写。 page 是内存管理分配的基本单位&#xff0c; Page Cache 由多个 page 构成&…

【观察】容器化部署“再简化”,云原生体验“再升级”

自2013年云原生概念被提出以来&#xff0c;云原生技术和架构在过去十多年得到了迅速的发展&#xff0c;并对数字基础设施、应用架构和应用构建模式带来了深刻的变革。根据IDC预测&#xff0c;到2024年&#xff0c;新增的生产级云原生应用在新应用的占比将从2020年的10%增加到60…