简单的自动曝光

     ~~~~     正好在android下使用v4l2打开usb相机,然后发现使用v4l2设置自动曝光没有反应,之前明明有用的,不知道改动了什么,想了一下,就自己写了一个简单的自动曝光,这样就不用看v4l2的脸色行事了。

理论基础

     ~~~~     我这里主要就是计算图像的中间灰度值,当然不是全图,我这里区中间一块矩形,然后计算中间灰度值,然后同测试,看图像和中间灰度值,通过调整曝光时间,得出一个最佳值,然后达到最佳值附近即可。
     ~~~~     然后我们运行的时候就可以通过调节曝光值来时图像中间灰度值接近最佳值即可。

中间灰度值

     ~~~~     首先我们要写一个中间灰度值计算的函数,我这里的码流是yuyv的,如果你是其他码流格式,就需要相应更改代码了

/**
 * 计算图像指定部分区域的直方图,并得到这部分图像的中间灰度值
 * @param psImage 图像
 * @param w 宽
 * @param h 高
 * @param iX 矩形左上角x坐标
 * @param iY 矩形左上角Y坐标
 * @param iW 矩形宽
 * @param iH 矩形高
 * @return 中间灰度值
 */
int GetMidVFromImHist_yuyv(unsigned char *psImage, int w, int h, int iX, int iY, int iW, int iH)
{
	if (iX < 0 || iY < 0 || iX + iW > w || iY + iH > h)
		return -1;

	int iMidValue = 0;
	int piHistgram[256];
	memset(piHistgram, 0, 256 * sizeof(int));
	//计算指定部分区域的灰度直方图
	//为了加快速度,隔一行和一列计算
	unsigned char *pTTT;
	for (int i = iY; i < iY + iH; i += 2)
	{
		pTTT = psImage + 2 * i * w + 2 * iX;
		for (int j = 0; j < iW; j += 2, pTTT += 2 * 2)
			piHistgram[(*pTTT)]++;
	}

    //得到中间灰度值
	int iPixSum = 0;
	int iSum_1 = ((((iW + 1) >> 1) * ((iH + 1) >> 1)) >> 1);
	for (int i = 0; i < 256; i++)
	{
		iPixSum += piHistgram[i];
		if (iPixSum > iSum_1)
		{
			iMidValue = i;
			break;
		}
	}
	return iMidValue;
}

自动曝光

     ~~~~     然后我们需要实现一个通过图片变更自动曝光值得函数,下面贴代码,有几个全局变量吧,实际使用,最好要放到类里面,函数也放到类里面。

#define AUTOEXPO_IMAGE_NUM	1					//几帧图像,调整一次曝光时间.
#define BSET_MIDVALUE		175						//图像最佳的中间灰度值
#define MAX_MIDVALUE_GAP  5						//不需要调整曝光时间的中间灰度值上下限
#define MAX_EXPO_ADJUST_STEP	0.3					//调节曝光时间时,最大的步长比例

int m_iCurExpoTime;		//当前的曝光时间值
int m_iImageNum1;		//当灰度值调节到合适的位置,通过设置这个数来减少计算量

/**
 * 初始化
 * @param iExpoTime 最初的曝光时间值
 */
void initAutoExposure(int iExpoTime)
{
	m_iCurExpoTime = iExpoTime;		//当前的曝光时间值
	m_iImageNum1 = 0;
}

/**
 * 设置曝光值
 * @param curExpoTime 曝光值
 */
void setExposureTime(int curExpoTime)
{
    struct v4l2_control ctrl;
    ctrl.id = V4L2_CID_BRIGHTNESS;
    int bright = ioctl(fd, VIDIOC_G_CTRL, &ctrl);
    ctrl.value = curExpoTime;
    int ret = ioctl(fd, VIDIOC_S_CTRL, &ctrl);
    if(ret!=0){
        //设置失败
    }
}

/**
 * 进行一次自动曝光操作(需要在虹膜检测函数GetTwoIrisFromBigImage_New_Mlt之后执行)
 * @param psBigImage 原始大图
 * @param w 宽
 * @param h 高
 */
void AutoExposure(unsigned char *psBigImage, int w, int h)
{
	if(!psBigImage)return;

	//每 AUTOEXPO_IMAGE_NUM 帧图像,调整一次曝光时间
	m_iImageNum1++;
	if (m_iImageNum1 >= AUTOEXPO_IMAGE_NUM)
	{
        //下一张图片继续计算
        m_iImageNum1 = 0;
        //小于和大于正好一半,对应的灰度值
        int iMidValue = -1;
        //先确定左边的固定区域
        int iW = w >> 1;
        int iH = h >> 1;
        int iX = w >> 2;
        int iY = h >> 2;
        //计算对应区域的直方图,得到中间灰度值
        iMidValue = GetMidVFromImHist_1(psBigImage, w, h, iX, iY, iW, iH);
        int iMax_M, iMin_M, iBest_M;

        iBest_M = BSET_MIDVALUE;
        iMax_M = iBest_M + MAX_MIDVALUE_GAP;
        iMin_M = iBest_M - MAX_MIDVALUE_GAP;
        //图像太亮,减少曝光时间
        if (iMidValue > iMax_M)		
        {
            //接近最佳值时,调整幅度较小
            double dDiff = ((double)(iMidValue - iBest_M)) / ((double)(iBest_M * 3));
            //调整步长不能太大,防止过冲
            if (dDiff > MAX_EXPO_ADJUST_STEP)
                dDiff = MAX_EXPO_ADJUST_STEP;
            //曝光时间的改变值
            int iExpo_Diff = (int)(dDiff * ((double)m_iCurExpoTime) + 0.5);		
            if (iExpo_Diff < 2)
                iExpo_Diff = 2;
            int iNewExpoTime = m_iCurExpoTime - iExpo_Diff;
            //小于50图像太黑了
            if (iNewExpoTime < 50)
                iNewExpoTime = 50;
            if (iNewExpoTime != m_iCurExpoTime)
            {
                m_iCurExpoTime = iNewExpoTime;
                //设置曝光时间
                setExposureTime(m_iCurExpoTime);	
            }
        }
        else if (iMidValue < iMin_M)//图像太暗,增加曝光时间
        {
            double dDiff = ((double)(iBest_M - iMidValue)) / ((double)(iBest_M * 3));		
            //调整步长不能太大,防止过冲
            if (dDiff > MAX_EXPO_ADJUST_STEP)
                dDiff = MAX_EXPO_ADJUST_STEP;
            int iExpo_Diff = (int)(dDiff * ((double)m_iCurExpoTime) + 0.5);	
            if (iExpo_Diff < 2)
                iExpo_Diff = 2;
            int iNewExpoTime = m_iCurExpoTime + iExpo_Diff;
            //大于1000图像太亮了
            if (iNewExpoTime > 1000)
                iNewExpoTime = 1000;
            if (iNewExpoTime != m_iCurExpoTime)
            {
                m_iCurExpoTime = iNewExpoTime;
                setExposureTime(m_iCurExpoTime);
            }
        }
        else{
            //十张图片之后再重新计算
            m_iImageNum1 = -10;
        }
	}
}

     ~~~~     加上上面的计算中间灰度值函数,完整,然后在打开相机是调用初始化,然后在码流获取后,调用自动曝光函数即可实现自动曝光。
     ~~~~     注意BSET_MIDVALUE这个数对应的相机和环境有差异,需要自行测试设置。
     ~~~~     这个不是完整的工程,就没有上传github了。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
自动曝光python可以使用Python的OpenCV库实现。OpenCV库是一个广泛使用的计算机视觉库,提供了很多有用的功能,包括图像处理和计算机视觉任务的实现。 首先,需要读取图片数据并将其转换为灰度图像。使用OpenCV库的cv2.imread()函数读取图片数据,并使用cv2.cvtColor()函数将其转换为灰度图像。 接下来,需要计算灰度直方图。使用cv2.calcHist()函数计算灰度直方图。然后,可以使用matplotlib库把直方图绘制出来。 然后,需要找到直方图中的最大值和最小值。使用numpy库的np.argmax()和np.argmin()函数找到最大值和最小值。 最后,根据最大值和最小值自动调整曝光。可以使用cv2.addWeighted()函数进行加权平均和cv2.imshow()函数显示处理后的图像。 下面是一个简单自动曝光python代码: ```python import cv2 import numpy as np import matplotlib.pyplot as plt # 读取图片并转换为灰度图像 img = cv2.imread("image.jpg") gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 计算灰度直方图 hist = cv2.calcHist([gray_img], [0], None, [256], [0, 256]) plt.plot(hist) plt.show() # 找到直方图中的最大值和最小值 min_value = np.argmin(hist) max_value = np.argmax(hist) # 根据最大值和最小值自动调整曝光 alpha = 255 / (max_value - min_value) beta = - min_value * alpha auto_img = cv2.convertScaleAbs(img, alpha=alpha, beta=beta) # 显示图片 cv2.imshow("Auto Exposure", auto_img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 以上是一个简单自动曝光python代码,可以根据直方图中的最大值和最小值自动调整曝光。此代码可以用于自动调整曝光的照片或视频。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值