影象亮度異常檢測主要就是求一張圖片的平均亮度,如果大於閾值則判斷為過亮,小於閾值則判斷為過暗,實際使用時可能不是對整張圖片進行檢測,而是隻檢測圖片的某個區域,這時候可以根據傳入的座標對特定區域進行檢測。
另外下面的程式碼中是驗證了幾種方法,最終用的就是平均值的方法,也就是程式碼中的da。
/***************************************************************************
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寫到組態檔中,上電初始化時讀取組態檔。