圖片相似度----SSIM以及PSNR

對於兩張圖片到底有沒有相似
相似度多少
客觀的評量方法有很多種
MSE、SNR、PSNR、SSIM等等

而今天要講的是PSNR 跟 SSIM
至於為什麼?
因為碩論有用到
但並不代表我其他沒看啦
從幾個方法裡面挑對自己有利的

PSNR的定義
維基裡有提到

峰值信噪比(經常縮寫為PSNR)是一個表示信號最大可能功率和影響它的表示精度的破壞性雜訊功率的比值的工程術語。由於許多信號都有非常寬的動態範圍,峰值信噪比常用對數分貝單位來表示。
峰值信噪比經常用作圖像壓縮等領域中信號重建質量的測量方法,它常簡單地通過均方差MSE)進行定義。兩個m×n單色圖像IK,如果一個為另外一個的噪聲近似,那麼它們的的均方差定義為:
峰值信噪比定義為:
其中,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),結構相似性在影像品質的衡量上更能符合人眼對影像品質的判斷

l(x, y)比較x和y的亮度(luminance),c(x, y)比較x和y的對比度(contrast),s(x, y)比較x和y的結構(structure),α>0、β>0、γ>0、μσ,為調整l(x, y)、c(x, y)、s(x, y)相對重要性的參數,μx及μy、σx及σy分別為x和y的平均值標準差,σxy為x和y的共變異數,C1、C2、C3 皆為常數,用以維持l(x, y)、c(x, y)、s(x, y)的穩定。

而在使用上呢

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卻很低阿...
大家看的出來圖片上的差異嗎?

沒有留言:

張貼留言

About

努力在程式的大海
用力的揮動雙手
找出屬於自己的航線

Blog Archive

Traffic