Skip to content
AI360Xpert
Beta

PSNR SSIM LPIPS Image Quality

Three fidelity lenses for restored images: pixel error, structural match and learned perceptual distance.

PSNR, SSIM and LPIPS score the same restored patch differently, so pixel, structure and perception disagree on purpose
PSNR, SSIM and LPIPS score the same restored patch differently, so pixel, structure and perception disagree on purpose

Why Does This Exist?

Restored images need numbers, but pixel error alone rewards blur. A shifted sharp edge looks worse by pixels than a blurry mess, yet humans prefer the edge. PSNR prices mean squared error, SSIM prices local structure, LPIPS prices deep-feature distance, so restoration reports carry all three.

This page gives formulas, one recomputed toy patch and misread traps.

Think of It Like This

Ruler, tracing and art teacher

PSNR is a ruler on pixel differences. SSIM traces shapes and asks if edges line up. LPIPS is an art teacher judging whether two patches feel alike.

Same homework, three grades that disagree usefully.

How It Actually Works

For max value MM and MSE, PSNR=10log⁡10(M2/MSE)\text{PSNR} = 10 \log_{10}(M^2 / \text{MSE}). Higher is better. SSIM blends luminance, contrast and structure in windows, higher is better with 1 as perfect. LPIPS is distance in normalized deep features, lower is better. Report all three because optimizing one degrades the others.

Worked toy patch

Take M=1M = 1 with MSE 0.010.01. PSNR is 10log⁡10(1/0.01)=10log⁡10(100)=10×2=2010 \log_{10}(1 / 0.01) = 10 \log_{10}(100) = 10 \times 2 = 20 dB. Halve MSE to 0.00250.0025 and PSNR rises to 10log⁡10(400)≈26.0210 \log_{10}(400) \approx 26.02 dB, a 6.026.02 dB lift for quarter error. SSIM and LPIPS need real windows and nets, so treat them qualitatively here: identical patches give SSIM 1 and LPIPS 0.

Code

PSNR from MSE, the only one hand-computable here.

import numpy as np

def psnr(mse: float, peak: float = 1.0) -> float:    return round(float(10 * np.log10(peak ** 2 / max(mse, 1e-12))), 2)

print(psnr(0.01), psnr(0.0025))# -> 20.0 26.02

MSE 0.01 gives 20 dB, quarter error gives about 26.02 dB.

Watch Out For

Shipping on PSNR while images look worse

Blur lifts PSNR by killing squared error yet destroys texture. The symptom is a higher dB with mushy outputs. Fix it by gating releases on LPIPS and blind looks beside PSNR.

The Quick Version

  • PSNR is 10log⁡10(M2/MSE)10 \log_{10}(M^2 / \text{MSE}), higher is better.
  • SSIM prices local structure with 1 as perfect, higher is better.
  • LPIPS is deep-feature distance, lower is better.
  • Toy MSE 0.01 gives 20 dB, 0.0025 gives about 26.02 dB.
  • Report all three because pixel wins can look worse.