基于opencv的图像亮度异常检测

图像亮度异常检测主要就是求一张图片的平均亮度,若是大于阈值则判断为过亮,小于阈值则判断为过暗,实际使用时可能不是对整张图片进行检测,而是只检测图片的某个区域,这时候能够根据传入的坐标对特定区域进行检测。数组

另外下面的代码中是验证了几种方法,最终用的就是平均值的方法,也就是代码中的da。ui

/***************************************************************************
Description:根据传入的信号灯结构体,求出左上角和右下角的坐标
parameter:
    lightStr:图像中包含的信号灯坐标;
	lightNum:信号灯框的数量,
    minNum:左上角点在数组中的下标,
    maxNum:右下角点在数组中的下标
return:
    0:success;
    1:fail
***************************************************************************/
int minAndMax(tlight::LightClock *lightStr, unsigned int lightNum, int &minNum, int &maxNum)
{
    
    int xmin = lightStr[0].xmin;
	int xmax = lightStr[0].xmax;
	
    //求出左上角点在数组中的下标
    for(int i = 0; i < lightNum; i++)
    {
         if(lightStr[i].xmin < xmin )
         {
             printf("i=%d,lightStr[i].xmin:%d,xmin:%d\n", i, lightStr[i].xmin, xmin);
             xmin = lightStr[i].xmin;
			 minNum = i;
         }
    }
 
    //求出右下角点在数组中的下标
	for(int i = 0; i < lightNum; i++)
    {
         if(lightStr[i].xmax > xmax )
         {
             printf("i=%d,lightStr[i].xmax:%d, xmax:%d\n", i, lightStr[i].xmax, xmax);
             xmax = lightStr[i].xmax;
			 maxNum = i;
         }
    }
 
	return 1;
 
 
}
 
 
 
/*****************************************************************************
Description:判断图像是否逆光,过亮;
parameter:
    inputImage:要检测的输入图像;
	lightStr:图像中包含的信号灯坐标;
	lightNum:信号灯框的数量,
return:
    21:图像过亮
    22:图像过暗
	20:图像正常
******************************************************************************/
int isBackLight(IplImage *inputImage, tlight::LightClock *lightStr, uint32_t lightNum)
{
    float da = 0.0;
	float cast = 0.0;
	float Ma = 0.0;
 
    int xmin = 0;
	int ymin = 0;
	int xmax = 0;
	int ymax = 0;
    int minNum = 0;
	int maxNum = 0;
	
    //首先把IplImage转化为Mat格式,而且转换为灰度图,
    cv::Mat inputMat = cv::cvarrToMat(inputImage);
	printf("inputMat.rows:%d\n", inputMat.rows);
	printf("inputMat.cols:%d\n", inputMat.cols);
 
	for(int i  = 0; i < lightNum;i++)//调试,记得删除
	{
	    printf("lightStr[%d].xmin:%d;\n", i, lightStr[i].xmin);
		printf("lightStr[%d].ymin:%d;\n", i, lightStr[i].ymin);
		printf("lightStr[%d].xmax:%d;\n", i, lightStr[i].xmax);
		printf("lightStr[%d].ymax:%d;\n", i, lightStr[i].ymax);
	}
 
	cv::Mat inputRec;
 
    if(0 == lightNum)//没有框的坐标,只检测上半部分
    {
        inputRec = inputMat(cv::Rect(0, 0, inputMat.cols, (inputMat.rows)/2 ));
     	printf("inputRec.rows:%d\n", inputRec.rows);
	    printf("inputRec.cols:%d\n", inputRec.cols);
        
    }
	else//有坐标信息的,按照坐标进行检测,
	{
        //找出xmin的最小值,和xmax的最大值,这两个点对应的就是相应的左上角和右下角。
        minAndMax(lightStr, lightNum, minNum, maxNum);
	    xmin = lightStr[minNum].xmin;
		ymin = lightStr[minNum].ymin;
		xmax = lightStr[maxNum].xmax;
		ymax = lightStr[maxNum].ymax;
        printf("lightNum:%d, minNum:%d, maxNum:%d\n", lightNum, minNum, maxNum);
		printf("xmin:%d, ymin:%d,xmax:%d,ymax:%d\n", xmin, ymin, xmax, ymax);
		//而后把矩形框外扩.
		xmin = ((xmin - 100) < 0) ? 0: (xmin - 100);
		ymin = ((ymin - 20) < 0) ? 0: (ymin - 20);
		xmax = ((xmax + 100) > inputMat.cols)? inputMat.cols : (xmax + 100);
		ymax = ((ymax + 300) > inputMat.rows)? inputMat.rows : (ymax + 300);
 
		printf("xmin:%d, ymin:%d,xmax:%d,ymax:%d\n", xmin, ymin, xmax, ymax);
 
		inputRec = inputMat(cv::Rect(xmin, ymin, (xmax - xmin), (ymax - ymin)));
		//printf("");
		
	}
 
	
	//cv::rectangle(inputMat, cvPoint(722, 28), cvPoint(813, 67), cvScalar(255, 0, 0), 2, 1, 0);//调试,记得删除
	//cv::imwrite("./test.jpg", inputMat);//调试,记得删除
	
	cv::Mat GRAYimg;
	cv::cvtColor(inputRec, GRAYimg, CV_BGR2GRAY);
	
	float a = 0;
	int Hist[256];
	for (int i = 0; i < 256; i++)
	{
		Hist[i] = 0;
	}
 
	float ave = 0.0;
	long sum = 0.0;
	for (int i = 0; i < GRAYimg.rows; i++)
	{
		for (int j = 0; j < GRAYimg.cols; j++)
		{
			//printf("GRAYimg.at<uchar>(i, j):%d\n", GRAYimg.at<uchar>(i, j));
			sum += GRAYimg.at<uchar>(i, j);
 
		}
	}
	printf("function:%s,sum:%d\n", __FUNCTION__, sum);
	ave = sum / (GRAYimg.rows * GRAYimg.cols);
	//printf("ave:%f\n", ave);
 
	int para = ave;
	int aveHigh = 0;
	for (int i = 0; i < GRAYimg.rows; i++)
	{
		for (int j = 0; j < GRAYimg.cols; j++)
		{
			a += float(GRAYimg.at<uchar>(i, j));
			//a += float(GRAYimg.at<uchar>(i, j) - para);
			//a += float(GRAYimg.at<uchar>(i, j) - ave);
			int x = GRAYimg.at<uchar>(i, j);
			if (x > ave)
			{
				aveHigh++;
				Hist[x]++;
			}
		}
	}
	da = a / float(GRAYimg.rows * GRAYimg.cols);//da是平均值
	printf("function:%s,da:%f\n", __FUNCTION__, da);
	float D = abs(da);
	//float Ma = 0;
	for (int i = 0; i < 256; i++)
	{
		if (i > ave)
		{
			Ma += abs(i - ave) * Hist[i];
		}
		//Ma += abs(i - para - da) * Hist[i];
		//Ma += abs(i - ave - da) * Hist[i];
	}
	Ma /= float(aveHigh);
	//Ma /= float((GRAYimg.rows * GRAYimg.cols));
	float M = abs(Ma);
	float K = D / M;
	cast = K;
 
	//调试,记得删除
	char debugName[20] = {};
 
 
	//if(da > 210.00)//过亮
	if(da > lightThresh)
	{
	    sprintf(debugName, "./%f.jpg", da);
	    //cv::imwrite(debugName, inputMat);//调试,记得删除。
	    return 21;
	}
	//else if(da < 25.00)
	else if(da < darkThresh)
	{
	    //printf("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ guoan+++++\n");
	    return 22;
	}
	else//正常
	{  
	    //printf("--------------------------------------------------------------------------------------liang-du-zheng-chang\n");
	    //cv::imwrite(debugName, inputMat);
	    return 20;
	}
}

项目中实际使用时能够把lightThresh写到配置文件中,上电初始化时读取配置文件。debug