在瞭解峰值信號雜訊比 (Peak Signal to Noise Ratio)定義之後,接下來當然就來驗證它的威力~
在此我特地找了png檔(無損壓縮)的影像,用nEOiMAGING影像處理軟體,將它另存為jpg檔(有損壓縮)的影像,其中jpg又有分壓縮品質。用肉眼也許看不太出來其中的差異,然而卻很容易從檔案大小看出端倪,壓縮品質越差,檔案大小越小。
除了從檔案大小可以知道影像品質的差異,我們還可以從PSNR這個衡量方法來驗證,定義可以參考峰值信號雜訊比 (Peak Signal to Noise Ratio)。這裡只列出公式:
Peak就是指8 bits表示法的最大值255。MSE指 Mean Square Error,In指原始影像第n個pixel值,Pn指經處理後的影像第n個pixel值。PSNR的單位為dB。
/**
Theme: PSNR (Peak Signal to Noise Ratio)
compiler: Dev C++ 4.9.9.2
Library: OpenCV 2.0
Date: 102/01/06
Author: HappyMan
Blog: https://cg2010studio.wordpress.com/
*/
#include <cv.h>
#include <highgui.h>
#include<iostream>
using namespace std;
int main(){
IplImage *src1= cvLoadImage("landscape.png");
IplImage *src2= cvLoadImage("landscape100Q.jpg");
long long int sigma = 0;
double MSE = 0.0;
double PSNR = 0.0;
int frameSize = src1->height*src1->width*3;
int blue1=0, blue2=0;
int green1=0, green2=0;
int red1=0, red2=0;
// width x height -> [height][width]
for(int i=0;i<src1->height;i++){
for(int j=0;j<src1->widthStep;j=j+3){
blue1=(int)(uchar)src1->imageData[i*src1->widthStep+j];//Blue
green1=(int)(uchar)src1->imageData[i*src1->widthStep+j+1];//Green
red1=(int)(uchar)src1->imageData[i*src1->widthStep+j+2];//Red
blue2=(int)(uchar)src2->imageData[i*src2->widthStep+j];//Blue
green2=(int)(uchar)src2->imageData[i*src2->widthStep+j+1];//Green
red2=(int)(uchar)src2->imageData[i*src2->widthStep+j+2];//Red
sigma+=(blue1-blue2)*(blue1-blue2)+
(green1-green2)*(green1-green2)+
(red1-red2)*(red1-red2);
}
}
MSE=sigma/(double)frameSize;
PSNR=10*log10(255*255/MSE);
cout<<"sigma: "<<sigma<<endl;;
cout<<"MSE: "<<MSE<<endl;;
cout<<"PSNR: "<<PSNR<<endl;;
system("pause");
cvWaitKey(0);
return EXIT_SUCCESS;
}
我實驗幾張圖,分別由png檔轉存jpg檔為不同壓縮品質(100%+High Quality、100%、90%、60%、30%、10%),再與png檔做比較。
執行結果:
100%+High Quality:
sigma: 339922
MSE: 0.491785
PSNR: 51.213
請按任意鍵繼續 . . .
100%:
sigma: 16337462
MSE: 23.6364
PSNR: 34.395
請按任意鍵繼續 . . .
90%:
sigma: 25189183
MSE: 36.4427
PSNR: 32.5147
請按任意鍵繼續 . . .
60%:
sigma: 56718531
MSE: 82.0581
PSNR: 28.9896
請按任意鍵繼續 . . .
30%:
sigma: 75184622
MSE: 108.774
PSNR: 27.7656
請按任意鍵繼續 . . .
10%:
sigma: 110296808
MSE: 159.573
PSNR: 26.1012
請按任意鍵繼續 . . .
比較讓我好奇的是100%+高品質壓縮影像jpg的檔案大小,居然比原始影像png的檔案大!
通常PSNR值越高表示品質越好,一般而言當PSNR的值<30db時,代表以人的肉眼看起來是不能容忍的範圍。因此大部分PSNR值皆要>30db。但PSNR高,並不代表影像品質一定好,有時候還是必須靠人的肉眼輔助來判斷影像的品質才較為正確。
JPG和PNG主要差異為何呢?這裡引述他人翻譯WiKi的幾段話:
JPEG在面對自然影像的時候,由於是採用失真壓縮演算法,因此壓縮率比PNG還要大。簡單來說,如果一張風景照片 你用JPG來存,需要1MB 的話,用PNG就要5MB~10MB,雖然PNG檔案較大但是在視覺品質上面並沒有顯著的優越。
PNG在處理包含文字、線條和明顯輪廓的影像則較JPG來的優越,當影像有明顯輪廓邊緣,JPG的失真演算法在處理這種邊緣上就會產生瑕疵,PNG採用無失真演算法,因此影像品質較佳。
若影像儲存在未來是需要更進一步的編輯修改的話則PNG是比較好的選擇,若是用JPG不斷的存取編輯,那麼圖像的品質就越來越差了。當影像已經編輯完畢準備散發傳播的話,JPG則可以幫你縮小體積,卻不損失太多的畫質。
參考:WiKi – JPG、WiKi – PNG、利用OpenCV計算灰度圖像的峰值信噪比(PSNR)、在DEV-C++環境使用OpenCV-2.1.0-win32-vs2008計算PSNR範例[程式碼篇]、該用 PNG 還是 JPG 來存螢幕截圖。









Comments on: "[OpenCV] 峰值信號雜訊比 (Peak Signal to Noise Ratio)" (7)
請問一下成是第22行的
int frameSize = src1->height*src1->width*3;
這個應該是只圖像的大小吧?
為什麼還要在後面乘以三呢?
讚讚
嗨~問得很好!
因為影像為三通道RGB,
就如你從程式碼看到,
PSNR會各別計算此三個通道,
最後用來平均~
同理,若是灰階影像,也就是一通道,
就不必乘以三了~ 😀
讚讚
可是我把src1->width用cout出來以後已經是有乘以三的值了
這樣還需要再乘三嗎?
讚讚
我想應該是widthStep=width*3喔~ 😉
讚讚
呃…的確是widthStep沒錯
我誤解了
感謝撥冗回答Orz
讚讚
呵呵~ 😉
讚讚
[…] 在瞭解結構相似性 (Structural SIMilarity)後,接下來就是驗證它的效果~我使用和峰值信號雜訊比 (Peak Signal to Noise Ratio)同樣的影像來示範。 […]
讚讚