0. sample背景介绍

该sample向我们展示如何将encoded image作为meta data然后将其以JPEG的格式保存下来。

该sample源代码的位置:sources/apps/sample_apps / deepstream-image-meta-test.代码中涉及的主要类及其它们之间的关系可以如下表所示。

1. 将encoded objects转换为metadata

在pgie_src_pad_buffer_probe回调函数中调用nvds_obj_enc_start_encode函数编码detected objects的内容。然后,通过在osd element的sink pad中创建一个probe回调函数来访问encoded objects并将其保存到文件中,此时encoded objects的metadata类型为"NVDS_CROP_IMAGE_META"。

在该sample中,使用的是Object Encoder API。

1.0 创建一个context

通过调用nvds_obj_enc_create_context来创建context并返回一个执行NvObjEncCtx的handle句柄。然后,将context传入probe回调函数。

 /* Lets add probe to get informed of the meta data generated, we add probe to* the srd pad of the pgie element, since by that time, the buffer would have* had got all the nvinfer metadata. */pgie_src_pad = gst_element_get_static_pad (pgie, "src");/*Creat Context for Object Encoding */NvDsObjEncCtxHandle obj_ctx_handle = nvds_obj_enc_create_context ();if (!obj_ctx_handle) {g_print ("Unable to create context\n");return -1;}if (!pgie_src_pad)g_print ("Unable to get src pad\n");elsegst_pad_add_probe (pgie_src_pad, GST_PAD_PROBE_TYPE_BUFFER,pgie_src_pad_buffer_probe, (gpointer) obj_ctx_handle, NULL);... /* Destroy context for Object Encoding */nvds_obj_enc_destroy_context (obj_ctx_handle);

1.1 编码objects区域

通过调用nvds_obj_enc_process函数,将物体检测的区域crop下来并编码。

首先,查看nvds_obj_enc_process函数的定义,即需要传入哪些参数。

在原始的frame中执行crop操作并进行JPEG编码。在这个函数中,我们需要传入NvDsObjEncCtxHandle和NvDsObjEncUsrArgs参数,前一个参数就是我们传进来的context,而后一个参数NvDsObjEncUsrArgs的定义如下:

在对所有检测到的objects的区域进行编码之后,需要调用 nvds_obj_enc_finish() to make sure all enqueued object crops have been processed来保证所有待处理的objects被crop下来。

/* pgie_src_pad_buffer_probe will extract metadata received on pgie src pad* and update params for drawing rectangle, object information etc. We also* iterate through the object list and encode the cropped objects as jpeg* images and attach it as user meta to the respective objects.*/
static GstPadProbeReturn
pgie_src_pad_buffer_probe (GstPad * pad, GstPadProbeInfo * info, gpointer ctx)
{GstBuffer *buf = (GstBuffer *) info->data;GstMapInfo inmap = GST_MAP_INFO_INIT;if (!gst_buffer_map (buf, &inmap, GST_MAP_READ)) {GST_ERROR ("input buffer mapinfo failed");return GST_FLOW_ERROR;}NvBufSurface *ip_surf = (NvBufSurface *) inmap.data;        // surfacegst_buffer_unmap (buf, &inmap);NvDsObjectMeta *obj_meta = NULL;guint vehicle_count = 0;guint person_count = 0;NvDsMetaList *l_frame = NULL;NvDsMetaList *l_obj = NULL;NvDsBatchMeta *batch_meta = gst_buffer_get_nvds_batch_meta (buf);for (l_frame = batch_meta->frame_meta_list; l_frame != NULL;l_frame = l_frame->next) {NvDsFrameMeta *frame_meta = (NvDsFrameMeta *) (l_frame->data);guint num_rects = 0;for (l_obj = frame_meta->obj_meta_list; l_obj != NULL; l_obj = l_obj->next) {obj_meta = (NvDsObjectMeta *) (l_obj->data);if (obj_meta->class_id == PGIE_CLASS_ID_VEHICLE) {vehicle_count++;num_rects++;}if (obj_meta->class_id == PGIE_CLASS_ID_PERSON) {person_count++;num_rects++;}/* Conditions that user needs to set to encode the detected objects of* interest. Here, by default all the detected objects are encoded.* For demonstration, we will encode the first object in the frame */if ((obj_meta->class_id == PGIE_CLASS_ID_PERSON|| obj_meta->class_id == PGIE_CLASS_ID_VEHICLE) && num_rects == 1) {NvDsObjEncUsrArgs userData = { 0 };/* To be set by user */userData.saveImg = save_img;userData.attachUsrMeta = attach_user_meta;/* Preset */userData.objNum = num_rects;/*Main Function Call */nvds_obj_enc_process (ctx, &userData, ip_surf, obj_meta, frame_meta);}}}nvds_obj_enc_finish (ctx);return GST_PAD_PROBE_OK;
}

2. 保存objects区域内容

通过在osd element的sink pad上添加一个probe函数,将objects区域保存成文件。

  /* Lets add probe to get informed of the meta data generated, we add probe to* the sink pad of the osd element, since by that time, the buffer would have* had got all the metadata. *//*通过在osd element的sink pad上添加一个probe函数,来通知meta data已经生成,因为,此时buffer已经获取到所有的metadata*/osd_sink_pad = gst_element_get_static_pad (nvosd, "sink");if (!osd_sink_pad)g_print ("Unable to get sink pad\n");elsegst_pad_add_probe (osd_sink_pad, GST_PAD_PROBE_TYPE_BUFFER,osd_sink_pad_buffer_probe, (gpointer) obj_ctx_handle, NULL);gst_object_unref (osd_sink_pad);

在OSD的sink probe函数中,我们通过循环遍历object meta中的user meta数据,找到类型为"NVDS_CROP_IMAGE_META"的,并将其保存到jpg文件中

/* To verify  encoded metadata of cropped objects, we iterate through the* user metadata of each object and if a metadata of the type* 'NVDS_CROP_IMAGE_META' is found then we write that to a file as* implemented below.*//*  为了验证所有的cropped objects编码的metadata,我们通过循环迭代每个object的user metadata如果找到的metadata类型为 'NVDS_CROP_IMAGE_META',则将其写入到一个文件中*/char fileNameString[FILE_NAME_SIZE];const char *osd_string = "OSD";int obj_res_width = (int) obj_meta->rect_params.width;int obj_res_height = (int) obj_meta->rect_params.height;if(prop.integrated) {obj_res_width = GST_ROUND_DOWN_2(obj_res_width);obj_res_height = GST_ROUND_DOWN_2(obj_res_height);}snprintf (fileNameString, FILE_NAME_SIZE, "%s_%d_%d_%d_%s_%dx%d.jpg",osd_string, frame_number, frame_meta->source_id, num_rects,obj_meta->obj_label, obj_res_width, obj_res_height);/* For Demonstration Purposes we are writing metadata to jpeg images of* only vehicles for the first 100 frames only.* The files generated have a 'OSD' prefix. */if (frame_number < 100 && obj_meta->class_id == PGIE_CLASS_ID_VEHICLE) {// 从object meta中获取user meta数据NvDsUserMetaList *usrMetaList = obj_meta->obj_user_meta_list;FILE *file;while (usrMetaList != NULL) // 可能存在多个user meta数据,而在本例中只处理NVDS_CROP_IMAGE_META类型的数据{// 得到user meta数据NvDsUserMeta *usrMetaData = (NvDsUserMeta *) usrMetaList->data;// 判断user meta的类型if (usrMetaData->base_meta.meta_type == NVDS_CROP_IMAGE_META) {NvDsObjEncOutParams *enc_jpeg_image =(NvDsObjEncOutParams *) usrMetaData->user_meta_data;/* Write to File */file = fopen (fileNameString, "wb");fwrite (enc_jpeg_image->outBuffer, sizeof (uint8_t),enc_jpeg_image->outLen, file);fclose (file);usrMetaList = NULL;} else {usrMetaList = usrMetaList->next;}}}

在上述的代码中,NvDsObjEncOutParams类中包含了cropped objects的数据内容,该类中的outBuffer是一个指向JPEG Encoded Object的指针,outLen表示该JPEG Encode Object的长度,基于这两个参数就可以将object的内容写入到一个文件中。

3. 修改pipeline保存视频结果

原pipeline中检测后的结果直接可视化在屏幕上,而一般对于嵌入式设备不链接显示器,因此可以通过如下的代码将检测的视频结果保存到MP4文件中。具体包含两步:

1. 新建element

 /* save file */GstElement *nvvideoconvert = NULL, *nvv4l2h264enc = NULL, *h264parserenc = NULL;nvvideoconvert = gst_element_factory_make("nvvideoconvert", "nvvideo-converter2");nvv4l2h264enc = gst_element_factory_make ("nvv4l2h264enc", "nvv4l2-h264enc");h264parserenc = gst_element_factory_make ("h264parse", "h264-parserenc");sink = gst_element_factory_make ("filesink", "filesink");g_object_set (G_OBJECT (sink), "location", "./output.mp4", NULL);

2. 将element加入到pipeline中

gst_bin_add_many (GST_BIN (pipeline), pgie, tiler, nvvidconv, nvosd,nvvideoconvert, nvv4l2h264enc, h264parserenc, sink, NULL);gst_element_link_many (streammux, pgie, tiler, nvvidconv, nvosd,nvvideoconvert, nvv4l2h264enc, h264parserenc, sink, NULL)

同样也可添加fakesink element将检测结果丢弃,具体可以参考链接。

  if(prop.integrated) {// Jetson平台才需要这个elementtransform = gst_element_factory_make ("queue", "nvegl-transform");    }sink = gst_element_factory_make ("fakesink", "nvvideo-renderer");

最后通过如下命令即可运行该sample

# 编译
export CUDA_VER=10.2
make
# 运行
./deepstream-image-meta-test file:///opt/nvidia/deepstream/deepstream-6.0/samples/streams/sample_720p.h264

deepstream-image-meta-test解析相关推荐

  1. Nvidia Deepstream极致细节:2. Deepstream Python Meta数据解读

    Nvidia Deepstream极致细节:2. Deepstream Python Meta数据解读 这一章节中,我们将介绍如何使用Nvidia Deepstream内自定义的Metadata,包括 ...

  2. deepstream学习笔记(三):deepstream-imagedata-multistream解析与接入适配yolov5模型测试

    引言 上一节重点介绍了gstreamer架构图与各部分组成原理说明,并且针对deepstream-test1介绍了它的整体功能和画出了管道图,本篇博文将详细介绍deepstream-imagedata ...

  3. 文件解析库doctotext源码分析

    doctotext中没有make install选项,make后生成可执行文件 在buile目录下面有.so动态库和头文件,需要的可以从这里面拷贝 build/doctotext就是可执行程序. do ...

  4. leveldb的sstable-ldb解析

    (Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu) leveldb数据库的sstable-ldb文件解析. 引言 ldb文件作为sorted-string- ...

  5. python scrapy爬虫视频_python爬虫scrapy框架的梨视频案例解析

    之前我们使用lxml对梨视频网站中的视频进行了下载 下面我用scrapy框架对梨视频网站中的视频标题和视频页中对视频的描述进行爬取 分析:我们要爬取的内容并不在同一个页面,视频描述内容需要我们点开视频 ...

  6. 一行代码让你的python运行速度提高100倍

    python一直被病垢运行速度太慢,但是实际上python的执行效率并不慢,慢的是python用的解释器Cpython运行效率太差. "一行代码让python的运行速度提高100倍" ...

  7. GCD简介二:多核心的性能

    一.概念 为了在单一进程中充分发挥多核的优势,我们有必要使用多线程技术.在低层,GCD全局dispatch queue仅仅是工作线程池的抽象.这些队列中的Block一旦可用,就会被dispatch到工 ...

  8. Redis实现分布式爬虫

    redis分布式爬虫 概念:多台机器上可以执行同一个爬虫程序,实现网站数据的爬取 原生的scrapy是不可以实现分布式爬虫, 原因如下: 调度器无法共享 管道无法共享 scrapy-redis组件:专 ...

  9. viewport理解

    以下内容对viewport理解不够深入,重写了一篇文章介绍基于REM响应式适配问题: 地址: 基于REM响应式适配方案 viewport预备知识 dpr === dppx dpr:device pix ...

  10. 一行代码让 Python 的运行速度提高100倍

    python一直被病垢运行速度太慢,但是实际上python的执行效率并不慢,慢的是python用的解释器Cpython运行效率太差. "一行代码让python的运行速度提高100倍" ...

最新文章

  1. 你的 webpack 也需要休息,让你的 webpack 拒绝 996ICU
  2. 成为顶尖机器学习算法专家需要知道哪些算法?
  3. 是第一个成功设计微型计算机的人,()是第一个成功设计微型计算机的人。
  4. 甲骨文预言机平台(2)OCI 系统架构
  5. VC编写的程序不能在其他机器上运行的解决方案(续)
  6. 没有shell63号单元_苏教版15年级数学上册第七单元整理与复习+同步练习
  7. Autocomplete
  8. Intellij IDEA中安装使用PlantUML画时序图、类图等
  9. Python装饰器详解,详细介绍它的应用场景
  10. 10.26 第二次面试小感
  11. [投稿]Speex回声消除代码分析
  12. 2022年最新微博批量删除代码_自动化删除新浪微博代码
  13. 从零开始的《数据挖掘与大数据分析》课堂学习笔记-1 前言第一章“数据挖掘与大数据分析简介”片段
  14. 操作系统from清华大学向勇,陈渝 笔记(一)绪论
  15. 华为新机预装鸿蒙,华为新机来了!预装鸿蒙OS,搭载麒麟9000
  16. Matlab-RBF网络(径向基函数网络)-rbepnngrnn
  17. Scrapy(二)翻页功能
  18. linux qq java_Java实现QQ登陆界面
  19. 在线分享 Hosts 规则工具:Remote Hosts Server
  20. PS流详解(载荷H264)

热门文章

  1. [AMD驱动]解决AMD驱动的1603错误
  2. 涂料油漆化工进口报关
  3. python产生模拟数据——faker库的使用
  4. 平安科技java在线考试_平安科技笔试题.docx
  5. 专题八单元作业MATLAB图形用户界面设计答案
  6. 组件用.vue还是.js_一个Vue.js 2.0组件,用于生成首字母缩写或基于图像的头像
  7. 小米笔记本pro macOS Mojave使用体验
  8. 新的掌上游戏机,首款防作弊的开放式硬件设备以及更多游戏新闻
  9. 奥特曼系列ol服务器维修,奥特曼系列OL分解系统玩法介绍
  10. 1.1.1 计算机的四代变化与元件的更新换代