以yolov8-pose为案例学习如何写deepstream的回调函数

这篇具有很好参考价值的文章主要介绍了以yolov8-pose为案例学习如何写deepstream的回调函数。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 管道元素的说明:

在给定的代码中,使用了以下几个元素来构建 DeepStream 管道:

  1. source:这个元素是用于从文件中读取视频流的输入源。它可以是任何 GStreamer 支持的视频输入源,如文件、摄像头、网络流等。

  2. streammux:这个元素是流复用器,用于将多个流合并成一个流,并将多帧画面打包为批处理数据。它可以将不同源的视频流合并为一个统一的输入。

  3. pgie:这个元素是主要的推理引擎(Primary GIE),用于执行物体检测和推理。它基于给定的配置文件进行推理,识别出图像中的物体并提取其特征。

  4. nvtracker:这个元素是 DeepStream 中的跟踪器,用于对识别到的物体进行跟踪。它利用先前识别到的物体特征和当前帧中的特征进行匹配和跟踪,以实现物体的持续跟踪。

  5. nvvidconv:这个元素是用于将视频帧格式从 NV12 转换为 RGBA 的视频转换器。在某些情况下,需要将视频帧从一种格式转换为另一种格式,以适应不同元素的要求。

  6. nvosd:这个元素是 On-Screen Display (OSD) 元素,用于在转换后的 RGBA 缓冲区上绘制识别结果、边界框、标签等信息。

  7. nvvidconv_postosd:这个元素是用于将转换后的 RGBA 格式的视频帧再次转换为 NV12 格式的视频转换器。这在将视频帧发送到编码器之前很常见。

  8. caps:这个元素是 Caps Filter 元素,用于设置视频格式的约束条件。它可以指定输入或输出流的特定格式和参数,以确保流的兼容性。

  9. encoder:这个元素是视频编码器,用于将原始视频帧编码为特定的视频编码格式,如 H.264 或 H.265。它根据指定的参数设置比特率、编码质量等。

  10. rtppay:这个元素用于将编码后的数据打包为 RTP(Real-time Transport Protocol)数据包。RTP 是一种常用的实时流传输协议。

  11. sink:这个元素是 UDPSink 元素,用于将 RTP 数据包通过 UDP 协议发送到网络。它通过指定目标 IP 地址和端口号来指定数据的接收位置。

以上是在给定的代码片段中使用的一些关键元素,它们在 DeepStream 管道中扮演着不同的角色,负责视频的输入、推理、跟踪、转换、绘制和输出等功能。

2. pipline的构建:

这是一个使用GStreamer构建的DeepStream管道。让我们逐步解释代码中的主要构建过程:

  1. 首先,定义了一系列用于构建管道所需的变量和参数,包括GstElement指针、比特率、编码格式、端口号等。

  2. 接下来,创建了GStreamer的各个元素,例如sourcestreammuxpgienvtracker等。这些元素用于处理视频流的输入、推理、跟踪和输出等功能。

  3. 设置了各个元素的参数。例如,设置streammux的批处理大小和输出分辨率,设置pgie的配置文件路径,设置nvtracker的属性等。

  4. 将各个元素添加到管道中。使用gst_bin_add_many()函数将元素添加到GStreamer的管道中,以便进行管理和链接。

  5. 连接元素之间的数据流。使用gst_element_link_many()函数将元素链接在一起,以定义数据的流动路径。

  6. 添加探针。使用gst_pad_add_probe()函数向pgie_src_padosd_sink_pad添加探针,用于获取元数据和处理缓冲区。

  7. 创建RTSP服务器。使用gst_rtsp_server_new()创建一个RTSP服务器,设置服务器的服务端口号,并将RTSP流挂载到服务器上。

  8. 设置管道状态为"播放"。使用gst_element_set_state()函数将管道设置为播放状态,开始视频流的处理和输出。

  9. 启动主循环。使用g_main_loop_run()函数启动GStreamer的主循环,该循环用于处理事件和消息。

  10. 等待退出。一直等待主循环结束,直到收到退出信号。

  11. 清理和释放资源。在退出主循环后,通过设置管道状态为NULL、释放管道资源和清理其他资源来完成清理工作。

以上是该代码构建DeepStream管道的主要过程。这个管道用于读取视频文件,执行推理和跟踪,然后输出处理结果,并通过RTSP流发布到网络上。

3. pgie探针函数主要功能

这个Pgie回调函数的主要功能如下:

  1. 获取GStreamer的buffer,并从中获取batch metadata。

  2. 遍历每一帧的metadata。

  3. 对于每一帧,遍历其用户metadata。

  4. 如果用户metadata的类型是tensor output,那么将其转换为NvDsInferTensorMeta类型。

  5. 获取模型的输入形状和输出层的信息。

  6. 将输出层的数据从C类型转换为Python的numpy数组。

  7. 对模型的输出进行后处理,包括调整维度、添加假的类别概率、将坐标映射到屏幕尺寸等。

  8. 对处理后的输出进行进一步的后处理,包括非极大值抑制等。

  9. 如果存在有效的预测结果,那么将这些结果添加到帧的对象metadata中,并显示在帧上。

  10. 更新帧的帧率。

  11. 标记该帧已经进行过推理。

将这个函数实现的大致步骤如下:

  1. 获取GStreamer的buffer,并从中获取batch metadata。这一步使用gst_buffer_get_nvds_batch_meta()函数来获取batch metadata。

  2. 遍历每一帧的metadata。这一步在C++中可以使用标准的迭代器或循环来完成。

  3. 对于每一帧,遍历其用户metadata。这一步在C++中可以使用标准的迭代器或循环来完成。

  4. 如果用户metadata的类型是tensor output,那么将其转换为NvDsInferTensorMeta类型。这一步使用NvDsInferNetworkInfo和NvDsInferLayerInfo来获取这些信息。

  5. 获取模型的输入形状和输出层的信息。这一步在C++中可以使用DeepStream的API来完成。

  6. 将输出层的数据从C类型转换为C++的数组或向量。这一步在C++中可以使用标准的数组或向量来完成。

  7. 对模型的输出进行后处理,包括调整维度、添加假的类别概率、将坐标映射到屏幕尺寸等。可以使用nvds_add_display_meta_to_frame()函数来添加显示metadata到帧中。

  8. 对处理后的输出进行进一步的后处理,包括非极大值抑制等。这一步在C++中可能需要使用或实现相应的算法。

  9. 如果存在有效的预测结果,那么将这些结果添加到帧的对象metadata中,并显示在帧上。这一步在C++中可以使用DeepStream的API来完成。

  10. 更新帧的帧率。这一步可以设置frame_meta->bInferDone为true来标记该帧已经进行过推理。

  11. 标记该帧已经进行过推理。这一步在C++中可以使用DeepStream的API来完成。

以上就是将这个Python函数转换为C++的大致步骤。具体的代码实现可能会根据你的具体需求和环境有所不同。

4. 分步骤实现这个回调函数

4.1 获取GStreamer的buffer

static GstPadProbeReturn pose_src_pad_buffer_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
{
    g_print("pose_src_pad_buffer_probe called\n");

    // 获取GstBuffer
    GstBuffer *buf = GST_PAD_PROBE_INFO_BUFFER(info);
    if (!buf) {
        g_print("Unable to get GstBuffer\n");
        return GST_PAD_PROBE_OK;
    }

    // 获取batch metadata
    NvDsBatchMeta *batch_meta = gst_buffer_get_nvds_batch_meta(buf);
    if (!batch_meta) {
        g_print("Unable to get batch metadata\n");
        return GST_PAD_PROBE_OK;
    }

    // 打印一些信息
    g_print("Successfully got GstBuffer and batch metadata\n");
    g_print("Batch meta frame count: %d\n", batch_meta->num_frames_in_batch);

    return GST_PAD_PROBE_OK;
}

4.2 遍历: batch metadata -> frame_meta_list -> user metadata

static GstPadProbeReturn pose_src_pad_buffer_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
{
    g_print("pose_src_pad_buffer_probe called\n");

    // 获取GstBuffer
    GstBuffer *buf = GST_PAD_PROBE_INFO_BUFFER(info);
    if (!buf) {
        g_print("Unable to get GstBuffer\n");
        return GST_PAD_PROBE_OK;
    }

    // 获取batch metadata
    NvDsBatchMeta *batch_meta = gst_buffer_get_nvds_batch_meta(buf);
    if (!batch_meta) {
        g_print("Unable to get batch metadata\n");
        return GST_PAD_PROBE_OK;
    }

    // 遍历每一帧的元数据
    for (NvDsMetaList *l_frame = batch_meta->frame_meta_list; l_frame != NULL; l_frame = l_frame->next) {
        NvDsFrameMeta *frame_meta = (NvDsFrameMeta *)(l_frame->data);

        // 对于每一帧,遍历其用户metadata
        for (NvDsMetaList *l_user = frame_meta->frame_user_meta_list; l_user != NULL; l_user = l_user->next) {
            NvDsUserMeta *user_meta = (NvDsUserMeta *)(l_user->data);
            g_print("Successfully got user metadata\n");
            g_print("User metadata type: %d\n", user_meta->base_meta.meta_type);
        }
    }

    return GST_PAD_PROBE_OK;
}
User metadata type: 12

这是NvDsMetaType枚举的一部分定义:

typedef enum
{
  NVDS_META_INVALID = 0,
  NVDS_META_FRAME_INFO,
  NVDS_META_EVENT_MSG,
  NVDS_META_STREAM_INFO,
  NVDS_META_SOURCE_INFO,
  NVDS_META_USER,
  NVDS_META_RESERVED_1,
  NVDS_META_RESERVED_2,
  NVDS_META_RESERVED_3,
  NVDS_META_RESERVED_4,
  NVDS_META_RESERVED_5,
  NVDS_META_RESERVED_6,
  NVDSINFER_TENSOR_OUTPUT_META = 12,
  /* More types */
} NvDsMetaType;

这意味着这个用户元数据是一个推理张量输出元数据,它包含了模型推理的结果

4.3 取出这个数据

用到这个,里面有解释对应的头文件是什么,我代码里面注释也有的
https://docs.nvidia.com/metropolis/deepstream/4.0/dev-guide/DeepStream_Development_Guide/baggage/structNvDsInferTensorMeta.html

static GstPadProbeReturn pose_src_pad_buffer_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
{
    g_print("pose_src_pad_buffer_probe called\n");

    // 获取GstBuffer
    GstBuffer *buf = GST_PAD_PROBE_INFO_BUFFER(info);
    if (!buf) {
        g_print("Unable to get GstBuffer\n");
        return GST_PAD_PROBE_OK;
    }

    // 获取batch metadata
    NvDsBatchMeta *batch_meta = gst_buffer_get_nvds_batch_meta(buf);
    if (!batch_meta) {
        g_print("Unable to get batch metadata\n");
        return GST_PAD_PROBE_OK;
    }

    // 遍历每一帧的元数据
    for (NvDsMetaList *l_frame = batch_meta->frame_meta_list; l_frame != NULL; l_frame = l_frame->next) {
        NvDsFrameMeta *frame_meta = (NvDsFrameMeta *)(l_frame->data);

        // 对于每一帧,遍历其用户metadata
        for (NvDsMetaList *l_user = frame_meta->frame_user_meta_list; l_user != NULL; l_user = l_user->next) 
        {
            NvDsUserMeta *user_meta = (NvDsUserMeta *)(l_user->data);
            
            // 如果用户metadata的类型是tensor output,那么将其转换为NvDsInferTensorMeta类型
            if (user_meta->base_meta.meta_type == 12) {
                NvDsInferTensorMeta *tensor_meta = (NvDsInferTensorMeta *)(user_meta->user_meta_data);
                g_print("Successfully casted user metadata to tensor metadata\n");
            }
        }
    }

    return GST_PAD_PROBE_OK;
}

4.4 使用这个换了的Tensor_Meta去获取模型的输入输出

做这一步是为了确保数据读取正确,因为本项目是做的Yolov8-pose, 输入是3x640x640 输出是56x8400

56 = bbox(4) + confidence(1) + keypoints(3 x 17) = 4 + 1 + 0 + 51 = 56

如果这里使用的是yolov7-pose, 输出就是57

bbox(4) + confidence(1) + cls(1) + keypoints(3 x 17) = 4 + 1 + 1 + 51 = 57

static GstPadProbeReturn pose_src_pad_buffer_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
{
    g_print("pose_src_pad_buffer_probe called\n");

    // 获取GstBuffer
    GstBuffer *buf = GST_PAD_PROBE_INFO_BUFFER(info);
    if (!buf) {
        g_print("Unable to get GstBuffer\n");
        return GST_PAD_PROBE_OK;
    }

    // 获取batch metadata
    NvDsBatchMeta *batch_meta = gst_buffer_get_nvds_batch_meta(buf);
    if (!batch_meta) {
        g_print("Unable to get batch metadata\n");
        return GST_PAD_PROBE_OK;
    }

    // 遍历每一帧的元数据
    for (NvDsMetaList *l_frame = batch_meta->frame_meta_list; l_frame != NULL; l_frame = l_frame->next) {
        NvDsFrameMeta *frame_meta = (NvDsFrameMeta *)(l_frame->data);

        // 对于每一帧,遍历其用户metadata
        for (NvDsMetaList *l_user = frame_meta->frame_user_meta_list; l_user != NULL; l_user = l_user->next) 
        {
            NvDsUserMeta *user_meta = (NvDsUserMeta *)(l_user->data);
            
            // 如果用户metadata的类型是tensor output,那么将其转换为NvDsInferTensorMeta类型
            if (user_meta->base_meta.meta_type == 12) {
                NvDsInferTensorMeta *tensor_meta = (NvDsInferTensorMeta *)(user_meta->user_meta_data);

                // 获取模型的输入形状
                NvDsInferNetworkInfo network_info = tensor_meta->network_info;
                g_print("Model input shape: %d x %d x %d\n", network_info.channels, network_info.height, network_info.width);

                // 获取模型的输出层信息
                for (unsigned int i = 0; i < tensor_meta->num_output_layers; i++) {
                    NvDsInferLayerInfo output_layer_info = tensor_meta->output_layers_info[i];
                    NvDsInferDims dims = output_layer_info.inferDims;
                    g_print("Output layer %d: %s, dimensions: ", i, output_layer_info.layerName);
                    for (int j = 0; j < dims.numDims; j++) {
                        g_print("%d ", dims.d[j]);
                    }
                    g_print("\n");
                }

            }
        }
    }

    return GST_PAD_PROBE_OK;
}

跟TensorRT推理的结果进行对齐

INFO: [Implicit Engine Info]: layers num: 2
0   INPUT  kFLOAT images          3x640x640       
1   OUTPUT kFLOAT output0         56x8400  

下面是我们打印出来的结果文章来源地址https://www.toymoban.com/news/detail-548900.html

Model input shape: 3 x 640 x 640
Output layer 0: output0, dimensions: 56 8400

到了这里,关于以yolov8-pose为案例学习如何写deepstream的回调函数的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 目标检测YOLO实战应用案例100讲-基于改进的 YOLOv8 小目标检测

    目录 前言 研究现状 传统目标检测算法 基于卷积神经网络的目标检测算法

    2024年02月07日
    浏览(34)
  • YOLOv8 如何进行目标追踪

    YOLOv8 检测-追踪 YOLOv8 分割-追踪 YOLOv8 检测-追踪 目标检测 是指在图像或视频中定位并识别出一个或多个目标物体的位置和类别。 目标检测算法通常会输出目标的边界框和对应的类别标签ÿ

    2024年02月14日
    浏览(25)
  • 如何加载模型YOLOv8 ONNXRuntime

    YOLOv8 是 YOLO(You Only Look Once)目标检测系统的最新版本(v8)。YOLO 是一种实时、一次性目标检测系统,旨在在网络的单次前向传递中执行目标检测,使其快速高效。YOLOv8是之前YOLO模型的改进版本,具有更高的精度和更快的推理速度。 ONNX(开放神经网络交换)是一种表示深度

    2024年02月14日
    浏览(25)
  • 如何从轻量化角度改进YOLOv8?

    随着计算机视觉技术的发展,目标检测一直是计算机视觉领域中的热门话题。而YOLO(You Only Look Once)作为一种基于神经网络的目标检测算法,在检测速度和准确率方面都有很好的表现。然而,在实际应用中,YOLO还存在着一些问题,例如它的模型比较大,需要较高的计算资源

    2024年02月04日
    浏览(31)
  • 【深度学习】YOLOv8训练过程,YOLOv8实战教程,目标检测任务SOTA,关键点回归

    https://github.com/ultralytics/ultralytics 官方教程:https://docs.ultralytics.com/modes/train/ 更建议下载代码后使用 下面指令安装,这样可以更改源码,如果不需要更改源码就直接pip install ultralytics也是可以的。 这样安装后,可以直接修改yolov8源码,并且可以立即生效。此图是命令解释: 安

    2024年02月10日
    浏览(44)
  • YOLOv8如何添加注意力模块?

    分为两种:有参注意力和无参注意力。 eg: 有参: 无参: 1、在nn文件夹下新建attention.py文件,把上面俩代码放进去 2、在tasks.py文件里面导入俩函数 3、在解析函数里面添加解析代码 c1:上一层的输出通道数,也是这一层的输入通道数 C2:该层的输出通道数,即将成为下一层的输

    2024年02月07日
    浏览(31)
  • 改进YOLO系列:改进YOLOv8,教你YOLOv8如何添加20多种注意力机制,并实验不同位置。

    注意力机制(Attention Mechanism)是深度学习中一种重要的技术,它可以帮助模型更好地关注输入数据中的关键信息,从而提高模型的性能。注意力机制最早在自然语言处理领域的序列到序列(seq2seq)模型中得到广泛应用,后来逐渐扩展到了计算机视觉、语音识别等多个领域。

    2024年02月16日
    浏览(31)
  • 【学习笔记】部署yolov8到安卓手机

    首先你需要配置好pytorch环境,本文不再详细阐述,若未配置好环境,可以参考我的另一篇博客:https://blog.csdn.net/liujiahao123987/article/details/128743017 yolov8的安装可参考:https://blog.csdn.net/weixin_44120785/article/details/128681117 官网链接:https://developer.android.google.cn/ 自行配置AS环境(这方

    2024年02月03日
    浏览(31)
  • Yolov8如何在训练意外中断后接续训练

    请使用第四节的新方法,不需要修改代码,更加简单。 在训练YOLOv8的时候,因为开太多其他程序,导致在100多次的时候崩溃,查询网上相关知识如何接着训练,在yolo5中把resume改成True就可以。 在yolov8中也这样尝试,将ultralytics/yolo/cfg/default.yaml中的resume改成True发现并没有作用

    2024年02月07日
    浏览(64)
  • 【计算机视觉】YOLOv8如何使用?(含源代码)

    comments description keywords true Boost your Python projects with object detection, segmentation and classification using YOLOv8. Explore how to load, train, validate, predict, export, track and benchmark models with ease. YOLOv8, Ultralytics, Python, object detection, segmentation, classification, model training, validation, prediction, model export, bench

    2024年02月04日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包