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

项目场景:

项目需要在较暗的光照环境下使用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()

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 相机自动曝光控制是一种在摄影过程中自动调整曝光时间的技术。OpenCV是一种广泛应用于计算机视觉领域的开源计算机视觉库。OpenCV提供了一些用于相机自动曝光控制的函数和算法,可以帮助我们实现自动曝光的功能。 在OpenCV中,我们可以使用cv::exposureCompensate()函数来实现曝光补偿。这个函数可以根据亮度分布的统计信息,自动调整图像的亮度和对比度。此外,我们还可以使用cv::CLAHE算法来实现对比度受限自适应直方图均衡化,这可以帮助我们进一步提升图像的质量。 OpenCV还提供了一些自适应阈值算法,例如cv::adaptiveThreshold()函数,可以根据图像的局部亮度来自动调整阈值,以实现更加精确的图像分割。 总的来说,相机自动曝光控制是基于计算机视觉算法的一种技术。OpenCV作为一款广泛应用于计算机视觉领域的开源计算机视觉库,提供了一些用于自动曝光控制的函数和算法,可以帮助我们快速实现自动曝光的功能。 ### 回答2: 相机自动曝光控制是指相机自动地调整曝光参数,使得图像曝光适中。在计算机视觉中,可以利用OpenCV库实现相机自动曝光控制。 OpenCV提供了一个简便的方法实现自动曝光控制:calcHist()函数可以计算图像的直方图,并将图像像素分成不同的灰度级别。可以利用这个函数计算每一幅图像的亮度值,并根据亮度值的分布情况,进行自动曝光控制。 在具体实现中,可以将曝光参数设置为“曝光时间”、“ISO”、“光圈”,然后根据当前图像的亮度分布情况调整这些参数。例如,如果图像过暗,则可以增加曝光时间或者ISO值,如果图像过亮,则可以降低曝光时间或者ISO值。 需要注意的是,在实现自动曝光控制时,需要多次拍摄同一个场景,并计算不同亮度的图像的直方图,从而确定最佳的曝光参数。此外,还需要对实时性要求高的应用程序,需要优化算法,减少计算时间。 总之,OpenCV提供了一种简单易用的方法实现相机自动曝光控制,可以在图像处理中起到重要作用。 ### 回答3: 相机自动曝光控制是摄影中常用的技术之一,用于调整相机曝光参数以达到正确的曝光效果。OpenCV是一个广泛使用的计算机视觉库,也提供了支持相机自动曝光控制的功能。 OpenCV中有两种方式实现相机自动曝光控制:基于区域的自动曝光控制和基于全局的自动曝光控制。基于区域的自动曝光控制将图像分成多个区域,并为每个区域计算曝光参数,得到最终的曝光参数后再应用于整个图像。基于全局的自动曝光控制则直接对整个图像计算曝光参数。 OpenCV中用于计算自动曝光参数的函数包括cv::findContours()、cv::mean()、cv::threshold()、cv::normalize()和cv::Scalar()等。其中,cv::findContours()用于生成图像的轮廓,cv::mean()用于计算像素值的均值,cv::threshold()用于二值化图像,cv::normalize()用于将像素值归一化,cv::Scalar()用于创建颜色。通过结合这些函数,就可以实现相机自动曝光控制的功能。 需要注意的是,在实际应用中,自动曝光控制的精度往往会受到多种因素的影响,如曝光时间、光源强度、拍摄场景等。因此,为了获得更好的曝光效果,需要结合实际拍摄情况进行调整,或选择更为精密的自动曝光控制算法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值