相似度多少
客觀的評量方法有很多種
MSE、SNR、PSNR、SSIM等等
而今天要講的是PSNR 跟 SSIM
至於為什麼?
因為碩論有用到
但並不代表我其他沒看啦
從幾個方法裡面挑對自己有利的
PSNR的定義
在維基裡有提到
峰值信噪比定義為:
其中,MAXI是表示圖像點顏色的最大數值,如果每個採樣點用 8 位表示,那麼就是 255。更為通用的表示是,如果每個採樣點用 B 位線性脈衝編碼調製表示,那麼 MAXI 就是
- .
對於每點有RGB三個值的彩色圖像來說峰值信噪比的定義類似,只是均方差是所有方差之和除以圖像尺寸再除以 3。
圖像壓縮中典型的峰值信噪比值在 30 到 40dB 之間,愈高愈好。
峰值信噪比(PSNR),是一種評價圖像的客觀標準。PSNR是「Peak Signal to Noise Ratio」的縮寫。
但是PSNR的分數無法和人眼看到的視覺品質完全一致,有可能PSNR較高者看起來反而比PSNR較低者差。這是因為人眼的視覺對於誤差的敏感度並不是絕對的,其感知結果會受到許多因素的影響而產生變化(例如:人眼對空間頻率較低的對比差異敏感度較高,人眼對亮度對比差異的敏感度較色度高,人眼對一個區域的感知結果會受到其周圍鄰近區域的影響)。
一般而言30db以下人眼看就不能容忍了。
PSNR在OpenCV裡面可以直接叫出
#include <iostream>
#include <opencv2\opencv.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat mat_1, mat_2;
mat_1 = imread("Lena.jpg",1);
mat_2 = imread("Lena.jpg",1);
if (mat_1.empty() != 0)
{
return -1;
}
if (mat_2.empty() != 0)
{
return -1;
}
GaussianBlur(mat_2, mat_2, Size(5, 5), 0, 0);
imshow("Src", mat_1);
imshow("Dst", mat_2);
cout << PSNR(mat_1, mat_2) << "db" << endl;
cvWaitKey(0);
return 0;
}
右邊那張是高斯模糊過後的圖片
PSNR值為28,可以很明顯看出有啥不同
PSNR也可以自己寫
但值是一樣的
double getPSNR(const Mat& I1, const Mat& I2)
{
Mat s1;
absdiff(I1, I2, s1); // |I1 - I2|
s1.convertTo(s1, CV_32F); // cannot make a square on 8 bits
s1 = s1.mul(s1); // |I1 - I2|^2
Scalar s = sum(s1); // sum elements per channel
double sse = s.val[0] + s.val[1] + s.val[2]; // sum channels
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;
}
}
剛剛有提到PSNR的缺點,而SSIM剛好可以彌補這項缺點
定義:
結構相似性指標(英文:structural similarity index,SSIM index)是一種用以衡量兩張數位影像相似程度的指標。當兩張影像其中一張為無失真影像,另一張為失真後的影像,二者的結構相似性可以看成是失真影像的影像品質衡量指標。相較於傳統所使用的影像品質衡量指標,像是峰值信噪比(英文:PSNR),結構相似性在影像品質的衡量上更能符合人眼對影像品質的判斷。
而在使用上呢
double getMSSIM(const Mat& i1, const Mat& i2)
{
const double C1 = 6.5025, C2 = 58.5225;
/***************************** INITS **********************************/
int d = CV_32F;
Mat I1, I2;
i1.convertTo(I1, d); // cannot calculate on one byte large values
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
/*************************** END INITS **********************************/
Mat mu1, mu2; // PRELIMINARY COMPUTING
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;
///////////////////////////////// FORMULA ////////////////////////////////
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
double ssim_rate = (mssim.val[2] * 100 + mssim.val[1] * 100 + mssim.val[0] * 100) / 3;
return ssim_rate;
}
可以看到值為87%
通常在95%以下人眼就可以感覺得出來
這樣比較PSNR跟SSIM似乎沒什麼感覺
拿我的碩論中的比較就可以很明顯感覺的到
就是這樣
SSIM結構相似度很高
可是PSNR卻很低阿...
大家看的出來圖片上的差異嗎?
沒有留言:
張貼留言