計算PSNR-python

峯值信噪比(Peak Signal to Noise Ratio,PSNR)經常用來評價圖像質量。對於一張RGB三通道圖像,其計算公式如下:

先計算圖像與Ground Truth的均方誤差MSE:

MSE=\frac{1}{mnc}\sum_{0}^{m-1}\sum_{0}^{n-1}\sum_{0}^{c-1}= \left \| I(m,n,c)-gt(m,n,c) \right \|^{2}

再計算PSNR:

PSNR=10\cdot log10(\frac{MAX_{I}^{2}}{MSE})=20\cdot log10(\frac{MAX_{I}}{\sqrt{MSE}})

計算PSNR的Python代碼,網上有下面兩種:

import cv2
import numpy as np
import math
 
def psnr1(img1, img2):
   mse = np.mean((img1 - img2) ** 2 )
   if mse < 1.0e-10:
      return 100
   return 10 * math.log10(255.0**2/mse)
 
def psnr2(img1, img2):
   mse = np.mean( (img1/255. - img2/255.) ** 2 )
   if mse < 1.0e-10:
      return 100
   PIXEL_MAX = 1
   return 20 * math.log10(PIXEL_MAX / math.sqrt(mse))

理論上,這兩種計算方式都對應上面的計算公式,在輸入圖像一樣的情況下,這兩段代碼的結果應該是一樣的。但是,在調用這段代碼的時候,我發現這兩者的結果卻相差很遠,同樣的圖片,psnr1的結果大概是29,而psnr2的結果是12。

gt = cv2.imread('1.jpg')
img= cv2.imread('2.jpg')
 
print(psnr1(gt,img))
print(psnr2(gt,img))

這是輸出的結果: 

 

單看代碼的話完全看不出來任何問題,後來我輸出了這兩張圖像作差的結果,發現所有的值都是在0-255之間的,比如img1的一個像素值是30,img2的一個像素值是60,二者作差,本來應該是-30,但是結果卻是226,即對於負值,輸出要加上256。所以,問題就出在這行代碼上:

mse = np.mean((img1 - img2) ** 2 )

如果img1某個點的像素比img2小,而兩者差別又比較大,這個絕對值比較大的負值就會變成一個比較小的正值,MSE的結果也會偏小,那麼PSNR的值就會偏大。

只要把上面那行代碼改成mse = np.mean((img1/1.0 - img2/1.0) ** 2 )就可以了。

最後,我們發現這兩個結果是一樣的了。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章