昨天老板临时交代一个活,要求通过算法检测监控设备是否存在失焦、偏色、亮度异常等问题。问题本身不难,在网上查看了一些资料,自己也做了一些思考,方法如下:

        1.失焦检测。

        失焦的主要表现就是画面模糊,衡量画面模糊的主要方法就是梯度的统计特征,通常梯度值越高,画面的边缘信息越丰富,图像越清晰。需要注意的是梯度信息与每一个视频本身的特点有关系,如果画面中本身的纹理就很少,即使不失焦,梯度统计信息也会很少,对监控设备失焦检测需要人工参与的标定过程,由人告诉计算机某个设备正常情况下的纹理信息是怎样的。

[cpp]  
   view plain 
   copy 
   
 
   
 
 
1. /********************************************************************************
2. *函数描述:  DefRto 计算并返回一幅图像的清晰度   
3. *函数参数: frame  彩色帧图
4. *函数返回值:double   清晰度表示值,针对该视频,当清晰度小于10为模糊,大于14为清楚                  
5. *********************************************************************************/  
6. double DefRto(Mat frame)  
7. {  
8.     Mat gray;  
9.     cvtColor(frame,gray,CV_BGR2GRAY);  
10.     IplImage *img = &(IplImage(gray));  
11. double temp = 0;  
12. double DR = 0;  
13. int i,j;//循环变量  
14. int height=img->height;  
15. int width=img->width;  
16. int step=img->widthStep/sizeof(uchar);  
17.     uchar *data=(uchar*)img->imageData;  
18. double num = width*height;  
19.   
20. for(i=0;i<height;i++)  
21.     {  
22. for(j=0;j<width;j++)  
23.         {  
24. double)(data[(i+1)*step+j]-data[i*step+j]),2) + pow((double)(data[i*step+j+1]-data[i*step+j]),2)));  
25.             temp += abs(data[(i+1)*step+j]-data[i*step+j])+abs(data[i*step+j+1]-data[i*step+j]);  
26.         }  
27.     }  
28.     DR = temp/num;  
29. return DR;  
30. }  
 
        2.色偏检测。
        网上常用的一种方法是将RGB图像转变到CIE L*a*b*空间,其中L*表示图像亮度,a*表示图像红/绿分量,b*表示图像黄/蓝分量。通常存在色偏的图像,在a*和b*分量上的均值会偏离原点很远,方差也会偏小;通过计算图像在a*和b*分量上的均值和方差,就可评估图像是否存在色偏。计算CIE L*a*b*空间是一个比较繁琐的过程,好在OpenCV提供了现成的函数,因此整个过程也不复杂。
 
 
   [cpp]  
   view plain 
   copy 
   
 
   
 
 
1. /********************************************************************************************
2. *函数描述:  calcCast    计算并返回一幅图像的色偏度以及,色偏方向   
3. *函数参数:  InputImg    需要计算的图片,BGR存放格式,彩色(3通道),灰度图无效
4. *           cast        计算出的偏差值,小于1表示比较正常,大于1表示存在色偏
5. *           da          红/绿色偏估计值,da大于0,表示偏红;da小于0表示偏绿
6. *           db          黄/蓝色偏估计值,db大于0,表示偏黄;db小于0表示偏蓝
7. *函数返回值: 返回值通过cast、da、db三个应用返回,无显式返回值
8. *********************************************************************************************/  
9. void colorException(Mat InputImg,float& cast,float& da,float& db)  
10. {  
11.     Mat LABimg;  
12. //参考  
13. //由于OpenCV定义的格式是uint8,这里输出的LABimg从标准的0~100,-127~127,-127~127,被映射到了0~255,0~255,0~255空间  
14. float a=0,b=0;  
15. int HistA[256],HistB[256];  
16. for(int i=0;i<256;i++)  
17.     {  
18.         HistA[i]=0;  
19.         HistB[i]=0;  
20.     }  
21. for(int i=0;i<LABimg.rows;i++)  
22.     {  
23. for(int j=0;j<LABimg.cols;j++)  
24.         {  
25. float(LABimg.at<cv::Vec3b>(i,j)[1]-128);//在计算过程中,要考虑将CIE L*a*b*空间还原 后同  
26. float(LABimg.at<cv::Vec3b>(i,j)[2]-128);  
27. int x=LABimg.at<cv::Vec3b>(i,j)[1];  
28. int y=LABimg.at<cv::Vec3b>(i,j)[2];  
29.             HistA[x]++;  
30.             HistB[y]++;  
31.         }  
32.     }  
33. float(LABimg.rows*LABimg.cols);  
34. float(LABimg.rows*LABimg.cols);  
35. float D =sqrt(da*da+db*db);  
36. float Ma=0,Mb=0;  
37. for(int i=0;i<256;i++)  
38.     {  
39. //计算范围-128~127  
40.         Mb+=abs(i-128-db)*HistB[i];  
41.     }  
42. float((LABimg.rows*LABimg.cols));  
43. float((LABimg.rows*LABimg.cols));  
44. float M=sqrt(Ma*Ma+Mb*Mb);  
45. float K=D/M;  
46.     cast = K;  
47. return;  
48. }  
3.亮度检测。
        亮度检测与色偏检测相似,计算图片在灰度图上的均值和方差,当存在亮度异常时,均值会偏离均值点(可以假设为128),方差也会偏小;通过计算灰度图的均值和方差,就可评估图像是否存在过曝光或曝光不足。函数如下:
 
 
 
 
    [cpp]  
    view plain 
    copy 
    
 
    
 
  
1. /*********************************************************************************************************************************************************
2. *函数描述:  brightnessException     计算并返回一幅图像的色偏度以及,色偏方向   
3. *函数参数:  InputImg    需要计算的图片,BGR存放格式,彩色(3通道),灰度图无效
4. *           cast        计算出的偏差值,小于1表示比较正常,大于1表示存在亮度异常;当cast异常时,da大于0表示过亮,da小于0表示过暗
5. *函数返回值: 返回值通过cast、da两个引用返回,无显式返回值
6. **********************************************************************************************************************************************************/  
7. void brightnessException (Mat InputImg,float& cast,float& da)  
8. {  
9.     Mat GRAYimg;  
10.     cvtColor(InputImg,GRAYimg,CV_BGR2GRAY);  
11. float a=0;  
12. int Hist[256];  
13. for(int i=0;i<256;i++)  
14.     Hist[i]=0;  
15. for(int i=0;i<GRAYimg.rows;i++)  
16.     {  
17. for(int j=0;j<GRAYimg.cols;j++)  
18.         {  
19. float(GRAYimg.at<uchar>(i,j)-128);//在计算过程中,考虑128为亮度均值点  
20. int x=GRAYimg.at<uchar>(i,j);  
21.             Hist[x]++;  
22.         }  
23.     }  
24. float(GRAYimg.rows*InputImg.cols);  
25. float D =abs(da);  
26. float Ma=0;  
27. for(int i=0;i<256;i++)  
28.     {  
29.         Ma+=abs(i-128-da)*Hist[i];  
30.     }  
31. float((GRAYimg.rows*GRAYimg.cols));  
32. float M=abs(Ma);  
33. float K=D/M;  
34.     cast = K;  
35. return;  
36. }

  1.         最后展示一下结果。

颜色失真 opencv 颜色失真会损伤色觉吗_视频处理

颜色失真 opencv 颜色失真会损伤色觉吗_方差_02


颜色失真 opencv 颜色失真会损伤色觉吗_方差_03

颜色失真 opencv 颜色失真会损伤色觉吗_i++_04

颜色失真 opencv 颜色失真会损伤色觉吗_i++_05

颜色失真 opencv 颜色失真会损伤色觉吗_opencv_06


        可以发现:当亮度变低时,失焦检测显示结果为:模糊。这是由于失焦检测依赖于梯度统计,亮度变低时,会导致梯度值整体下降,从而导致检测不正确。一种更好的方法是利用亮度检测的结果,合理设定失焦检测的报警阈值,避免这种情况。