使用opencv关闭相机自动曝光的问题

本文探讨了在暗光条件下使用OpenCV控制USB相机曝光以保持高帧率的挑战,以及在Windows和Ubuntu系统上的不同设置和解决方案。

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

项目场景:

项目需要在较暗的光照环境下使用USB相机实时拍着视频,且需要保证相机跑满30帧。如果使用相机默认的自动曝光设置,会因为低光照而自动延长曝光时间,最终导致拍摄帧率只有15帧左右。因此,需要通过OpenCV控制相机关闭自动曝光,并设置手动的曝光参数,以限制实际的曝光时间。从而在部分牺牲拍摄亮度的情况下换取更高的拍摄帧率。

系统环境:win10、ubuntu20.04
OpenCV版本:均为4.7.0


问题描述

软件需要兼容win10、ubuntu20.04,最初在win10上编写和调试。
按照网上的教程,使用cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, value) 设置曝光时,value在0-2.6为手动曝光,2.6-4为自动曝光。于是写了如下代码:

cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
exposure = -5
cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 3.0) # 先打开自动曝光
cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 1.0) # 再关闭自动曝光
cap.set(cv2.CAP_PROP_EXPOSURE, exposure) # 最后设置曝光参数

测试时发现,相机拍到的图像有时候会变得非常暗。远比使用相机调试软件设置相同参数下拍到的图像暗。并且时而正常时而不正常。

经过多次测试发现,当使用windows系统自带的相机打开USB相机并关闭后,再使用自己编写的程序可以以正常的曝光亮度打开相机一次。但重启自己编写的程序后相机的图像又会变得非常暗。所以,基本可以推测自己的程序设置的参数可能有问题。


于是又自己测试了一遍cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, value) 参数。奇怪的是在设置value为1.0时可以打开自动曝光,而在设置value为0.0时可以关闭自动曝光???
然后把代码改成

cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
exposure = -5 # 我这里取-5时相机刚好能达到30帧
cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 1.0) # 先打开自动曝光
cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 0.0) # 再关闭自动曝光
cap.set(cv2.CAP_PROP_EXPOSURE, exposure) # 最后设置曝光参数

相机的帧率和亮度一切看起来都正常了。


然而当开始把代码搬到ubuntu上调试的时候一切问题又重来了。相机的图像又变得非常暗,甚至比在win10上出问题时还要暗。出问题的代码如下:

cap = cv2.VideoCapture(0, cv2.CAP_V4L2)
exposure = 300 # linux的曝光参数计算和windows不太一样,我这里取大约300时相机刚好达到30帧
cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 1.0) # 先打开自动曝光
cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 0.0) # 再关闭自动曝光
cap.set(cv2.CAP_PROP_EXPOSURE, exposure) # 最后设置曝光参数

一番折腾之后,把cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, value)的参数改回:

cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 3.0) # 先打开自动曝光
cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 1.0) # 再关闭自动曝光

拍摄的图像又恢复正常了。


解决方案:

经过测试发现,在windows下,以下参数是正常工作的:

cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 1.0) # 打开自动曝光
cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 0.0) # 关闭自动曝光

在ubuntu下,以下参数是正常工作的:

cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 3.0) # 打开自动曝光
cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 1.0) # 关闭自动曝光

推测网上主流的教程是以linux系统写的。这个问题目前不确定是系统差异还是OpenCV的bug(毕竟一个开关量用0~4之间的数表示感觉十分反直觉)。
最后,顺带一提cap.set(cv2.CAP_PROP_EXPOSURE, exposure) 设置手动曝光时windows和linux上exposure参数的换算。直观上感觉linux的exposure比较接近快门时间ms数×10。和windows上的曝光参数大致可按

exposure_linux≈10000*2^(exposure_win)

换算


目前可用的程序

import cv2
import os
import numpy as np
import sys
import time


def TakePictures(fileName = '', dirPath='.'):
    framesSkip = 30
    FPS = 999
    interval_ms =  1000.0 / FPS - 1;
    manualExposure = -5
    inputSrc = 0
    
    if sys.platform.startswith('win'):
        cap = cv2.VideoCapture(int(inputSrc), cv2.CAP_DSHOW)
    elif sys.platform.startswith('linux'):
        cap = cv2.VideoCapture(int(inputSrc), cv2.CAP_V4L2)
    else:
        print('Unknow System')
        return
        
    cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
    cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'))

    # 打开自动曝光
    if sys.platform.startswith('win'):
        cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 1.0)
    elif sys.platform.startswith('linux'):
        cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 3.0)
    
    cap.set(cv2.CAP_PROP_AUTO_WB, 1.0) 
    
    # 打开自动白平衡
    cap.set(cv2.CAP_PROP_AUTO_WB, 1.0)
    for i in range(framesSkip):
        cap.read();
        time.sleep(interval_ms / 1000);

    # 关闭自动曝光
    # 并设置手动曝光参数
    if sys.platform.startswith('win'):
        cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 0.0) 
        cap.set(cv2.CAP_PROP_EXPOSURE, manualExposure)
    elif sys.platform.startswith('linux'):
        cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 1.0) # 关闭自动曝光
        cap.set(cv2.CAP_PROP_EXPOSURE, 10000 * 2**manualExposure)
        
    n = 1
    goon, frame = cap.read()
    # print('size: %d x %d' % (frame.shape[1], frame.shape[0]))
    cv2.namedWindow('camera', 0)
    dt = interval_ms / 1000
    t0 = time.time()
    while goon:
            
        cv2.imshow('camera', frame)
        key = cv2.waitKey(2)
        
        if key == 13: #ENTER
            if fileName == '':
                saveFileName = os.path.join(dirPath, 'pic_%04d.png' % (n,))
                cv2.imwrite(saveFileName, frame)
                n += 1
            else:
                saveFileName = os.path.join(dirPath, fileName)
                cv2.imwrite(saveFileName, frame)
                break
            print('save: ', saveFileName)
        elif key == 27 or key == ord('q'): #ESC
            break
        goon, frame = cap.read()
        t1 = time.time()
        dt += (t1 - t0 - dt) * 0.1
        t0 = t1
        print('FPS = %f' % (1.0/dt), end='\r')
    cap.release()
    cv2.destroyAllWindows()

if __name__ == '__main__':
    TakePictures()

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值