視訊清晰度、色偏以及亮度異常檢測[轉]
阿新 • • 發佈:2019-01-01
昨天老闆臨時交代一個活,要求通過演算法檢測監控裝置是否存在失焦、偏色、亮度異常等問題。問題本身不難,在網上查看了一些資料,自己也做了一些思考,方法如下:
1.失焦檢測。
失焦的主要表現就是畫面模糊,衡量畫面模糊的主要方法就是梯度的統計特徵,通常梯度值越高,畫面的邊緣資訊越豐富,影象越清晰。需要注意的是梯度資訊與每一個視訊本身的特點有關係,如果畫面中本身的紋理就很少,即使不失焦,梯度統計資訊也會很少,對監控裝置失焦檢測需要人工參與的標定過程,由人告訴計算機某個裝置正常情況下的紋理資訊是怎樣的。
/******************************************************************************** *函式描述:DefRto 計算並返回一幅影象的清晰度 *函式引數:frame 彩色幀圖 *函式返回值:double 清晰度表示值,針對該視訊,當清晰度小於10為模糊,大於14為清楚 *********************************************************************************/ double DefRto(Mat frame) { Mat gray; cvtColor(frame,gray,CV_BGR2GRAY); IplImage *img = &(IplImage(gray)); double temp = 0; double DR = 0; int i,j;//迴圈變數 int height=img->height; int width=img->width; int step=img->widthStep/sizeof(uchar); uchar *data=(uchar*)img->imageData; double num = width*height; for(i=0;i<height;i++) { for(j=0;j<width;j++) { temp += sqrt((pow((double)(data[(i+1)*step+j]-data[i*step+j]),2) + pow((double)(data[i*step+j+1]-data[i*step+j]),2))); temp += abs(data[(i+1)*step+j]-data[i*step+j])+abs(data[i*step+j+1]-data[i*step+j]); } } DR = temp/num; return DR; }
2.色偏檢測。
網上常用的一種方法是將RGB影象轉變到CIE L*a*b*空間,其中L*表示影象亮度,a*表示影象紅/綠分量,b*表示影象黃/藍分量。通常存在色偏的影象,在a*和b*分量上的均值會偏離原點很遠,方差也會偏小;通過計算影象在a*和b*分量上的均值和方差,就可評估影象是否存在色偏。計算CIE L*a*b*空間是一個比較繁瑣的過程,好在OpenCV提供了現成的函式,因此整個過程也不復雜。
/******************************************************************************************** *函式描述: calcCast 計算並返回一幅影象的色偏度以及,色偏方向 *函式引數: InputImg 需要計算的圖片,BGR存放格式,彩色(3通道),灰度圖無效 * cast 計算出的偏差值,小於1表示比較正常,大於1表示存在色偏 * da 紅/綠色偏估計值,da大於0,表示偏紅;da小於0表示偏綠 * db 黃/藍色偏估計值,db大於0,表示偏黃;db小於0表示偏藍 *函式返回值: 返回值通過cast、da、db三個應用返回,無顯式返回值 *********************************************************************************************/ void colorException(Mat InputImg,float& cast,float& da,float& db) { Mat LABimg; cvtColor(InputImg,LABimg,CV_BGR2Lab);//參考http://blog.csdn.net/laviewpbt/article/details/9335767 //由於OpenCV定義的格式是uint8,這裡輸出的LABimg從標準的0~100,-127~127,-127~127,被對映到了0~255,0~255,0~255空間 float a=0,b=0; int HistA[256],HistB[256]; for(int i=0;i<256;i++) { HistA[i]=0; HistB[i]=0; } for(int i=0;i<LABimg.rows;i++) { for(int j=0;j<LABimg.cols;j++) { a+=float(LABimg.at<cv::Vec3b>(i,j)[1]-128);//在計算過程中,要考慮將CIE L*a*b*空間還原 後同 b+=float(LABimg.at<cv::Vec3b>(i,j)[2]-128); int x=LABimg.at<cv::Vec3b>(i,j)[1]; int y=LABimg.at<cv::Vec3b>(i,j)[2]; HistA[x]++; HistB[y]++; } } da=a/float(LABimg.rows*LABimg.cols); db=b/float(LABimg.rows*LABimg.cols); float D =sqrt(da*da+db*db); float Ma=0,Mb=0; for(int i=0;i<256;i++) { Ma+=abs(i-128-da)*HistA[i];//計算範圍-128~127 Mb+=abs(i-128-db)*HistB[i]; } Ma/=float((LABimg.rows*LABimg.cols)); Mb/=float((LABimg.rows*LABimg.cols)); float M=sqrt(Ma*Ma+Mb*Mb); float K=D/M; cast = K; return; }
3.亮度檢測。
亮度檢測與色偏檢測相似,計算圖片在灰度圖上的均值和方差,當存在亮度異常時,均值會偏離均值點(可以假設為128),方差也會偏小;通過計算灰度圖的均值和方差,就可評估影象是否存在過曝光或曝光不足。函式如下:
/*********************************************************************************************************************************************************
*函式描述: brightnessException 計算並返回一幅影象的色偏度以及,色偏方向
*函式引數: InputImg 需要計算的圖片,BGR存放格式,彩色(3通道),灰度圖無效
* cast 計算出的偏差值,小於1表示比較正常,大於1表示存在亮度異常;當cast異常時,da大於0表示過亮,da小於0表示過暗
*函式返回值: 返回值通過cast、da兩個引用返回,無顯式返回值
**********************************************************************************************************************************************************/
void brightnessException (Mat InputImg,float& cast,float& da)
{
Mat GRAYimg;
cvtColor(InputImg,GRAYimg,CV_BGR2GRAY);
float a=0;
int Hist[256];
for(int i=0;i<256;i++)
Hist[i]=0;
for(int i=0;i<GRAYimg.rows;i++)
{
for(int j=0;j<GRAYimg.cols;j++)
{
a+=float(GRAYimg.at<uchar>(i,j)-128);//在計算過程中,考慮128為亮度均值點
int x=GRAYimg.at<uchar>(i,j);
Hist[x]++;
}
}
da=a/float(GRAYimg.rows*InputImg.cols);
float D =abs(da);
float Ma=0;
for(int i=0;i<256;i++)
{
Ma+=abs(i-128-da)*Hist[i];
}
Ma/=float((GRAYimg.rows*GRAYimg.cols));
float M=abs(Ma);
float K=D/M;
cast = K;
return;
}
最後展示一下結果
可以發現:當亮度變低時,失焦檢測顯示結果為:模糊。這是由於失焦檢測依賴於梯度統計,亮度變低時,會導致梯度值整體下降,從而導致檢測不正確。一種更好的方法是利用亮度檢測的結果,合理設定失焦檢測的報警閾值,避免這種情況。
From:視訊清晰度、色偏以及亮度異常檢測