当前位置: 首页 > news >正文

树莓派学习专题<9>:使用V4L2驱动获取摄像头数据--设定分辨率和帧率

树莓派学习专题<9>:使用V4L2驱动获取摄像头数据--设定分辨率和帧率

  • 1. 设定分辨率
  • 2. 设定帧率
  • 3. 设定分辨率代码解析
  • 4. 获取与设定帧率代码解析
  • 5. 实测

1. 设定分辨率

使用如下代码设定摄像头的分辨率:

#define CAMERA_RESOLUTION_WIDTH    (         1280u)
#define CAMERA_RESOLUTION_HEIGHT   (          720u)
/*********************************************** other codes * ********************************************/
/*******************************************************************************
- Function    : __SetCameraResolution
- Description : 本函数设置摄像头输出格式。
- Input       : void
- Output      : null
- Return      : void
- Others      :
*******************************************************************************/
void __SetCameraResolution(void)
{struct v4l2_format     stFormat ;memset(&stFormat, 0, sizeof(stFormat)) ;/* 设置输出格式 */stFormat.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE ;stFormat.fmt.pix.width       = CAMERA_RESOLUTION_WIDTH ;stFormat.fmt.pix.height      = CAMERA_RESOLUTION_HEIGHT ;stFormat.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV ;             /* 根据需要的格式填写 */if(-1 == ioctl(g_iFDVideo, VIDIOC_S_FMT, &stFormat)) {printf("ioctl VIDIOC_S_FMT error.\n") ;exit(-1) ;}/* 检查设置效果 */stFormat.type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;if(-1 == ioctl(g_iFDVideo, VIDIOC_G_FMT, &stFormat)){printf("ioctl VIDIOC_G_FMT error.\n") ;exit(-1) ;}else{printf("--Set format result---------------------------------------\n") ;printf("-- Resolution width  : %d\n""-- Resolution height : %d\n""-- Pixel format      : %c%c%c%c\n",stFormat.fmt.pix.width, stFormat.fmt.pix.height,stFormat.fmt.pix.pixelformat & 0xFF,(stFormat.fmt.pix.pixelformat >> 8) & 0xFF,(stFormat.fmt.pix.pixelformat >> 16) & 0xFF,(stFormat.fmt.pix.pixelformat >> 24) & 0xFF);printf("----------------------------------------------------------\n\n\n") ;}return ;
}

2. 设定帧率

使用如下代码设定摄像头的输出帧率:

#define CAMERA_FPS                 (           30u)
/*********************************************** other codes * ********************************************/
/*******************************************************************************
- Function    : __SetCameraFPS
- Description : 本函数设置摄像头输出格式。
- Input       : void
- Output      : null
- Return      : void
- Others      :
*******************************************************************************/
void __SetCameraFPS(void)
{struct v4l2_streamparm stStreamParm ;stStreamParm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;/* 获取当前设置 */if(-1 == ioctl(g_iFDVideo, VIDIOC_G_PARM, &stStreamParm)){printf("ioctl VIDIOC_G_PARM error.\n") ;exit(-1) ;}else{printf("--Previous camera stream param----------------------------\n") ;printf("-- Capability        : %08x\n""-- Capturemode       : %08x\n""-- Numerator         : %d\n""-- Denominator       : %d\n",stStreamParm.parm.capture.capability, stStreamParm.parm.capture.capturemode, stStreamParm.parm.capture.timeperframe.numerator, stStreamParm.parm.capture.timeperframe.denominator) ;printf("----------------------------------------------------------\n\n\n") ;}/* 修改FPS */stStreamParm.parm.capture.timeperframe.numerator   = 1 ;stStreamParm.parm.capture.timeperframe.denominator = CAMERA_FPS ;if(-1 == ioctl(g_iFDVideo, VIDIOC_S_PARM, &stStreamParm)){printf("ioctl VIDIOC_S_PARM error.\n") ;exit(-1) ;}/* 获取新设置 */if(-1 == ioctl(g_iFDVideo, VIDIOC_G_PARM, &stStreamParm)){printf("ioctl VIDIOC_G_PARM error.\n") ;exit(-1) ;}else{printf("--Current camera stream param-----------------------------\n") ;printf("-- Capability        : %08x\n""-- Capturemode       : %08x\n""-- Numerator         : %d\n""-- Denominator       : %d\n",stStreamParm.parm.capture.capability, stStreamParm.parm.capture.capturemode, stStreamParm.parm.capture.timeperframe.numerator, stStreamParm.parm.capture.timeperframe.denominator) ;printf("----------------------------------------------------------\n\n\n") ;}    return ;
}

3. 设定分辨率代码解析

使用命令 VIDIOC_S_FMT 来设定输出格式。命令原型为:

#define VIDIOC_S_FMT		_IOWR('V',  5, struct v4l2_format)

可见,需要一个 v4l2_format 结构体。结构体的定义如下:

/*** struct v4l2_format - stream data format* @type:	enum v4l2_buf_type; type of the data stream* @pix:	definition of an image format* @pix_mp:	definition of a multiplanar image format* @win:	definition of an overlaid image* @vbi:	raw VBI capture or output parameters* @sliced:	sliced VBI capture or output parameters* @raw_data:	placeholder for future extensions and custom formats* @fmt:	union of @pix, @pix_mp, @win, @vbi, @sliced, @sdr, @meta* 	    and @raw_data*/
struct v4l2_format {__u32	 type;union {struct v4l2_pix_format		pix;     /* V4L2_BUF_TYPE_VIDEO_CAPTURE */struct v4l2_pix_format_mplane	pix_mp;  /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */struct v4l2_window		win;     /* V4L2_BUF_TYPE_VIDEO_OVERLAY */struct v4l2_vbi_format		vbi;     /* V4L2_BUF_TYPE_VBI_CAPTURE */struct v4l2_sliced_vbi_format	sliced;  /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */struct v4l2_sdr_format		sdr;     /* V4L2_BUF_TYPE_SDR_CAPTURE */struct v4l2_meta_format		meta;    /* V4L2_BUF_TYPE_META_CAPTURE */__u8	raw_data[200];                   /* user-defined */} fmt;
};

结构体中:
type 应指定为:V4L2_BUF_TYPE_VIDEO_CAPTURE
联合体中,使用 v4l2_pix_format。该结构体的定义如下:

struct v4l2_pix_format {__u32			width;__u32			height;__u32			pixelformat;__u32			field;		/* enum v4l2_field */__u32			bytesperline;	/* for padding, zero if unused */__u32			sizeimage;__u32			colorspace;	/* enum v4l2_colorspace */__u32			priv;		/* private data, depends on pixelformat */__u32			flags;		/* format flags (V4L2_PIX_FMT_FLAG_*) */union {/* enum v4l2_ycbcr_encoding */__u32			ycbcr_enc;/* enum v4l2_hsv_encoding */__u32			hsv_enc;};__u32			quantization;	/* enum v4l2_quantization */__u32			xfer_func;	/* enum v4l2_xfer_func */
};

这里主要填写 widthheightpixelformat三个成员。
width 指输出图像的宽度;
height指输出图像的高度;
pixelformat指输出图像的像素格式。根据需要填写 V4L2_PIX_FMT_XXXX

设置执行后,未必能执行成功。需要读出再检查。读出设置,使用 VIDIOC_G_FMT 命令。该命令的原型为:

#define VIDIOC_G_FMT		_IOWR('V',  4, struct v4l2_format)

返回值同样为 struct v4l2_format 类型。

4. 获取与设定帧率代码解析

使用命令 VIDIOC_G_PARM 来获取当前摄像头的参数(包含帧率)。该命令的原型是:

#define VIDIOC_G_PARM		_IOWR('V', 21, struct v4l2_streamparm)

该命令需要一个 struct v4l2_streamparm 类型的参数。

struct v4l2_streamparm {__u32	 type;			/* enum v4l2_buf_type */union {struct v4l2_captureparm	capture;struct v4l2_outputparm	output;__u8	raw_data[200];  /* user-defined */} parm;
};

对于摄像头,type 仍然填写 V4L2_BUF_TYPE_VIDEO_CAPTURE
联合体中,对于摄像头而言,应该取 struct v4l2_captureparm capture。该结构体的定义如下:

struct v4l2_captureparm {__u32		   capability;	  /*  Supported modes */__u32		   capturemode;	  /*  Current mode */struct v4l2_fract  timeperframe;  /*  Time per frame in seconds */__u32		   extendedmode;  /*  Driver-specific extensions */__u32              readbuffers;   /*  # of buffers for read */__u32		   reserved[4];
};

和帧率有关的是其中的结构体成员 struct v4l2_fract timeperframe 。其定义如下:

struct v4l2_fract {__u32   numerator;__u32   denominator;
};

参数 timeperframe ,意指每一帧图像的输出时间。成员 numerator (分子)和 denominator (分母)参数决定了具体的值。例如:

numerator   = 1
denominator = 30

则表明每一帧的时间为1/30秒,则相当于30fps输出。此外:

numerator   = 100
denominator = 3000

效果是一样的。
需要注意的是,摄像头未必能按照设定的参数来输出。主要有2点:

  1. 设置未必生效。如果设置的FPS过大,设置下去后,重新读回配置,会发现参数 numeratordenominator 被修改为一个受限制的值。
  2. 即使能够设置下去,输出帧率和硬件还有关系,例如,对于同一个CMOS,MIPI-CSI的2-lane和4-lane所能支持的最大帧率是不同的。

使用命令 VIDIOC_S_PARM 来设置设定的参数。命令的定义:

#define VIDIOC_S_PARM		_IOWR('V', 22, struct v4l2_streamparm)

同样还是需要结构体 struct v4l2_streamparm

同设定输出格式一样,也需要检查是否设定成功。

5. 实测

材料:

  1. Raspberry Pi 4B计算机;
  2. IMX219摄像头组件。
    运行上述代码,打印结果:
--Set format result---------------------------------------
-- Resolution width  : 1280
-- Resolution height : 720
-- Pixel format      : YUYV
------------------------------------------------------------Previous camera stream param----------------------------
-- Capability        : 00001000
-- Capturemode       : 00000000
-- Numerator         : 1000
-- Denominator       : 30000
------------------------------------------------------------Current camera stream param-----------------------------
-- Capability        : 00001000
-- Capturemode       : 00000000
-- Numerator         : 1
-- Denominator       : 30
----------------------------------------------------------

可以看到,在设置帧率之前, Numerator 参数和 Denominator参数,分别是1000和30000,即帧率是30fps。设置后仍然是30fps。
上述代码中,如果修改帧率设置:

numerator   = 1
denominator = 100

则打印信息为:

--Current camera stream param-----------------------------
-- Capability        : 00001000
-- Capturemode       : 00000000
-- Numerator         : 1
-- Denominator       : 90
----------------------------------------------------------

可见,Denominator 参数被修改为了90,相当于最大输出90fps。此时尝试连续捕获,最终计算帧率为:

FPS : 90.25 

相关文章:

  • Go设计模式-观察者模式
  • 【量化交易笔记】17.多因子的线性回归模型策略
  • JAVA---字符串
  • docker配置mysql遇到的问题:网络连接超时、启动mysql失败、navicat无法远程连接mysql
  • Nginx技术培训文档
  • 【Linux网络#1】:网络基础知识
  • strings.TrimLeft 使用详解
  • ssm乡村合作社商贸网站设计与实现(源码+lw+部署文档+讲解),源码可白嫖!
  • 网络流之最大流(Dinic)
  • 26考研——指令系统_CISC 和 RISC 的基本概念(4)
  • [详细无套路]MDI Jade6.5安装包下载安装教程
  • setup语法糖
  • AudioVideoMerger 下载与使用
  • ZBrush2025建模软件下载 ZBrush中文版免费下载 ZBrush版本大全
  • c++初始化数组
  • python输出
  • 利用知识图谱提升测试用例生成精准性:基于Graphiti与DeepSeek-R1的实战指南
  • 23种设计模式-行为型模式之迭代器模式(Java版本)
  • Redis数据结构SDS,IntSet,Dict
  • 【读论文】面向小目标的轻型变电设备缺陷检测算法
  • 学大教育:去年净利润1.797亿元,学习中心增加约60所
  • 泽连斯基与特朗普进行简短会谈
  • 航行警告!黄海南部进行实弹射击,禁止驶入
  • 文庙印象:一周城市生活
  • “两高”发布侵犯知产犯罪司法解释:降低部分犯罪入罪门槛
  • 民政部党组成员、中国老龄协会会长刘振国任民政部副部长