Gstreamer使用mipi csi摄像头,转码成BGR格式的cv::Mat

您所在的位置:网站首页 质谱仪电路图怎么看 Gstreamer使用mipi csi摄像头,转码成BGR格式的cv::Mat

Gstreamer使用mipi csi摄像头,转码成BGR格式的cv::Mat

2024-07-18 04:16:02| 来源: 网络整理| 查看: 265

硬件平台:致远M1808 AI核心板

阅读本博客需要有对gstreamer基础知识的了解,这里给出学习链接:

GStreamer系列 - 基本介绍 - John.Leng - 博客园

在做项目时,需要增加对多路mipi csi摄像头图像获取的支持,以往使用的ffmpeg无法支持该转接板转接的mipi csi摄像头。于是便有了本博客,权当记录啦~

1.可行性验证

使用gst-lauch-1.0验证管道连接和输出帧是否正常:

gst-lauch-1.0 v4l2src device=/dev/video3 ! video/x-raw,format=NV16,width=1280,height=720,framerate=5/1 ! queue ! videoconvert ! waylandsink

可以看到这个pipeline由4个element元件构成,每个element都实现各自的功能:

v4l2src 读取摄像头queue 缓存数据videoconvert 转换video数据格式waylandsink 获取到的数据传输给致远桌面桌面/etc/init.d/S50launcher进行屏幕输出

其中:

“device=/dev/video3”紧跟着v4l2src意为给v4l2src组件成员device赋值,用于指定摄像头设备路径。

“video/x-raw,format=NV16,width=1280,height=720,framerate=5/1”意为通过Cap来指定数据类型

需要注意的是我手上的硬件转接板获取到的图像数据是NV16格式的,也就是YUV422SP格式,不同硬件可能格式不一样。

最后的waylandsink可以换成appsink,用于在程序中我们自己获取帧,而不是通过waylandsink来进行显示,该例子只用于进行读取摄像头可行性的验证。

2.代码实现

根据上面验证了读取该摄像头的可行性并确定了各element元件进行实现:

伪代码如下:

/* * 初始化gstreamer * 若无初始化值可以传入NULL,NULL * 一般情况下初始化不需要参数 */ gst_init (*argc, **argv[]); /* * 使用gstreamer工厂创建各个element元件 * 函数第一个参数为元件型别名,gstreamer根据该元件型别名成查找对应元件 * 第二个参数为用户自定义的该元件的名称 */ GstElement * v4l2src = gst_element_factory_make ("v4l2src", "source"); GstElement * queue = gst_element_factory_make("queue","Queue"); GstElement * videoconvert = gst_element_factory_make("videoconvert","Videoconvert"); GstElement * appsink = gst_element_factory_make ("appsink","sink"); //创建管道头,输入参数为自定义的管道名称 GstElement * pipeline = gst_pipeline_new ("mipi-pipeline"); /* * 连接各个element元件前需要先确定创建出来的指针是否为空 * 如果为空说明gstreamer未找到对应的element元件 * 判断是否创建成功略 */ //调用g_object_set来设置v4l2src的device组件指定摄像头路径 std::string capturePath = "..."; g_object_set (v4l2src, "device", capturePath.data() , NULL); /* * 当前当前致远M1808上使用的N4转接板接AHD摄像头获取到的数据规格为 * video/x-raw,format=NV16,width=1280,height=720,framerate=5/1 * 其他转接板接AHD摄像头获取到的数据规格暂不明晰,该数据规格必须准确,否则会导致gstreamer初始化出错 */ std::string capInfo = "video/x-raw,format=NV16,width=1280,height=720,framerate=5/1"; gchar * video_caps_text = g_strdup_printf (capInfo.data()); //gst_caps_from_string通过Cap来指定数据类型,设置v4l2src输出格式 GstCaps * video_caps = gst_caps_from_string (video_caps_text); //video_caps需要进行是否为空判断,这里略 //把appsink的emit-signals属性打开,才能收到管道发出的new-sample信号,同时设置输出视频格式 g_object_set(appsink, "emit-signals", TRUE, "caps", video_caps, NULL); /* * 设置监听new-sample和回调函数get_sample,&gstData是传给回调函数的参数 * 注意必须使用静态函数来实现回调:static GstFlowReturn get_sample(GstElement *sink, GstreamerMipiData *gstData); * 回调里使用&gstData进行与外部通讯 */ g_signal_connect (appsink, "new-sample", G_CALLBACK (get_sample), &gstData); //把所有元件放入管道里 gst_bin_add_many (GST_BIN (pipeline), v4l2src,queue,videoconvert,appsink, NULL); /* * 连接各个元件,注意顺序不能错 * 参数数量可变,以NULL作为结束标志 * 需要判断返回值是不是false,这里略 */ gst_element_link_many (v4l2src,queue,videoconvert,appsink, NULL); //至此管道各元件初始化完成并已完成连接 //并已设定回调函数 /* * 完成初始化和各个element元件连接和设定appsink new-sample信号的回调后 * 开启循环防止管道被释放掉资源而停止 */ //开启循环略,当前项目中为开启一个循环判断是否暂停和重启线程 //gst_element_set_state(GstElement* , GST_STATE_*)启动管道开始工作,可设置GST_STATE_PAUSED暂停 //gstreamer中管道状态枚举源码定义: typedef enum { GST_STATE_VOID_PENDING = 0, GST_STATE_NULL = 1, GST_STATE_READY = 2, GST_STATE_PAUSED = 3, GST_STATE_PLAYING = 4 } GstState; gst_element_set_state (pipeline, GST_STATE_PLAYING); /* * gstreamer中,管道的工作状态不能跳变 * GST_STATE_VOID_PENDING: 没有等待状态,这只是作为一个枚举的起始 * GST_STATE_NULL: 默认状态,该状态将会回收所有被该元件占用的资源。 * GST_STATE_READY: 准备状态,元件会得到所有所需的全局资源,这些全局资源将被通过该元件的数据流所使用。 * GST_STATE_PAUSED: 在这种状态下,元件已经对流开始了处理,但此刻暂停了处理。 * GST_STATE_PLAYING: PLAYING 状态除了当前运行时钟外,其它与 PAUSED 状态一模一样。 * 状态切换: * VOID_PENDING NULL READY PAUSED PLAYING */ /* * 前面提到GsreamerCameraReader::get_sample回调函数 * appsink在收到一帧会发出new-sample信号,此时get_sample会被调用 * get_sample定义为:static GstFlowReturn get_sample (GstElement *sink, GstreamerMipiData *gstData); * sink可取出帧进行处理 -> gstData为外部指针 */ GstFlowReturn GsreamerCameraReader::get_sample (GstElement *sink, GstreamerMipiData *gstData){ //从sink中取帧数据到GstSample * sample g_signal_emit_by_name (sink, "pull-sample", &gstData->outData.sample); //从gstData获取图像的宽高信息,这里略 //获取一帧buffer,这个buffer是无法直接用的,它不是char类型 //gstData->outData.buff型别为 GstBuffer * gstData->outData.buff = gst_sample_get_buffer (gstData->outData.sample); //把buffer映射到map,就可以通过map.data取到buffer的数据 //gstData->outData.map型别为 GstMapInfo map //需要判断映射返回是否为true,这里略 gst_buffer_map (gstData->outData.buffer, &gstData->outData.map, GST_MAP_READ) //这样就取出了一帧NV16格式的像素数据,map.data取到的就是该像素数据,opencv中没有提供NV16转BGR //由于获取到的是NV16也就是YUV422SP格式数据,opencv中没有转码NV16格式的方法 //需要先将NV16转NV12,再使用CV_YUV2BGR_NV12转成BGR //先创建NV12格式的cv::Mat用于后续操作,使用cv::create创建一个高为原来3/2,宽不变,通道为1的cv::Mat存储 gstData->outData.nv12Img.create(gstData->outData.height * 3 / 2, gstData->outData.width, CV_8UC1); //将NV16转NV12 nv16_to_nv12(gstData->outData.map.data , gstData->outData.nv12Img.data , gstData->outData.width , gstData->outData.height); 使用CV_YUV2BGR_NV12将NV12转成BGR cv::cvtColor(gstData->outData.nv12Img, gstData->outData.bgrImg , CV_YUV2BGR_NV12); //这样,解析完成的BGR格式的cv::Mat就保存在gstData->outData.bgrImg中 //资源释放、抽帧和返回这里略 }

源码链接:

https://download.csdn.net/download/qq_42711516/88670221



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


    图片新闻

    实验室药品柜的特性有哪些
    实验室药品柜是实验室家具的重要组成部分之一,主要
    小学科学实验中有哪些教学
    计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
    实验室各种仪器原理动图讲
    1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
    高中化学常见仪器及实验装
    1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
    微生物操作主要设备和器具
    今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
    浅谈通风柜使用基本常识
     众所周知,通风柜功能中最主要的就是排气功能。在

    专题文章

      CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭