OpenCV对图像的性能测试
2016-07-22 15:07
585 查看
最近在做图像算法,对图像性能指标进行测试。主要包括PSNR(峰值信噪比)、NC(归一化相关系数)、SSIM(结构相似性)等,下面对这三个指标做简单介绍。
PSNR:峰值信噪比,一种评价图像的客观标准,用来评估图像的保真性。峰值信噪比经常用作图像压缩等领域中信号重建质量的测量方法,它常简单地通过均方差(MSE)进行定义,使用两个m×n单色图像I和K。PSNR的单位为分贝dB。计算公式如下:
其中,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是指经过简单的数字指纹加密的图像或失真的图像。(这里用到的数字指纹加密是指将图像随机数量像素点进行小范围的改变,肉眼无法辨别)。
测试一:使用Windows自带的“郁金香”图片,先生成数字指纹图像,比较图像的失真结果。
原图 数字指纹加密后
测试结果:
测试二:用原图和经过噪声攻击的图像进行测试。
测试结果:
PSNR:峰值信噪比,一种评价图像的客观标准,用来评估图像的保真性。峰值信噪比经常用作图像压缩等领域中信号重建质量的测量方法,它常简单地通过均方差(MSE)进行定义,使用两个m×n单色图像I和K。PSNR的单位为分贝dB。计算公式如下:
其中,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是指经过简单的数字指纹加密的图像或失真的图像。(这里用到的数字指纹加密是指将图像随机数量像素点进行小范围的改变,肉眼无法辨别)。
#include <cstdio> #include <cmath> #include <ctime> #include <cstdlib> #include "cv.h" #include "highgui.h" //计算两幅图像的保真性 //参数: src 原图像 // key 指纹加密的图像 double Psnr( IplImage* src, IplImage* key ) { int width = src->width; //图像宽 int height = src->height; //图像高 double mse = 0.0; //MSE为均方差 CvScalar s_src; //原图像的像素通道结构体 CvScalar s_key; //加密后的像素通道结构体 //计算MSE——均方差 for( int row = 0; row < height; row++ ) { for( int col = 0; col < width; col++ ) { s_src = cvGet2D( src, row, col ); s_key = cvGet2D( key, row, col ); double src_r = s_src.val[0]; //取出G通道的像素值 double key_r = s_key.val[0]; //if( src_r != key_r ) { //printf( "%.lf %.lf\n", src_r, key_r ); //char ch = getchar(); //} mse += ( src_r - key_r ) * ( src_r - key_r ); //计算方差 } } const double MAX = 255.0; //最大峰值为255 //方法一 double temp = MAX * MAX * ( double )width * ( double )height; double r = temp / mse; r = 10.0 * log10( r ); //方法二,计算结果是一样的 //mse = mse / ( width * height ); //printf( "均方误差: %lf\n", mse ); //mse = sqrt( mse ); //double temp = MAX; //double r = temp / mse; //r = 20.0 * log10( r ); //打印的中间结果信息 //printf( "temp: %lf\n", temp ); //printf( "sum: %lf\n", sum ); //printf( "%lf\n", r ); return r; } //计算两幅图像的鲁棒性 //参数: src 原图像 // key 指纹加密的图像 double Nc( IplImage* src, IplImage* key ) { int width = src->width; //图像宽 int height = src->height; //图像高 CvScalar s_src; //原图像的像素通道结构体 CvScalar s_key; //加密后的像素通道结构体 double d = 0.0; double d_src = 0.0; double d_key = 0.0; for( int row = 0; row < height; row++ ) { for( int col = 0; col < width; col++ ) { s_src = cvGet2D( src, row, col ); s_key = cvGet2D( key, row, col ); double src_r = s_src.val[0]; //取出G通道的像素值 double key_r = s_key.val[0]; d += src_r * key_r; d_src += src_r * src_r; d_key += key_r * key_r; } } //nc是鲁棒性指标 double nc = 0.0; nc = d / ( sqrt( d_src ) * sqrt( d_key ) ); return nc; } //计算两幅图像的结构相似性 //参数: src 原图像 // key 指纹加密的图像 double Ssim( IplImage* src, IplImage* key ) { int width = src->width; //图像宽 int height = src->height; //图像高 CvScalar s_src; //原图像的像素通道结构体 CvScalar s_key; //加密后的像素通道结构体 double mu_src = 0.0; //原图像均值 double mu_key = 0.0; //加密后的图像均值 int row, col; for( row = 0; row < height; row++ ) { for( col = 0; col < width; col++ ) { s_src = cvGet2D( src, row, col ); s_key = cvGet2D( key, row, col ); double src_r = s_src.val[0]; //取出G通道的像素值 double key_r = s_key.val[0]; mu_src += src_r; mu_key += key_r; } } mu_src = mu_src / ( width * height ); //原图像均值 mu_key = mu_key / ( width * height ); //加密图像均值 //打印的中间结果信息 //printf( "src的均值: %lf\n", mu_src ); //printf( "key的均值: %lf\n", mu_key ); double sigma_src2 = 0.0; //原图像方差,即sigma_src^2 double sigma_key2 = 0.0; //加密图像方差,即sigma_key^2 double sigma_s_k2 = 0.0; //原图和加密图像的方差,即sigma_s_k^2 double sigma_src = 0.0; //原图像标准差 double sigma_key = 0.0; //加密图像标准差 double sigma_s_k = 0.0; //原图像和加密图像的标准差 for( row = 0; row < height; row++ ) { for( col = 0; col < width; col++ ) { s_src = cvGet2D( src, row, col ); s_key = cvGet2D( key, row, col ); double src_r = s_src.val[0]; //取出G通道的像素值 double key_r = s_key.val[0]; sigma_src2 += ( src_r - mu_src ) * ( src_r - mu_src ); sigma_key2 += ( key_r - mu_key ) * ( key_r - mu_key ); sigma_s_k2 += ( src_r - mu_src ) * ( key_r - mu_key ); } } sigma_src2 = sigma_src2 / ( width * height - 1 ); sigma_key2 = sigma_key2 / ( width * height - 1 ); sigma_s_k2 = sigma_s_k2 / ( width * height - 1 ); sigma_src = sqrt( sigma_src2 ); sigma_key = sqrt( sigma_key2 ); sigma_s_k = sqrt( sigma_s_k2 ); //打印的中间结果信息 //printf( "sigma_src: %lf\n", sigma_src ); //printf( "sigma_key: %lf\n", sigma_key ); //printf( "sigma_s_k: %lf\n", sigma_s_k ); //固定参数,为常量 //c1,c2,c3是用来维持稳定的常数 //MAX是像素值的动态范围 const double k1 = 0.01; const double k2 = 0.03; const int MAX = 255; double c1 = ( k1 * MAX ) * ( k1 * MAX ); double c2 = ( k2 * MAX ) * ( k2 * MAX ); double c3 = c2 / 2; //亮度、对比度、结构三方面度量图像相似性 double light = ( 2 * mu_src * mu_key + c1 ) / ( mu_src * mu_src + mu_key * mu_key + c1 ); double contrast = ( 2 * sigma_src * sigma_key + c2 ) / ( sigma_src2 + sigma_key2 +c2 ); double structure = ( sigma_s_k2 + c3 ) / ( sigma_src * sigma_key + c3 ); //打印的中间结果信息 //printf( "light: %lf\n", light ); //printf( "contrast: %lf\n", contrast ); //printf( "structure: %lf\n", structure ); //方法一 //亮度 * 对比度 * 结构相似度 double ssim = light * contrast * structure; //方法二,计算结果是一样的 //double ssim = light * ( ( 2 * sigma_s_k2 + c2 ) / (sigma_src2 + sigma_key2 + c2 ) ); return ssim; } void KeyImg( IplImage* src ) { int n = 0; int width = src->width; //图像宽 int height = src->height; //图像高 printf( "图像宽: %d, 高: %d\n", width, height ); printf( "输入嵌入的像素点位数: " ); scanf( "%d", &n ); int count = 0; srand( (unsigned)time(NULL) ); CvScalar s; IplImage* keyImg; keyImg = cvCreateImage( cvGetSize( src ), IPL_DEPTH_8U, 1 ); keyImg = cvCloneImage( src ); while( count < n ) { int x = rand() % width; int y = rand() % height; s = cvGet2D( keyImg, y, x ); double b = s.val[0]; double g = s.val[1]; double r = s.val[2]; //printf( "修改前: %0.lf, %0.lf, %0.lf\n ", s.val[0], s.val[1], s.val[2] ); int temp = rand() % 2; if( temp == 0 ) { s.val[0] -= 10.0; } else if( temp == 1 ) { s.val[0] += 10.0; } cvSet2D( keyImg, y, x, s ); //s = cvGet2D( keyImg, y, x ); //printf( "修改后: %0.lf\n", s.val[0] ); count++; } cvSaveImage( "Test.bmp", keyImg ); //cvNamedWindow("image", CV_WINDOW_AUTOSIZE); //创建窗口 //cvShowImage("image", keyImg); //显示图像 cvWaitKey(0); printf( "图像生成成功!\n" ); } int main() { IplImage* src = NULL; IplImage* key = NULL; src = cvLoadImage( "Flower.bmp", CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR ); //生成一张加密的指纹图片 //KeyImg( src ); key = cvLoadImage( "水印Flower.bmp", CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR ); double psnr = 0.0; double nc = 0.0; double ssim = 0.0; psnr = Psnr( src, key ); nc = Nc( src, key ); ssim = Ssim( src, key ); printf( "保真性: %lf\n", psnr ); printf( "鲁棒性: %lf\n", nc ); printf( "结构相似性: %lf\n", ssim ); return 0; }
测试一:使用Windows自带的“郁金香”图片,先生成数字指纹图像,比较图像的失真结果。
原图 数字指纹加密后
测试结果:
测试二:用原图和经过噪声攻击的图像进行测试。
测试结果:
相关文章推荐
- Hadoop项目实战---黑马论坛日志分析
- 锁定Mac的键盘:连击5次option键
- 常用的Linux组合命令备忘
- DevOpt
- linux socket 编程(二)
- LINUX下PHP安装VLD扩展,利用opcode优化php代码
- 发布ASP.NET Core程序到Linux生产环境
- zabbix监控ap_h3c交换口流量
- openfire好友管理
- opendir, readdir
- 转: Linux 技巧:让进程在后台可靠运行的几种方法
- linux系统下安装php的pcntl扩展
- linux 操作系统中cp复制命令的使用
- docker 入门
- Tomcat能承受的极限压力测试
- linux 基础学习入门 2
- 利用OpenCV的Grabcut()函数实现图像的前景与背景的分割-并对Grabcut()作详细介绍
- 一些cmd命令和linux触摸板关启命令
- SOA标准之----SCA架构思想
- nginx应用场景