OpenCV对图像的性能测试

最近在做图像算法,对图像性能指标进行测试。主要包括PSNR(峰值信噪比)、NC(归一化相关系数)、SSIM(结构相似性)等,下面对这三个指标做简单介绍。

PSNR:峰值信噪比,一种评价图像的客观标准,用来评估图像的保真性。峰值信噪比经常用作图像压缩等领域中信号重建质量的测量方法,它常简单地通过均方差(MSE)进行定义,使用两个m×n单色图像IK。PSNR的单位为分贝dB。计算公式如下:

                                                              mathit{MSE} = frac{1}{mn}sum_{i=0}^{m-1}sum_{j=0}^{n-1} ||I(i,j) - K(i,j)||^2

                                                              mathit{PSNR} = 10 cdot log_{10} left( frac{mathit{MAX}_I^2}{mathit{MSE}} 
ight) = 20 cdot log_{10} left( frac{mathit{MAX}_I}{sqrt{mathit{MSE}}} 
ight)

其中,MAXI是表示图像点颜色的最大数值,如果每个采样点用 8 位表示,那么就是 255。PSNR值越大,就代表失真越少,图像压缩中典型的峰值信噪比值在 30 到 40dB 之间,小于30dB时考虑图像无法忍受。

NC:对两幅图像进行相似度的衡量,除了用眼睛观察的方法外,我们可以更加精确地用数据来客观的评估归一化,归一化的相关系数(NC)提供了度量工具,它可以用来评估图像的鲁棒性

                                                                       

其中,w(x,y)和w'(x,y)代表两张图像(水印和提取水印),M、N为图像分标率,归一化相关系数用来表示原始水印与提取水印的相似度,取值在0到1之间,越接近1表示鲁棒性越好。

SSIM:(structural similarity index),结构相似性,是一种衡量两幅图像相似度的指标,也是一种全参考的图像质量评价指标,它分别从亮度对比度结构三方面度量图像相似性。Wiki中的计算公式:

                                                                               

 

其中  是 的平均值,   的平均值,    的方差,    的方差,  是   的标准差。  是用来维持稳定的常数。 是像素值的动态范围。  ,  。结构相似性的范围为  到  当两张图像一模一样时,SSIM的值等于1

另一篇博文中的计算公式如下,也可以使用。http://blog.csdn.net/xiaxiazls/article/details/47952611

                                                           

其中ux、uy分别表示图像X和Y的均值,σX、σY分别表示图像X和Y的方差,σXY表示图像X和Y的协方差,即

                                                                  

C1、C2、C3为常数,为了避免分母为0的情况,通常取C1=(K1*L)^2, C2=(K2*L)^2, C3=C2/2, 一般地K1=0.01, K2=0.03, L=255. 则

                                                                                       

在实际应用中,可以利用滑动窗将图像分块,令分块总数为N,考虑到窗口形状对分块的影响,采用高斯加权计算每一窗口的均值、方差以及协方差,然后计算对应块的结构相似度SSIM,最后将平均值作为两图像的结构相似性度量,即平均结构相似性MSSIM:

                                                                                         

另外可以参考SSIM的另一篇博文:  http://blog.csdn.net/xiaxiazls/article/details/47952611

程序如下:

环境:win7   VC++6.0   OpenCV1.0

其中 src 是原图像,key是指经过简单的数字指纹加密的图像或失真的图像。(这里用到的数字指纹加密是指将图像随机数量像素点进行小范围的改变,肉眼无法辨别)。

  1 #include <cstdio>
  2 #include <cmath>
  3 #include <ctime>
  4 #include <cstdlib>
  5 
  6 #include "cv.h"  
  7 #include "highgui.h"  
  8 
  9 
 10 //计算两幅图像的保真性
 11 //参数: src 原图像
 12 //      key 指纹加密的图像
 13 
 14 double Psnr( IplImage* src, IplImage* key ) {
 15     int width = src->width;       //图像宽
 16     int height = src->height;     //图像高
 17     
 18     double mse = 0.0;             //MSE为均方差
 19 
 20     CvScalar s_src;               //原图像的像素通道结构体
 21     CvScalar s_key;               //加密后的像素通道结构体
 22 
 23                                   //计算MSE——均方差
 24     for( int row = 0; row < height; row++ ) {
 25         for( int col = 0; col < width; col++ ) {
 26             s_src = cvGet2D( src, row, col );   
 27             s_key = cvGet2D( key, row, col );
 28             double src_r = s_src.val[0];        //取出G通道的像素值
 29             double key_r = s_key.val[0];
 30             //if( src_r != key_r ) {
 31             //printf( "%.lf %.lf
", src_r, key_r );
 32             //char ch = getchar();
 33             //}
 34             mse += ( src_r - key_r ) * ( src_r - key_r );   //计算方差
 35         }
 36     }
 37 
 38     const double MAX = 255.0;               //最大峰值为255
 39     
 40     //方法一
 41     double temp = MAX * MAX * ( double )width * ( double )height;
 42     double r = temp / mse;
 43     r = 10.0 * log10( r );
 44     
 45     //方法二,计算结果是一样的
 46     //mse = mse / ( width * height );
 47     //printf( "均方误差: %lf
", mse );
 48     //mse = sqrt( mse );
 49     //double temp = MAX;
 50     //double r = temp / mse;
 51     //r = 20.0 * log10( r );
 52 
 53     //打印的中间结果信息
 54     //printf( "temp: %lf
", temp );
 55     //printf( "sum: %lf
", sum );
 56      //printf( "%lf
", r );
 57     
 58     return r;
 59 }
 60 
 61 
 62 
 63 //计算两幅图像的鲁棒性
 64 //参数: src 原图像
 65 //      key 指纹加密的图像
 66 
 67 double Nc( IplImage* src, IplImage* key ) {
 68     int width = src->width;       //图像宽
 69     int height = src->height;     //图像高
 70 
 71     CvScalar s_src;               //原图像的像素通道结构体
 72     CvScalar s_key;               //加密后的像素通道结构体
 73 
 74     double d = 0.0;
 75     double d_src = 0.0;
 76     double d_key = 0.0;
 77 
 78     for( int row = 0; row < height; row++ ) {
 79         for( int col = 0; col < width; col++ ) {
 80             s_src = cvGet2D( src, row, col );   
 81             s_key = cvGet2D( key, row, col );
 82             double src_r = s_src.val[0];        //取出G通道的像素值
 83             double key_r = s_key.val[0];
 84             d += src_r * key_r;
 85             d_src += src_r * src_r;
 86             d_key += key_r * key_r;
 87         }
 88     }
 89     
 90     //nc是鲁棒性指标
 91     double nc = 0.0;
 92     nc = d / ( sqrt( d_src ) * sqrt( d_key ) );
 93 
 94     return nc;
 95 }
 96 
 97 
 98 
 99 //计算两幅图像的结构相似性
100 //参数: src 原图像
101 //      key 指纹加密的图像
102 
103 double Ssim( IplImage* src, IplImage* key ) {
104     int width = src->width;       //图像宽
105     int height = src->height;     //图像高
106 
107     CvScalar s_src;               //原图像的像素通道结构体
108     CvScalar s_key;               //加密后的像素通道结构体
109 
110     double mu_src = 0.0;          //原图像均值
111     double mu_key = 0.0;          //加密后的图像均值
112 
113     int row, col;
114     for( row = 0; row < height; row++ ) {
115         for( col = 0; col < width; col++ ) {
116             s_src = cvGet2D( src, row, col );   
117             s_key = cvGet2D( key, row, col );
118             double src_r = s_src.val[0];        //取出G通道的像素值
119             double key_r = s_key.val[0];
120             mu_src += src_r;
121             mu_key += key_r;
122         }
123     }
124 
125     mu_src = mu_src / ( width * height );       //原图像均值
126     mu_key = mu_key / ( width * height );       //加密图像均值
127 
128     //打印的中间结果信息
129     //printf( "src的均值: %lf
", mu_src );
130     //printf( "key的均值: %lf
", mu_key );
131 
132     double sigma_src2 = 0.0;                    //原图像方差,即sigma_src^2
133     double sigma_key2 = 0.0;                    //加密图像方差,即sigma_key^2
134     double sigma_s_k2 = 0.0;                    //原图和加密图像的方差,即sigma_s_k^2
135 
136     double sigma_src = 0.0;                     //原图像标准差
137     double sigma_key = 0.0;                     //加密图像标准差
138     double sigma_s_k = 0.0;                     //原图像和加密图像的标准差
139 
140     for( row = 0; row < height; row++ ) {
141         for( col = 0; col < width; col++ ) {
142             s_src = cvGet2D( src, row, col );   
143             s_key = cvGet2D( key, row, col );
144             double src_r = s_src.val[0];        //取出G通道的像素值
145             double key_r = s_key.val[0];
146             sigma_src2 += ( src_r - mu_src ) * ( src_r - mu_src );
147             sigma_key2 += ( key_r - mu_key ) * ( key_r - mu_key );
148             sigma_s_k2 += ( src_r - mu_src ) * ( key_r - mu_key ); 
149         }
150     }
151 
152     sigma_src2 = sigma_src2 / ( width * height - 1 );
153     sigma_key2 = sigma_key2 / ( width * height - 1 );
154     sigma_s_k2 = sigma_s_k2 / ( width * height - 1 );
155 
156     sigma_src = sqrt( sigma_src2 );
157     sigma_key = sqrt( sigma_key2 );
158     sigma_s_k = sqrt( sigma_s_k2 );
159 
160     //打印的中间结果信息
161     //printf( "sigma_src: %lf
", sigma_src );
162     //printf( "sigma_key: %lf
", sigma_key );
163     //printf( "sigma_s_k: %lf
", sigma_s_k );
164 
165     //固定参数,为常量
166     //c1,c2,c3是用来维持稳定的常数
167     //MAX是像素值的动态范围
168     const double k1 = 0.01;
169     const double k2 = 0.03;
170     const int MAX = 255;
171     
172     double c1 = ( k1 * MAX ) * ( k1 * MAX );
173     double c2 = ( k2 * MAX ) * ( k2 * MAX );
174     double c3 = c2 / 2;
175 
176     //亮度、对比度、结构三方面度量图像相似性
177     double light = ( 2 * mu_src * mu_key + c1 ) / ( mu_src * mu_src + mu_key * mu_key + c1 );
178     double contrast = ( 2 * sigma_src * sigma_key + c2 ) / ( sigma_src2 + sigma_key2 +c2 );
179     double structure = ( sigma_s_k2 + c3 ) / ( sigma_src * sigma_key + c3 );
180 
181     //打印的中间结果信息
182     //printf( "light: %lf
", light );
183     //printf( "contrast: %lf
", contrast );
184     //printf( "structure: %lf
", structure );
185 
186     //方法一
187     //亮度 * 对比度 * 结构相似度
188     double ssim = light * contrast * structure;
189 
190     //方法二,计算结果是一样的
191     //double ssim = light * ( ( 2 * sigma_s_k2 + c2 ) / (sigma_src2 + sigma_key2 + c2 ) );
192 
193     return ssim;
194 }
195 
196 void KeyImg( IplImage* src ) {
197     int n = 0;
198     int width = src->width;       //图像宽
199     int height = src->height;     //图像高
200 
201     printf( "图像宽: %d, 高: %d
", width, height );
202     printf( "输入嵌入的像素点位数: " );
203     scanf( "%d", &n );
204     int count = 0;
205     
206     srand( (unsigned)time(NULL) );
207 
208     CvScalar s;
209 
210     IplImage* keyImg;
211     keyImg = cvCreateImage( cvGetSize( src ), IPL_DEPTH_8U, 1 );
212     keyImg = cvCloneImage( src );
213 
214     while( count < n ) {
215         int x = rand() % width;
216         int y = rand() % height;
217         s = cvGet2D( keyImg, y, x );
218         double b = s.val[0];
219         double g = s.val[1];
220         double r = s.val[2];
221         //printf( "修改前: %0.lf, %0.lf, %0.lf
  ", s.val[0], s.val[1], s.val[2] );
222         int temp = rand() % 2;
223         if( temp == 0 ) {
224             s.val[0] -= 10.0;
225         }
226         else if( temp == 1 ) {
227             s.val[0] += 10.0;
228         }
229         cvSet2D( keyImg, y, x, s );
230         //s = cvGet2D( keyImg, y, x );
231         //printf( "修改后: %0.lf
", s.val[0] );
232         count++;
233     }
234     
235     cvSaveImage( "Test.bmp", keyImg );
236     //cvNamedWindow("image", CV_WINDOW_AUTOSIZE); //创建窗口
237     //cvShowImage("image", keyImg); //显示图像
238     cvWaitKey(0);
239     printf( "图像生成成功!
" );
240 }
241 
242 
243 int main() {
244     IplImage* src = NULL;
245     IplImage* key = NULL;
246     
247     
248     src = cvLoadImage( "Flower.bmp", CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR );
249 
250     //生成一张加密的指纹图片
251     //KeyImg( src );
252     key = cvLoadImage( "水印Flower.bmp", CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR );
253 
254     double psnr = 0.0;
255     double nc = 0.0;
256     double ssim = 0.0;
257     psnr = Psnr( src, key );
258     nc = Nc( src, key );
259     ssim = Ssim( src, key );
260     printf( "保真性: %lf
", psnr );
261     printf( "鲁棒性: %lf
", nc );
262     printf( "结构相似性: %lf
", ssim );
263     return 0;
264 }

测试一:使用Windows自带的“郁金香”图片,先生成数字指纹图像,比较图像的失真结果。

         

                                原图                                                                              数字指纹加密后

测试结果:

测试二:用原图和经过噪声攻击的图像进行测试。

  

测试结果:

原文地址:https://www.cnblogs.com/lzjtdxfxl/p/5695253.html