本篇博客主要介绍Linux下的V4L2库以及利用v4l2-ctl
命令访问相机的基本操作。最后我们来探究一个问题:如何获得普通USB相机的Raw影像数据。
1.什么是V4L2
V4L是Video For Linux的缩写,V4L2则是V4L的第二个版本,其官网是这里,官方文档是这里。这里我们不涉及复杂的介绍,只是简单说明。V4L2库是Linux内核提供给应用程序访问音视频驱动的统一接口,提供了一整套设备驱动和API的合集,让应用程序和用户可以方便的访问USB相机等各种设备,其被广泛用于多媒体开发等应用。如果对具体开发感兴趣,可以参考这个网页、这个网页、这个网页。
上图展示了V4L2与相机有关的架构图。图片来自这里,感兴趣可以查看更多内容。
我们当然可以使用V4L2进行编程开发,但其也提供了一系列命令行工具,使我们可以方便地和硬件进行交互,v4l2-ctl
便是其中之一。通过v4l2-ctl
配合不同的参数,使得我们可以获得和设置很多内容。
2.V4L2的安装
V4L2本身并不需要特别的安装,而v4l2-ctl
作为V4L2的用户端,需要单独安装一下。我们可以通过apt-get install v4l-utils
进行安装。安装完成后,在终端中输入v4l2-ctl
,如果出现如下输出,就说明安装成功了。
3.v4l2-ctl的常用参数
v4l2-ctl
有很多有用的参数,这里简单列举一下,方便查阅。完整的参数可以输入v4l2-ctl --help-all
获得。
设备列举与基本属性相关:
--list-devices
: 列出所有可用的视频设备-d
: 指定要使用的目标设备(默认为/dev/video0
),如-d /dev/video1
-D
: 输出设备的驱动信息--all
: 输出设备的所有信息
下图展示了打印可用设备以及输出/dev/video0
信息的效果。
相机控制相关:
-L
: 输出当前设备支持的控制选项--set-ctrl
: 用于设置不同选项的值,例如--set-ctrl contrast=40
下图展示了当前相机设备支持的控制选项、设置范围、精度、默认值等信息。
输出影像相关:
--list-formats-ext
: 输出设备所支持的像素格式、分辨率、帧率等信息--set-parm
: 设置帧率,如--set-parm=30
--set-fmt-video
:设置视频的分辨率等,如--set-fmt-video=width=640,height=480
--set-count
: 设置缓冲/拍摄的帧数,如--set-count=1
--stream-mmap
: 设置使用mmap()函数进行缓冲--stream-to
: 设置视频流的存储路径,如--stream-to=/root/test.jpg
--verbose
: 输出拍摄过程中一系列信息,以方便调试
下图展示了本机所支持的一些输出格式。
4.v4l2-ctl的常用模式
4.1 相关信息输出
v4l2-ctl --list-devices; v4l2-ctl -L; v4l2-ctl --list-formats-ext
在控制台中输入上述命令,系统就会输出一系列的硬件信息,如下所示。
4.2 拍摄单张影像
下面是利用上面介绍过的参数拍摄单张影像的命令。
v4l2-ctl --set-fmt-video=width=960,height=540,pixelformat=JPEG --stream-mmap --stream-count=1 --stream-to=test.jpg
运行之后就会得到一张960×540的影像。这时候你可能会好奇,如果设置的分辨率超过了上面提到的相机最大分辨率会怎么样。答案是相机会按照它所能拍摄的最大分辨率拍一张影像。而还有一种情况是,任意指定了一个大小,真的会得到指定大小的影像吗?答案是否定的。例如我们指定960×440,但最后会得到一个848×480的影像。这是因为相机会自动根据你指定的大小,寻找一个最相近的支持的模式,然后拍摄并返回给你照片。例如在这里,我们指定的960×440共有约42万像素,相机就会去支持的模式中寻找,960×540约为52万像素,下一级是848×480约为41万像素。所以相机就选择了848×480分辨率进行拍摄。其它参数如果不支持,类似的,系统也会寻找最相近的配置。
4.3 拍摄多张影像
下面展示利用v4l2-ctl
以30帧每秒拍摄300张640×480影像的命令。
v4l2-ctl --set-parm=30;v4l2-ctl --set-fmt-video=width=640,height=480,pixelformat=JPEG --stream-mmap --stream-count=300 --stream-to=pics@30fps.jpeg
下面是利用gst-play
命令回放刚刚拍摄的影像的命令。
gst-play-1.0 pics@30fps.jpeg --videosink="videorate ! video/x-raw, framerate=(fraction)30/1 ! autovideosink"
需要注意的是,这里虽然看起来保存为一个.jpeg
文件,但其实里面是有多张影像帧数据的,而非只是一张。如果把文件后缀改成.mp4
就可以看到动图了(因为没有时间编码所以播放速度不对)。
5.v4l2-ctl获取Raw数据
在本文的一开头,我们就提出了一个问题:如何获得普通USB相机的Raw影像数据。在回答这个问题之前,我们首先要明确一个问题,到底我们认为什么是Raw数据,是未经任何处理的Bayer Raw数据,还是YUV或者未压缩的影像。关于这个问题的讨论可以参考这篇博客。这里我们认为Raw数据是Bayer Raw数据,以此为前提进行讨论。当然这里需要说明的是YUV等这种数据格式并非真正的Bayer Raw数据,所以即使有些相机可以输出非RGB格式的数据也并不代表其可以输出Bayer Raw数据。比如,我们利用OpenCV直接输出一些YUV格式的数据,可以参考这篇博客,在其给出代码的基础上,只需要再指定cv2.CAP_PROP_CONVERT_RGB
属性为False即可。
这里先给出结论:从软件层面而言,V4L2具备获取Bayer Raw数据的能力,且提供了一套统一的接口支持数据的读写;从硬件层面而言,不是所有的USB相机都支持输出Bayer Raw数据。因此,如果硬件不支持,即便使用V4L2,也没办法获得Bayer Raw数据。而某个相机是否支持Bayer Raw输出,则需要具体传感器具体分析。例如Leopard Imaging(高清嵌入式相机设计和制造领域的全球领导者)的几款相机传感器支持Raw数据输出。具体点例如Leopard Imaging的LI-USB30-M021X相机,其用的是Onsemi(一家中国半导体公司,叫安森美)的MT9M021 CMOS影像传感器。进一步,我在Onsemi的官网上找到了这个传感器的有关信息,点击这里可以下载PDF,获得更多相关信息。又例如OmniVision(豪威,美国半导体公司)的OV7251传感器,同样支持Raw数据输出。官方的参数PDF文件点击下载。如下可以看到,其中提到了输出数据类型,包含10bit的黑白Raw数据(和上面的Bayer Raw有区别)。
最后,感兴趣可以查看这个网页,里面总结了很多相机传感器的型号以及对应的输出数据类型。
而如何知道某个USB相机是否支持Bayer Raw输出呢?有两种方法,第一种就是直接根据相机型号在网上查询,找到该型号传感器的Specification,里面一般都会有提到。或者第二种方法利用4.1部分提到的命令进行查询,看相机支持输出的模式里有没有”Raw”相关的字眼,如果有的话则说明支持Bayer Raw输出。但这并非一定正确,有些相机可能v4l2-ctl
查询并没有”Raw”相关的输出模式,但是却可以通过定制的程序或驱动实现Bayer Raw数据输出,一个典型的例子是树莓派的相机。例如我们利用v4l2-ctl --list-formats-ext
查询树莓派相机V2所支持的输出格式,如下。
可以看到其并没有支持Raw的模式,但我们却可以通过raspistill -r
实现Bayer Raw的输出(更多信息见这篇博客),所以这个方法也并不一定完全有效。关于这个问题,也有人做了进一步的探讨,有人说树莓派相机有两套驱动,通用驱动无法获得Bayer Raw数据,只有通过专有驱动才可以获得。具体可以参考这个和这个网页。
甚至如这个网页中提到的,还可能出现传感器说是给出YUV输出,但其实是Bayer Raw数据的问题,所以实际情况比较复杂,可能需要具体传感器具体分析。
到这里,我们假设已经有了一个支持Bayer Raw数据输出的相机,那么如何利用v4l2-ctl
进行Bayer Raw数据输出呢?参考这个网页与这个网页,与4.2部分的命令类似的,只需要在编码格式的参数中稍作修改即可,如下。
v4l2-ctl -d /dev/video0 --set-fmt-video=width=3280,height=2464,pixelformat=RGGB --stream-mmap --stream-count=1 --stream-to=test.raw --verbose
这里RGGB表示相机支持的Raw数据的名称,不同的相机可能名称不同,可以利用4.1部分的命令查询。比如在我的树莓派上跑这个命令,输出结果如下。
可以看到,相机并不支持RG10这种输出模式,所以采用了YUV420的格式,事实上这并非是我们想要的Bayer Raw格式。如果我们强行用Rawpy进行解析,就会报错,提示我们这是一个未支持的RAW文件。
由于我手边并没有能够输出Raw数据的相机传感器,所以也没有办法做进一步测试。更多内容可以参考这个网页、这个网页、这个网页、这个网页、这个网页。如果之后手边有了可以输出Bayer Raw的传感器再做进一步测试。
6.参考资料
- [1] http://www.linuxtv.org/
- [2] https://www.linuxtv.org/downloads/v4l-dvb-apis-new/userspace-api/v4l/v4l2.html
- [3] https://silencewt.github.io/2015/04/29/v4l2%E7%9A%84%E5%AD%A6%E4%B9%A0%E5%BB%BA%E8%AE%AE%E5%92%8C%E6%B5%81%E7%A8%8B%E8%A7%A3%E6%9E%90/
- [4] https://www.cnblogs.com/vedic/p/10763838.html
- [5] https://blog.csdn.net/zz531987464/article/details/83350670
- [6] https://wiki.stmicroelectronics.cn/stm32mpu/wiki/V4L2_camera_overview
- [7] https://www.baidu.com/link?url=Rf7V6OqXgI0xD7vtIChNRaW4j3QCkYyivclA5vQczZd3gjYmk8qd-qgRqe9vuWxCxftltuiWLQ6paZTV7ZtQYq&wd=&eqid=c5a44d46000a390c00000005614c8600
- [8] https://www.ovt.com/download/sensorpdf/146/OmniVision_OV7251.pdf
- [9] https://cloud.tencent.com/developer/article/1173207
- [10] https://raspberrypi.stackexchange.com/questions/130865/does-v4l2-driver-support-raw-bayer-capture-with-hq-camera
- [11] https://www.raspberrypi.org/forums/viewtopic.php?t=221203
- [12] https://forums.developer.nvidia.com/t/how-to-handle-raw-from-usb-cameras/45394
- [13] https://github.com/RidgeRun/NVIDIA-Jetson-IMX477-RPIV3/issues/19 https://forums.developer.nvidia.com/t/viewing-raw-bayer-data/45227
- [14] https://www.e-consystems.com/5MP-OV5680-MIPI-Camera-Module-FAQ.asp
- [15] https://community.nxp.com/t5/i-MX-Processors/Command-to-capture-video-or-image-for-10-RGB-layer-with-OV4689/m-p/1077548
- [16] https://blog.csdn.net/hanmengaidudu/article/details/76671438
- [17] http://credentiality2.blogspot.com/2017/01/nvidia-jetson-tx1-raw-bayer-frames-via.html
- [18] https://forum.videohelp.com/threads/367373-Looking-for-Raw-RGB-video-camera-source
- [19] https://www.jianshu.com/p/20d4b81f8d14