在瞭解峰值信號雜訊比 (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)同樣的影像來示範。 […]
讚讚