V4L2下摄像头的详细参数调整

本文详细介绍了Linux下V4L2的相关头文件路径,涉及摄像头参数如白平衡、曝光等的设置方法,以及常用的ioctl命令及其作用,包括VIDIOC_QUERYCAP、VIDIOC_ENUM_FMT、VIDIOC_QUERYCTRL等,并提供了实例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(Linux下V4L2相关头文件所在路径为/内核源码目录/include/linux/videodev2.h,V4L2相关API文档可查看链接https://linuxtv.org/downloads/v4l-dvb-apis/uapi/v4l/v4l2.html)

摄像头(相机)常见参数:
白平衡(自动白平衡AWB)及色温、曝光(自动曝光AE、曝光补偿EV)、亮度、对比度、饱和度、色度(色调+饱和度)、锐度(也叫清晰度)、背光补偿(也叫逆光补偿)、增益、对焦等

注:不同摄像头开放的参数不一致,需提前确认该款摄像头的可调参数,未开放的参数是无法调整的!!!

上述参数涵义如有不懂,可自行维基百科https://zh.wikipedia.org/wiki/Wikipedia:%E9%A6%96%E9%A1%B5和百度词条百度百科——全球领先的中文百科全书科普。

常见的 ioctl 命令:

VIDIOC_QUERYCAP     /* 获取设备支持的操作 */
VIDIOC_G_FMT             /* 获取设置支持的视频格式 */
VIDIOC_S_FMT             /* 设置捕获视频的格式 */
VIDIOC_REQBUFS       /* 向驱动提出申请内存的请求 */
VIDIOC_QUERYBUF    /* 向驱动查询申请到的内存 */
VIDIOC_QBUF              /* 将空闲的内存加入可捕获视频的队列 */
VIDIOC_DQBUF           /* 将已经捕获好视频的内存拉出已捕获视频的队列 */
VIDIOC_STREAMON      /* 打开视频流 */
VIDIOC_STREAMOFF    /* 关闭视频流 */
VIDIOC_QUERYCTRL    /* 查询驱动是否支持该命令 */
VIDIOC_G_CTRL         /* 获取当前命令值 */
VIDIOC_S_CTRL         /* 设置新的命令值 */
VIDIOC_G_TUNER     /* 获取调谐器信息 */
VIDIOC_S_TUNER      /* 设置调谐器信息 */
VIDIOC_G_FREQUENCY  /* 获取调谐器频率 */
VIDIOC_S_FREQUENCY  /* 设置调谐器频率 */

参数控制相关函数及结构体:

函数ioctl(fd,VIDIOC_QUERYCAP,struct v4l2_streamparm *argp);

用:查询设备能力

struct v4l2_capability {undefined
        __u8    driver[16];     /* i.e. "bttv" */
        __u8    card[32];       /* i.e. "Hauppauge WinTV" */
        __u8    bus_info[32];   /* "PCI:" + pci_name(pci_dev) */
        __u32   version;        /* should use KERNEL_VERSION() */
        __u32   capabilities;   /* Device capabilities */
        __u32   reserved[4];
};

举例:

 /*获取摄像头信息*/
    struct v4l2_capability cap;
 
    if (ioctl(cam_fd, VIDIOC_QUERYCAP, &cap) < 0)
    {
        perror("get info failed!");
        return -1;
    }
 
    printf("Driver Name:%s\n Card Name:%s\n Bus info:%s\n version:%d\n capabilities:%x\n \n ", cap.driver, cap.card, cap.bus_info,cap.version,cap.capabilities);
             
    if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == V4L2_CAP_VIDEO_CAPTURE)
    {
        printf("Device %s: supports capture.\n",DEV_NAME);
    }
    if ((cap.capabilities & V4L2_CAP_STREAMING) == V4L2_CAP_STREAMING)
    {
        printf("Device %s: supports streaming.\n",DEV_NAME);
    }

函数 int ioctl(fd, VIDIOC_ENUM_FMT, struct v4l2_fmtdesc *argp); 

作用:获取当前驱动支持的视频格式

struct v4l2_fmtdesc

{undefined
__u32 index; // 要查询的格式序号,应用程序设置
enum v4l2_buf_type type; // 帧类型,应用程序设置
__u32 flags; // 是否为压缩格式
__u8 description[32]; // 格式名称
__u32 pixelformat; // 格式
__u32 reserved[4]; // 保留
};

举例:

printf("【**********************所有支持的格式:****************************】\n"); 
struct v4l2_fmtdesc dis_fmtdesc; 
dis_fmtdesc.index=0; 
dis_fmtdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE; 
printf("Support format:\n"); 
while(ioctl(cam_fd,VIDIOC_ENUM_FMT,&dis_fmtdesc)!=-1) 
{ 
printf("\t%d.%s\n",dis_fmtdesc.index+1,dis_fmtdesc.description); 
dis_fmtdesc.index++;
} 
printf("\n");

函数ioctl(fd,VIDIOC_QUERYCAP,struct v4l2_queryctrl *argp);  

作用:用作查询某些参数的一些属性要求(如最大最小范围,默认值等)

struct v4l2_queryctrl {undefined
        __u32                id;
        enum v4l2_ctrl_type  type;
        __u8                 name[32];  /* Whatever */
        __s32                minimum;   /* Note signedness */
        __s32                maximum;
        __s32                step;
        __s32                default_value;
        __u32                flags;
        __u32                reserved[2];
};

函数ioctl(fd,VIDIOC_G_FMT,struct v4l2_format *argp);  //VIDIOC_S_FMT

作用:分辨率、图像采集格式相关设置

struct v4l2_format {undefined
        enum v4l2_buf_type type;
        union {undefined
                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 */
                __u8    raw_data[200];                   /* user-defined */
        } fmt;
};

举例:

printf("【**********************获取当前格式信息:****************************】\n");
    Format.type= V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if(ioctl(cam_fd,VIDIOC_G_FMT,&Format)==-1)
    {
        perror("ioctl");
        exit(EXIT_FAILURE);
    }
    printf(">>:  %d * %d\n",Format.fmt.pix.width,Format.fmt.pix.height);
    printf("pix.pixelformat:%c%c%c%c\n", \
            Format.fmt.pix.pixelformat & 0xFF,\
            (Format.fmt.pix.pixelformat >> 8) & 0xFF, \
            (Format.fmt.pix.pixelformat >> 16) & 0xFF,\
            (Format.fmt.pix.pixelformat >> 24) & 0xFF);
    printf("\n");

函数ioctl(fd,VIDIOC_G_PARM,struct v4l2_streamparm *argp);  //VIDIOC_S_PARM

作用:流相关 (如帧率)

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

举例:

printf("【***********************获取帧率信息**************************】\n");
 
struct v4l2_streamparm Stream_Parm;
 
Stream_Parm.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
if(ioctl(cam_fd,VIDIOC_G_PARM,&Stream_Parm)==-1)
 
{
 
perror("ioctl");
 
exit(EXIT_FAILURE);
 
}
 
printf(">>: Frame rate: %u/%u\n",Stream_Parm.parm.capture.timeperframe.numerator,Stream_Parm.parm.capture.timeperframe.denominator);
 
printf("\n");

函数ioctl(fd,VIDIOC_G_CTRL,struct v4l2_control*argp);  //VIDIOC_S_CTRL

作用:参数控制(白平衡、色温、对比度、饱和度、锐度、曝光等,均有该结构控制)

struct v4l2_control {undefined
        __u32                id;        //id即要控制的参数id(例白平衡ID为V4L2_CID_AUTO_WHITE_BALANCE)
        __s32                value;  
};

举例:

    printf("【**********************设置手动白平衡:******************************】\n");
    ctrl.id = V4L2_CID_AUTO_WHITE_BALANCE;
    ctrl.value = V4L2_WHITE_BALANCE_MANUAL ;
    if(ioctl(cam_fd,VIDIOC_G_CTRL,&ctrl)==-1)
    {
        perror("ioctl");
        exit(EXIT_FAILURE);
    }
    printf("\n");    
 
    /*************设置白平衡色温****************************/
    printf("【****************设置白平衡色温********************】\n");
    ctrl.id = V4L2_CID_WHITE_BALANCE_TEMPERATURE;
    ctrl.value = 5100;
     if(ioctl(cam_fd,VIDIOC_S_CTRL,&ctrl)==-1)
    {
        perror("ioctl");
        exit(EXIT_FAILURE);
    }
    printf("\n");
 
    printf("【***************设置亮度***************************】\n");
    ctrl.id= V4L2_CID_BRIGHTNESS;
    ctrl.value = 40;
    if(ioctl(cam_fd,VIDIOC_S_CTRL,&ctrl)==-1)
    {
        perror("ioctl");
        exit(EXIT_FAILURE);
    }
    printf("\n");
 
    printf("【***************设置对比度**************************】\n");
    ctrl.id = V4L2_CID_CONTRAST;
    ctrl.value= 45;
    if(ioctl(cam_fd,VIDIOC_S_CTRL,&ctrl)==-1)
    {
        perror("ioctl");
        exit(EXIT_FAILURE);
    }
    sleep(1);
    printf("\n");
 
    printf("【***************设置饱和度**************************】\n");
    ctrl.id = V4L2_CID_SATURATION;
    ctrl.value= 60;
    if(ioctl(cam_fd,VIDIOC_S_CTRL,&ctrl)==-1)
    {
        perror("ioctl");
        exit(EXIT_FAILURE);
    }
    printf("\n");
 
    printf("【********************设置色度**********************】\n");
    ctrl.id = V4L2_CID_HUE;
    ctrl.value = 1;
    if(ioctl(cam_fd,VIDIOC_S_CTRL,&ctrl)==-1)
    {
        perror("ioctl");
        exit(EXIT_FAILURE);
    }
    printf("\n");
 
    printf("【********************设置锐度**********************】\n");
    ctrl.id = V4L2_CID_SHARPNESS;
    ctrl.value = 4;
    if(ioctl(cam_fd,VIDIOC_S_CTRL,&ctrl)==-1)
    {
        perror("ioctl");
        exit(EXIT_FAILURE);
    }
    printf("\n");
 
    
    printf("【*******************设置背光补偿******************】\n");
    ctrl.id = V4L2_CID_BACKLIGHT_COMPENSATION;
    ctrl.value = 3;
    if(ioctl(cam_fd,VIDIOC_S_CTRL,&ctrl)==-1)
    {
        perror("ioctl");
        exit(EXIT_FAILURE);
    }
    printf("\n");
 
    printf("【********************设置伽玛值**********************】\n");
    ctrl.id = V4L2_CID_GAMMA;
    ctrl.value = 120;
    if(ioctl(cam_fd,VIDIOC_S_CTRL,&ctrl)==-1)
    {
        perror("ioctl");
        exit(EXIT_FAILURE);
    }
    printf("\n");

设置曝光值

1. 首先将曝光模式修改为手动曝光。

2. 设置曝光档次或者具体的曝光值。

例1:得到曝光模式,设置为手动曝光模式

int ret;
struct v4l2_control ctrl;
//得到曝光模式
ctrl.id = V4L2_CID_EXPOSURE_AUTO;
ret = ioctl(Handle, VIDIOC_G_CTRL, &ctrl);
 
if (ret < 0) 
{
    printf("Get exposure auto Type failed\n");
 
    return V4L2_UTILS_GET_EXPSURE_AUTO_TYPE_ERR;
}
 
printf("\nGet Exposure Auto Type:[%d]\n", ctrl.value);

//设置曝光模式为手动模式

ctrl.id = V4L2_CID_EXPOSURE_AUTO; 
ctrl.value = V4L2_EXPOSURE_MANUAL;  //手动曝光模式
ret = ioctl(Handle, VIDIOC_S_CTRL, &ctrl); 
if (ret < 0) 
{
   printf("Get exposure auto Type failed\n"); 
 
   return V4L2_UTILS_SET_EXPSURE_AUTO_TYPE_ERR; 
 
}

例2:在设置为手动模式后,再得到和设置曝光等级

int ret; 
struct v4l2_control ctrl; 
ctrl.id = V4L2_CID_EXPOSURE;  //得到曝光档次,A20接受从 -4到4 共9个档次
ret = ioctl(Handle, VIDIOC_G_CTRL, &ctrl); 
if (ret < 0) 
{ 
    printf("Get exposure failed (%d)\n", ret); 
    return V4L2_UTILS_GET_EXPSURE_ERR; 
} 
 
printf("\nGet Exposure :[%d]\n", ctrl.value);
 
//设置曝光档次
ctrl.id = V4L2_CID_EXPOSURE; 
ctrl.value = -4; 
ret = ioctl(Handle, VIDIOC_S_CTRL, &ctrl); 
if (ret < 0) 
{ 
    printf("Set exposure failed (%d)\n", ret); 
    return V4L2_UTILS_SET_EXPSURE_ERR; 
} 

例3:在设置为手动模式后,再得到和设置曝光绝对值:

int ret;
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_EXPOSURE_ABSOLUTE;
ret = ioctl(handle, VIDIOC_G_CTRL, &ctrl);
if (ret < 0) 
{
    printf("Set exposure failed (%d)\n", ret);
 
    //return V4L2_UTILS_SET_EXPSURE_ERR;
}
 
printf("\nGet ABS EXP Success:[%d]\n", ctrl.value);
 
sleep(1);
 
//设置曝光绝对值
ctrl.id = V4L2_CID_EXPOSURE_ABSOLUTE;
ctrl.value = 300;  //单位100us
ret = ioctl(handle, VIDIOC_S_CTRL, &ctrl);
if (ret < 0) 
{
    printf("Set exposure failed (%d)\n", ret);
 
    //return V4L2_UTILS_SET_EXPSURE_ERR;
}

( 以上参数经过测试均能有效设置,但曝光、自动对焦、增益无法设置通过,会出现ioctl: Invalid argument问题,原因未知,如有朋友知晓,诚请赐教,在此先行谢过)。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值