Skip to content

Dear Internet Explorer user: Your browser is no longer supported

Please switch to a modern browser such as Microsoft Edge, Mozilla Firefox or Google Chrome to view this website's content.

Peak Signal-to-Noise Ratio (PSNR) in Python

Quantitatively check the quality of a compressed image using a simple Python code for calculating the Peak Signal-to-Noise Ratio (PSNR) between two images.

When images are compressed, resized or converted to different formats, there can be a loss of fidelity between the original and the copy.

A common method for quantitatively checking the effect that format changes or compression may have had on an image is to use the peak signal-to-noise ratio (PSNR), which is the ratio between the maximum possible power of an image and the power of corrupting noise that affects the quality of its representation.

Mathematically, PSNR is represented as follows:

\[PSNR = 20\times\log_{10}\left(\frac{MAX_{f}}{\sqrt{MSE}}\right)\]

where the Mean Squared Error (MSE) is:

\[MSE = \displaystyle \frac{1}{mn} \sum\limits_{i=0}^{m-1}\displaystyle\sum\limits_{j=0}^{n-1}\lVert f(i,j)-g(i,j)\lVert^2\]


The mean squared error (MSE) permits a comparison of the “true” pixel values in the original image with our copied image. The MSE represents the average of the squares of the “errors” between the two. The error is the amount by which the values of the original image differ from the copied image.

PSNR is usually expressed in terms of the logarithmic decibel scale where the larger the value of PSNR, the more efficient is a corresponding compression or filter method.

Fortunately, it is fairly easy to implement PSNR in Python on the command line, using OpenCV:

#!/usr/bin/env python

from math import log10, sqrt 
import cv2 
import numpy as np
import argparse

def options():
 parser = argparse.ArgumentParser(description="Read image metadata")
 parser.add_argument("-o", "--original", help="Input image file.", required=True)
 parser.add_argument("-c", "--copy", help="Input image file.", required=True)
 args = parser.parse_args()
 return args

def PSNR(original, compressed):
 mse = np.mean((original - compressed) ** 2)
 if(mse == 0):
  return 100
 max_pixel = 255.0
 psnr = 20 * log10(max_pixel / sqrt(mse))
 return psnr 
def main(): 

 # Get options
 args = options()

 # Import images
 original = cv2.imread(args.original)
 compressed = cv2.imread(args.copy, 1)

 # Check for same size and ratio and report accordingly
 ho, wo, _ = original.shape
 hc, wc, _ = compressed.shape
 ratio_orig = ho/wo
 ratio_comp = hc/wc
 dim = (wc, hc)

 if round(ratio_orig, 2) != round(ratio_comp, 2):
  print("\nImages not of the same dimension. Check input.")

 # Resize original if the compressed image is smaller
 elif ho > hc and wo > wc:
  print("\nResizing original image for analysis...")
  original = cv2.resize(original, dim)

 elif ho < hc and wo < wc:
  print("\nCompressed image has a larger dimension than the original. Check input.")

 value = PSNR(original, compressed)
 print("\nPeak Signal-to-Noise Ratio (PSNR) value is", value, "dB")

if __name__ == '__main__':

The code takes two inputs on the command line:

If the python file were saved as, implemenation would be as follows: /path/to/ -o /path/to/original.ext -c /path/to/copy.ext

Before calculating PSNR, the above code will check that the two images are the same size. If the copy is smaller, then the original will be reduced to the same dimensions using OpenCV’s cv2.resize() function which uses a bilinear interpolation. (Ideally, the two images would have identical dimensions and this step would not be necessary but your application will determine this). The aspect ratio of each image is also checked before proceeding.

This code has been posted to GitHub Gist.



No comments have yet been submitted. Be the first!

Have Your Say

The following HTML is permitted:
<a href="" title=""> <b> <blockquote cite=""> <code> <em> <i> <q cite=""> <strike> <strong>

Comments will be published subject to the Editorial Policy.