图像亮度异常检测主要就是求一张图片的平均亮度,若是大于阈值则判断为过亮,小于阈值则判断为过暗,实际使用时可能不是对整张图片进行检测,而是只检测图片的某个区域,这时候能够根据传入的坐标对特定区域进行检测。数组
另外下面的代码中是验证了几种方法,最终用的就是平均值的方法,也就是代码中的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