OpenCV对图像的性能测试

来源:互联网 发布:图片分割打印软件 编辑:程序博客网 时间:2024/05/17 01:46

最近在做图像算法,对图像性能指标进行测试。主要包括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}} \right) = 20 \cdot \log_{10} \left( \frac{\mathit{MAX}_I}{\sqrt{\mathit{MSE}}} \right)

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

 

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

                                                                       

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

 

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




另一篇博文中的计算公式如下,也可以使用。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];        //取出B通道的像素值            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];        //取出B通道的像素值            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];        //取出B通道的像素值            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];        //取出B通道的像素值            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自带的“郁金香”图片,先生成数字指纹图像,比较图像的失真结果。

          

                                原图                                                                              数字指纹加密后

 

测试结果:

 

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

  

 

测试结果:


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 全身起疙瘩很痒怎么办 怀孕了肚子很痛怎么办 月经来肚子疼的厉害怎么办 孕妇9个月肚子疼怎么办 斗鱼身上长白点怎么办 8个月宝宝肚子疼怎么办 1岁半宝宝肚子痛怎么办 3岁宝宝肚子疼怎么办啊 吃的太辣肚子疼怎么办 2岁半宝宝肚子疼怎么办 2岁宝宝肚子痛哭怎么办 怀孕3个月拉肚子怎么办 一岁宝宝消化不良拉肚子怎么办 后背长好多痘痘怎么办 身上起疹子很痒怎么办 背上长好多痘痘怎么办 月经两三个月不来怎么办 来月经很少是褐色的怎么办 例假一天就没了怎么办 月经来一天就没了怎么办 假体隆胸8年怀孕怎么办 1岁宝宝长湿疹怎么办 2017卓达破产后怎么办 8岁儿童反复发烧怎么办 工商年报报错了怎么办 买房契税票丢了怎么办 合同地址写错了怎么办 货物被海关扣了怎么办 货被海关扣了怎么办 发票领用薄丢了怎么办 开票税率开错了怎么办 开错税率过月了怎么办 公司开不下去了怎么办 想注册一个公司怎么办手续 税率是3%开成5%怎么办 分列后0变没了怎么办 excel中求和得0怎么办 京东账号被黑了怎么办 合同上写错金额怎么办 裤子穿久了发亮怎么办 皮衣穿久了松了怎么办