1.PSNR( Peak signal-to-noise ratio)。
详细代码及注释:
// 054 视频输入和相似度测量.cpp : 定义控制台应用程序的入口点。
//
#include
"stdafx.h"
#include
<iostream>
#include
<string>
#include
<iomanip>
//
#include
<sstream>
//
#include
<opencv2/imgproc/imgproc.hpp>
//
#include
<opencv2/core/core.hpp>
//
#include
<opencv2/highgui/highgui.hpp>
//
using namespace
std;
using namespace cv;
double getPSNR ( const
Mat& I1, const Mat& I2);
Scalar getMSSIM( const Mat& I1, const
Mat& I2);
int main(int argc,
char *argv[], char *window_name)
{
//设定PSNR算法的最小返回值为35
int
psnrTriggerValue=35;
int
delay=10;
//用构造函数的方法打开第一个视频;
VideoCapture
captRefrnc("Megamind.avi");
//用open函数打开第二个比较用的压缩后的视频
VideoCapture captUndTst;
captUndTst.open("Megamind_bugy.avi");
//判断是否打开视频
if (
!captRefrnc.isOpened()||!captUndTst.isOpened())
{
cout << "Could not
open reference " <<endl;
return -1;
}
char
c;
//waitKey的返回值
int frameNum =
-1;
//帧数计数器
//获取原视频的尺寸,
get 函数返回一个double类型的数据
Size refS = Size((int)
captRefrnc.get(CV_CAP_PROP_FRAME_WIDTH),(int)
captRefrnc.get(CV_CAP_PROP_FRAME_HEIGHT));
//获取压缩后视频的尺寸
Size uTSi = Size((int)
captUndTst.get(CV_CAP_PROP_FRAME_WIDTH),(int)
captUndTst.get(CV_CAP_PROP_FRAME_HEIGHT));
//尺寸不相同则退出
if (refS !=
uTSi)
{
cout << "Inputs have different
size!!! Closing." << endl;
return -1;
}
const char* WIN_UT = "Under Test";
const char*
WIN_RF = "Reference";
// Windows
namedWindow(WIN_RF, CV_WINDOW_AUTOSIZE );
namedWindow(WIN_UT, CV_WINDOW_AUTOSIZE );
cvMoveWindow(WIN_RF,
400
,
0);
//750, 2 (bernat =0)
cvMoveWindow(WIN_UT,
refS.width,
0);
//1500, 2
//输出视频的尺寸和总的帧数
cout
<< "Reference frame resolution:
Width=" << refS.width
<< " Height="
<< refS.height
<< " of nr#: "
<<
captRefrnc.get(CV_CAP_PROP_FRAME_COUNT)
<< endl;
//输出PSNR的最小返回值
cout << "PSNR trigger value "
<<
setiosflags(ios::fixed) <<
setprecision(3) << psnrTriggerValue
<< endl;
Mat frameReference, frameUnderTest;
double
psnrV;
Scalar
mssimV;
while( true) //Show the image captured in the window and
repeat
{
//将VideoCapture 对象里释放出每一帧图像并保存成
Mat 格式
//两种方法,一:重载操作符>>;二:read
captRefrnc >> frameReference;
captUndTst.read(frameUnderTest);
// captUndTst >>
frameUnderTest;
if( frameReference.empty() ||
frameUnderTest.empty())
{
cout << " <
< < Game
over! > >
> ";
break;
}
++frameNum;
cout <<"Frame:"
<< frameNum
<<"# ";
///////////////////////////////// PSNR
////////////////////////////////////////////////////
psnrV =
getPSNR(frameReference,frameUnderTest);
//get PSNR
cout << setiosflags(ios::fixed)
<< setprecision(3)
<< psnrV
<< "dB";
//////////////////////////////////// MSSIM
/////////////////////////////////////////////////
if (psnrV < psnrTriggerValue
&&
psnrV)
//PSNR算法计算出的结果低于输入值,调用SSIM算法
{
mssimV = getMSSIM(frameReference,frameUnderTest);
cout << " MSSIM: "
<< " R "
<< setiosflags(ios::fixed)
<< setprecision(2)
<< mssimV.val[2] * 100
<< "%"
<< " G "
<< setiosflags(ios::fixed)
<< setprecision(2)
<< mssimV.val[1] * 100
<< "%"
<< " B "
<< setiosflags(ios::fixed)
<< setprecision(2)
<< mssimV.val[0] * 100
<< "%";
}
cout << endl;
////////////////////////////////// Show Image
/////////////////////////////////////////////
imshow( WIN_RF, frameReference);
imshow( WIN_UT, frameUnderTest);
c = cvWaitKey(delay);
if (c == 27) break;
}
return 0;
}
//PSNR( Peak
signal-to-noise ratio)。使用“局部均值误差”来判断差异的最简单的方法
//考察压缩后的视频时,返回值值大约在30到50之间,数字越大则表明压缩质量越好
//PSNR算法简单,检查的速度也很快。但是其呈现的差异值有时候和人的主观感受不成比例。
double getPSNR(const Mat& I1, const
Mat& I2)
{
Mat
s1;
absdiff(I1,
I2,
s1);
// |I1 - I2|
s1.convertTo(s1, CV_32F); //不能在8位矩阵上做平方运算
s1 =
s1.mul(s1);
// s1*s1,即|I1 - I2|^2
Scalar s =
sum(s1);
// 分别叠加每个通道的元素,存于s中
double sse = s.val[0] + s.val[1] + s.val[2]; // 叠加所有通道元素
if( sse <= 1e-10) // for small values return
zero
return 0;
else
{
double mse =sse /(double)(I1.channels() *
I1.total());
double psnr = 10.0*log10((255*255)/mse);
return psnr;
}
}
//SSIM算法,structural
similarity index 结构相似性 的算法
//针对图像的每个通道返回一个相似度,取值范围应该在0到1之间,取值为1时代表完全符合。
Scalar getMSSIM( const Mat& i1, const
Mat& i2)
{
const double
C1 = 6.5025, C2 = 58.5225;
int
d
= CV_32F;
Mat I1, I2;
i1.convertTo(I1,
d);
// 不能在单字节像素上进行计算,范围不够。
i2.convertTo(I2, d);
Mat I2_2 =
I2.mul(I2);
// I2^2
Mat
I1_2 =
I1.mul(I1);
// I1^2
Mat
I1_I2 =
I1.mul(I2);
// I1 * I2
///初步计算
Mat mu1,
mu2;
//高斯平滑
GaussianBlur(I1, mu1, Size(11, 11), 1.5);
GaussianBlur(I2, mu2, Size(11, 11), 1.5);
Mat mu1_2
= mu1.mul(mu1);
Mat
mu2_2
= mu2.mul(mu2);
Mat mu1_mu2
= mu1.mul(mu2);
Mat sigma1_2, sigma2_2, sigma12;
GaussianBlur(I1_2, sigma1_2, Size(11, 11), 1.5);
sigma1_2 -=
mu1_2;
GaussianBlur(I2_2, sigma2_2, Size(11, 11), 1.5);
sigma2_2 -=
mu2_2;
GaussianBlur(I1_I2, sigma12, Size(11, 11), 1.5);
sigma12 -=
mu1_mu2;
//公式
Mat t1, t2,
t3;
t1 = 2 * mu1_mu2 + C1;
t2 = 2 *
sigma12 + C2;
t3 =
t1.mul(t2);
// t3 = ((2*mu1_mu2 + C1).*(2*sigma12 + C2))
t1 = mu1_2 + mu2_2 + C1;
t2 =
sigma1_2 + sigma2_2 + C2;
t1 =
t1.mul(t2);
// t1 =((mu1_2 + mu2_2 + C1).*(sigma1_2 + sigma2_2 +
C2))
Mat ssim_map;
divide(t3,
t1,
ssim_map);
// ssim_map = t3./t1;
Scalar mssim = mean( ssim_map ); // mssim = average of ssim
map
return
mssim;
}
运行结果: