实际应用中我们需要调整摄像头的参数比如曝光,由于opencv的后端是一般编译是支撑多种插件,详细信息请参考OpenCV: Video I/O with OpenCV Overview,这里引用里面的图:
对于VideoCaputure,后端有ffmpge,V4L,DShow等,opencv并没有完全用统一参数来屏蔽后端的差异性,也就是部分参数需要依据选择的后端来确定是否实现或者参数范围。
你可以通过下面命令查看当前opencv编译支撑了哪些后端:
C++ : cout<<cv::getBuildInformation()<<endl;
Python: cv2.getBuildInformation()
以opencv修改曝光参数为例,常见的python代码形式如下:
vs.stream.set(cv2.CAP_PROP_AUTO_EXPOSURE,0.25) #选择手动曝光
vs.stream.set(cv2.CAP_PROP_EXPOSURE,-4) #设置曝光参数
这个代码在windows上可以正常修改曝光,但是linux可能报错(依据缺省的后端),出现类似下面的错误:
GStreamer warning: unhandled property: 15
这是因为linux下缺省用有时候是gstreamer做后端,而该接口没有实现曝光调整,如需让曝光有效,在linux平台需要强制使用V4L的后端,即在创建caputure时候通过参数指定:
cv::VideoCapture cap(0, cv::CAP_V4L);
指定V4L作为后端,则对应的参数范围也要做调整,在我的系统下测试切换曝光方式和设置曝光值都需要改变,常见的曝光参数都是负值,而V4L则需要传入标准正的值(见文档后面的曝光参数说明),你可以用v4l2-ctl 查看值的范围和当前值,下面方式是我实测有效的方法,其中os为nt表示是windows下的设置,缺省认为是linux系统
if os.name =='nt':
vs = VideoStream(src=1).start()
vs.stream.set(cv2.CAP_PROP_AUTO_EXPOSURE,0.25)
vs.stream.set(cv2.CAP_PROP_EXPOSURE,-4)
else:
v=VideoStream(src=0).stream
time.sleep(0.5)
v.stream.set(cv2.CAP_PROP_FRAME_WIDTH,640) #
v.stream.set(cv2.CAP_PROP_FRAME_HEIGHT,480)#
v.stream.set(cv2.CAP_PROP_AUTO_EXPOSURE,1.0)
v.stream.set(cv2.CAP_PROP_EXPOSURE,500)
vs=v.start()
Python系统中如果使用imutils.video,其并没有提供切换到v4l的对外接口,可采用强制修改的方式实现,见下面红色部分(需根据自己python实际情况调整):
sudo vi /usr/local/lib/python3.9/dist-packages/imutils/video/webcamvideostream.py 强制改变后端模式:
# from the stream
#self.stream = cv2.VideoCapture(src)
self.stream = cv2.VideoCapture(src,cv2.CAP_V4L)
(self.grabbed, self.frame) = self.stream.read()
此外在打开摄像头和开始操作需要延时一下,否则出现下面错误:
requestBuffers VIDEOIO(V4L2:/dev/video0): failed VIDIOC_REQBUFS: errno=16 (Device or resource busy),出现这个错误后面就无法获取图像数据了。
曝光参数说明:
负值对应关系表
(计算公式 EXP_TIME = 2^(-EXP_VAL) UVC camera exposure timing in OpenCV | KUROKESU):
注意:V4L方式设置的曝光值就不是上面的负数,而是v4l2-ctl里面显示的值。
以曝光参数为例,网络提到的曝光参数都是负值,而v4l2的整数值除以100000 为秒(根据1.11. Camera Control Reference — The Linux Kernel documentation),假如值为200,那么就是20ms。
所以两者换算关系为:
Ev=2^(Ep)*10000 Ev为v4l2的曝光值而Ep为python下面的负数值。
如果希望通用保存的参数,因为Ep取值范围稀疏,可以以Ep的负值进行存储曝光值,如果是linux则利用上面公式转为正确值。