如何将DMA-BUF文件描述符导入OpenCV的cv::Mat?
将libcamera的DMA-BUF文件描述符导入OpenCV的cv::Mat
当然可以实现,核心是通过内存映射或硬件加速接口将DMA-BUF的共享内存关联到OpenCV的矩阵结构,以下是两种实用方案:
方案一:用户空间内存映射(CPU处理)
DMA-BUF本质是内核态的共享内存,通过mmap可以将其映射到用户空间,再基于映射后的内存创建cv::Mat。需要提前明确图像的像素格式、宽高、每个plane的stride(行字节数),这些信息可从libcamera的FrameBuffer和StreamConfiguration中获取。
示例代码(以YUV420格式为例)
#include <fcntl.h> #include <sys/mman.h> #include <opencv2/opencv.hpp> // 从libcamera获取的参数 int fd = frameBuffer->plane(0).fd.get(); // 第一个plane的DMA-BUF文件描述符 int width = streamConfig.size.width; int height = streamConfig.size.height; size_t stride = frameBuffer->plane(0).stride; size_t planeSize = frameBuffer->plane(0).length; // 映射DMA-BUF到用户空间 void* mappedData = mmap(nullptr, planeSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (mappedData == MAP_FAILED) { perror("mmap failed"); return; } // 创建cv::Mat(YUV420为单通道8位格式) cv::Mat yuvMat(height + height/2, width, CV_8UC1, mappedData, stride); // 转换为OpenCV常用的BGR格式 cv::Mat bgrMat; cv::cvtColor(yuvMat, bgrMat, cv::COLOR_YUV2BGR_I420); // 使用完后释放映射 munmap(mappedData, planeSize);
注意:如果是多plane格式(比如YUV420的U/V plane分别在不同DMA-BUF),需要分别映射每个plane,再通过cv::merge或直接构造多通道Mat处理。
方案二:CUDA硬件加速(GPU处理)
如果设备支持CUDA,可直接将DMA-BUF注册到CUDA内存空间,避免内存拷贝,提升效率:
示例代码
#include <opencv2/cudaarithm.hpp> #include <opencv2/cudaimgproc.hpp> // 注册DMA-BUF到CUDA cv::cuda::GpuMat gpuMat; cv::cuda::registerBuffer(gpuMat, fd, width, height, CV_8UC1, stride); // GPU端直接转换格式 cv::cuda::GpuMat gpuBgrMat; cv::cuda::cvtColor(gpuMat, gpuBgrMat, cv::COLOR_YUV2BGR_I420); // 下载到CPU端的cv::Mat(按需使用) cv::Mat bgrMat; gpuBgrMat.download(bgrMat); // 注销缓冲区 cv::cuda::unregisterBuffer(gpuMat);
关键注意事项
- 必须匹配libcamera输出的像素格式与OpenCV的格式转换参数,比如
COLOR_YUV2BGR_I420对应YUV420 planar格式,若输出为RGB格式则无需转换。 - 确保DMA-BUF的文件描述符在使用期间保持有效,避免提前关闭。
- 多plane格式需要分别处理每个plane的fd、stride和size,比如YUV420的U/V plane高度为原高度的1/2,宽度为原宽度的1/2。
内容的提问来源于stack exchange,提问作者Newbyte
相关产品推荐
相关产品推荐

