1

I downloaded two images (original uncompressed PNG and Q = 90 compressed JPG, reported PSNR is 45.53 dB) from Wikipedia's PSNR article. Then, I ran:

import cv2

img1 = cv2.imread('PSNR-example-base.png')
img2 = cv2.imread('PSNR-example-comp-90.jpg')
cv2.PSNR(img1, img2)

But the output value I obtain is 29.436334461883582, instead of 45.53.

I've also tried Ryan SH's suggestion from this topic:

import numpy as np
import math

img1 = img1.astype(np.float64) / 255.
img2 = img2.astype(np.float64) / 255.
mse = np.mean((img1 - img2) ** 2)
10 * math.log10(1. / mse)

Obtaining, again, 29.43633446188358.

What am I doing wrong?

HansHirse
  • 18,010
  • 10
  • 38
  • 67
guigo
  • 11
  • 1
  • 3

1 Answers1

2

The cause for the difference is most likely hinted in the caption of the referenced images (emphasis by me):

Example luma PSNR values for a cjpeg compressed image at various quality levels.

The PSNR is not calculated for the whole RGB image like you did, but only for the image's luma ("brightness").

Also, I even couldn't reproduce the 29.4363... from your question. So, here's my code for comparison:

import cv2
import numpy as np
from skimage import io              # Only needed for web grabbing images, use cv2.imread for local images


def psnr(image1, image2):

    # OpenCV
    print('OpenCV PSNR: ', cv2.PSNR(image1, image2))

    # Own implementation
    mse = np.mean((image1.astype(np.float64) / 255 - image2.astype(np.float64) / 255) ** 2)
    print('Own implementation: ', 10 * np.log10(1. / mse))


def luma(image):
    return (0.299 * image[:, :, 2] + 0.587 * image[:, :, 1] + 0.114 * image[:, :, 0]).astype(np.uint8)
    # return (0.2126 * image[:, :, 2] + 0.7152 * image[:, :, 1] + 0.0722 * image[:, :, 0]).astype(np.uint8)
    # return (0.212 * image[:, :, 2] + 0.701 * image[:, :, 1] + 0.087 * image[:, :, 0]).astype(np.uint8)


# Calculate PSNR on referenced images
img1 = cv2.cvtColor(io.imread('https://upload.wikimedia.org/wikipedia/commons/d/d3/PSNR-example-base.png'), cv2.COLOR_RGB2BGR)
img2 = cv2.cvtColor(io.imread('https://upload.wikimedia.org/wikipedia/commons/2/2a/PSNR-example-comp-90.jpg'), cv2.COLOR_RGB2BGR)
psnr(img1, img2)

# Calculate luma PSNR on referenced images
psnr(luma(img1), luma(img2))

Output:

OpenCV PSNR:  39.021537956442224
Own implementation:  39.02153795644222
OpenCV PSNR:  44.79892614734474
Own implementation:  44.79892614734474

For me, the PSNR of the RGB image is way higher than the one you report. But, the PSNR for the luma does quite match the given value, although it's not exactly the same. I tested several luma calculations, none gave the exact result – but since it's not mentioned in the referenced example, how the luma was calculated, trying to reproduce the exact values is meaningless anyway.

Hope that helps!

HansHirse
  • 18,010
  • 10
  • 38
  • 67