Updated November 2026: new section on PSNR in image processing with the default peak value in scikit-image, OpenCV, MATLAB and TorchMetrics, a NumPy PSNR calculation, and the xpsnr filter status in FFmpeg 9.0 "Lei".

What is PSNR? The short answer

PSNR stands for Peak Signal-to-Noise Ratio: a full-reference metric that measures how much a compressed image or video frame differs from its original, expressed in decibels (dB). It is computed as PSNR = 10 · log₁₀(MAX² / MSE), where MAX is the largest pixel value (255 for 8-bit) and MSE is the mean squared error between the two frames. Higher PSNR is better: for 8-bit lossy video, 30–50 dB is the normal range, below 30 dB errors are usually visible, above 40 dB the copy is close to the original, and identical frames score infinity. PSNR is fast and universal, but it only measures pixel error, so it is trustworthy for comparing encodes of the same source and weak at predicting how good video looks to a viewer.

Question PSNR at a glance
Full formPeak Signal-to-Noise Ratio
Formula10 · log₁₀(MAX² / MSE), MAX = 2B − 1 for B-bit video
Unitdecibels (dB), logarithmic
Higher or lower is better?Higher. +3 dB ≈ half the pixel error
Typical 8-bit video range30–50 dB; identical frames = ∞
What it measuresaverage pixel error against the original (full reference)
Valid forsame content, same codec: encoder tuning, RDO, regression gates, BD-rate
Not valid forranking quality across different clips, codecs or resolutions

Why this matters

If you measure video quality, PSNR is the first number you will see and the first one you will be tempted to over-trust. It appears in encoder logs, in FFmpeg output, in vendor benchmark charts, and in academic tables — usually with no explanation of what it can and cannot tell you. This article gives you that explanation, so you can read a PSNR figure the way a skeptic would: knowing what it measures, which comparisons it is valid for, and the exact content where it will mislead you. It is the foundation for the perceptual metrics that come next — SSIM and VMAF — both of which exist precisely because PSNR was not good enough.

What PSNR actually measures

Start with the thing PSNR is built on, because the name hides it. Underneath the decibels, PSNR (see the PSNR glossary entry) is a measurement of pixel error: how different is each pixel in the compressed video from the same pixel in the original, on average, squared.

Think of it as a spell-checker that counts wrong letters. Give it the original document and a copy, and it will tell you how many characters differ. What it will not tell you is whether the sentence still reads well — a typo in the headline and a typo in the footer count exactly the same. PSNR has the same blind spot. It counts how many pixel values changed and by how much, never asking whether those changes landed somewhere the eye is looking.

To measure that pixel error you need the pristine original, frame for frame. That makes PSNR a full-reference metric — a metric that compares the impaired video against the complete uncompressed master. If you do not have the original on disk, you cannot compute PSNR at all; on a live stream or a user-uploaded clip there is no master to reference, and the number simply does not exist. (The three reference setups — full, reduced, and no-reference — are covered in full-reference, reduced-reference, no-reference metrics; PSNR sits firmly in the first.)

From pixel error to decibels: the math, shown once

PSNR is computed in two steps. First you measure the raw error with the Mean Squared Error, almost always written MSE. Then you turn that error into decibels. Both steps are short, and seeing them once removes all the mystery.

The Mean Squared Error is exactly what its name says, read right to left: take the error at every pixel (original value minus compressed value), square it, then take the mean of all those squares across the whole frame. Squaring does two things: it makes every error positive so they do not cancel out, and it punishes big errors far more than small ones. For an image of width m and height n:

MSE = (1 / (m·n)) · Σ Σ [ I(i,j) − K(i,j) ]²

Here I is the original frame, K is the compressed frame, and the double sum runs over every pixel. An MSE of zero means the two frames are identical. A larger MSE means more error.

MSE on its own is awkward to read — its scale depends on the bit depth, and the numbers are unintuitive. So PSNR rescales it against the brightest possible pixel and takes the logarithm, which compresses a huge range of error into a friendly two-digit decibel number:

PSNR = 10 · log₁₀ ( MAX² / MSE )   [dB]

MAX is the largest value a pixel can take. For ordinary 8-bit video that is 255; for B bits per sample it is 2^B − 1 (1023 for 10-bit, 4095 for 12-bit). Because the formula divides MAX² by MSE, smaller error gives a larger PSNR — the scale runs the intuitive way, higher is better.

A worked example

Suppose you measure an 8-bit clip and find its MSE is 25. That means the average pixel is off by 5 levels (because 5² = 25) on a 0–255 scale — a small error. Plug it in:

PSNR = 10 · log₁₀ ( 255² / 25 )
     = 10 · log₁₀ ( 65025 / 25 )
     = 10 · log₁₀ ( 2601 )
     = 10 · 3.415
     = 34.15 dB

So a 5-level average error lands at about 34 dB. Now push the error up: an MSE of 100 (average error of 10 levels) gives 10 · log₁₀(65025 / 100) = 28.1 dB. Push it down to an average error of one level, an MSE of 1, and you get 10 · log₁₀(65025) = 48.13 dB. That figure is often quoted as the 8-bit "ceiling", but it is not one: MSE is an average, so it can fall below 1. If only one pixel in a 1920×1080 frame is off by one level, MSE is 1 / 2,073,600 and PSNR is about 111 dB. A perfect match has MSE = 0, the division blows up, and PSNR is infinite — which is why tools either print inf or clamp the value (see the table below).

How PSNR is computed. Two input plates - the original frame, the uncompressed master, and the compressed frame, what the encoder produced - merge into four numbered steps: difference, subtract each compressed pixel from the original; square, which drops the sign and punishes big errors more; average, whose mean of those squares is the Mean Squared Error; and decibels, which rescale MSE against the brightest pixel and take the log. Below sits the formula PSNR = 10 times log base 10 of MAX squared over MSE, with the note that MSE 25 on 8-bit video gives 34.15 dB. A closing line reads: smaller average error means larger PSNR; identical frames score infinity. Figure 1. PSNR in four steps: difference, square, average (MSE), then convert to decibels. The metric never looks at where the errors are — only how big they are on average.

The one rule of thumb worth memorizing

Because PSNR is logarithmic, there is a clean shortcut: every halving of the error adds about 3 dB (since 10 · log₁₀ 2 ≈ 3.01), and every doubling subtracts about 3 dB. So if encoder A scores 36 dB and encoder B scores 39 dB on the same clip, B has roughly half the pixel error of A. That 3-dB-per-doubling intuition is the single most useful thing to carry out of the math.

Reading a PSNR number: the decibel scale

A PSNR figure means nothing until you know what range to expect. For 8-bit lossy video and image compression, real-world PSNR almost always lands between 30 and 50 dB, and the bands inside that range have rough, well-worn meanings.

Below about 30 dB, errors are usually visible — the picture looks degraded to an attentive viewer. From 30 to about 40 dB you are in the normal operating range of streaming-grade compression, where quality is acceptable to good and most viewers are content. Above 40 dB the compressed frame is close to the original, and by the high 40s (an average error of about one level) the difference is near-imperceptible for 8-bit content. Higher bit depths shift the whole scale up: high-quality 12-bit imagery is judged at 60 dB or above, and 16-bit data runs from roughly 60 to 80 dB, because more bits mean a higher MAX and a higher ceiling.

The 8-bit PSNR decibel scale drawn from 20 to 50 dB in three bands: 20 to 30 dB where errors are usually visible, 30 to 40 dB the normal streaming range, and 40 to 50 dB near-imperceptible. Three worked examples are marked on it: MSE 100 at 28 dB, MSE 25 at 34.15 dB, and MSE 1 at 48.13 dB. Two notes below the scale: it is valid only when comparing encodes of the same content with the same codec, and higher bit depths shift it up, with 12-bit judged at 60 dB and above. Figure 2. The 8-bit PSNR scale with the worked examples placed on it. The bands are rules of thumb, not guarantees — content and codec move them.

The caveat attached to that scale is the most important sentence in this article. A PSNR value is only conclusively valid when you compare results from the same codec and the same content (Huynh-Thu and Ghanbari, Electronics Letters, 2008). A 38 dB score on an animation clip and a 38 dB score on a film grain clip do not mean the two look equally good — they mean nothing relative to each other. Use PSNR to compare two encodes of the same source, and the comparison is sound. Use it to rank quality across different sources, resolutions, or codecs, and you are reading tea leaves.

What is a good PSNR value? By bit depth and by tool

For 8-bit video, a good PSNR is roughly 35 dB and above: below 30 dB errors are usually visible, 30–40 dB is the normal range for streaming-grade compression, and above 40 dB the copy is close to the original. The same error reads as a higher number at higher bit depths, because MAX grows with the bits. The column "PSNR at MSE = 1" is the value for an average error of one code value, a useful reference point but not a hard limit.

Bit depth MAX PSNR at MSE = 1 Typical lossy range libvmaf PSNR cap
8-bit25548.13 dB30–50 dB60 dB
10-bit102360.20 dBshifted up by ~12 dB vs 8-bit for the same relative error72 dB
12-bit409572.25 dB60 dB and above is high quality84 dB
16-bit6553596.33 dB60–80 dB108 dB

Tools treat the top of the scale differently, so check which one produced a number before comparing near-lossless results. Netflix's libvmaf clamps PSNR at 60 dB for 8-bit, 72 dB for 10-bit, 84 dB for 12-bit and 108 dB for 16-bit input (libvmaf source, checked November 2026). FFmpeg's own psnr filter applies no such clamp: it reports values above 90 dB for near-identical frames and inf for identical ones. A "60 dB" from libvmaf and a "74 dB" from FFmpeg on the same pair can describe the same encode.

Luma, chroma, and the "average" you actually quote

There is one more wrinkle between the formula and the number in your log. Video is not one channel; it is split into brightness (luma, the Y component) and color (chroma, the U and V components). PSNR is computed separately for each, so a tool reports psnr_y, psnr_u, psnr_v, and a combined psnr_avg.

The eye is far more sensitive to brightness than to color, which is why encoders spend most of their bits on luma. For the same reason, the luma PSNR (psnr_y) is the figure most engineers quote — it tracks the part of the picture viewers notice. The combined average is weighted by how many pixels each plane has, and because chroma is usually subsampled, luma dominates it anyway. When you read or report a PSNR number, say which one it is; "PSNR 38 dB" with no component named is a small but real ambiguity.

How to compute PSNR with FFmpeg

You will rarely write the formula yourself. The everyday tool is FFmpeg, whose psnr filter takes two video inputs — the distorted clip first, the reference second — and prints the per-component and average PSNR.

# PSNR between a distorted encode and its reference master.
# Output prints psnr_y, psnr_u, psnr_v and psnr_avg to the console.
ffmpeg -i distorted.mp4 -i reference.mp4 \
  -lavfi psnr -f null -

To capture a value per frame — useful for finding the worst moments, not just the average — write a stats file:

# Per-frame PSNR written to psnr.log (n, mse_avg, psnr_avg, per-plane values).
ffmpeg -i distorted.mp4 -i reference.mp4 \
  -lavfi "psnr=stats_file=psnr.log" -f null -

The shape of the command encodes the full-reference contract: it will not run without both files. If you want PSNR, SSIM, and VMAF in a single pass, the libvmaf filter can emit all three — that workflow, with model selection and output parsing, is covered in depth in measuring quality with FFmpeg and libvmaf, and the encoder-side quick reference lives in Video Encoding's FFmpeg cheat sheet.

To make the math concrete at your desk, we built a small, dependency-light script that computes PSNR between two image or frame files from first principles — MSE, then decibels — and prints every intermediate value so you can see exactly where the number comes from. Download the from-scratch PSNR calculator (Python) and run it against your own frames.

The alignment trap

PSNR assumes the two videos line up exactly: the same frame, at the same resolution, with the same brightness. Compare frame 100 of the encode against frame 98 of the master — a two-frame temporal slip — and PSNR reports a quality collapse the eye would never see. A one-pixel spatial shift or a small brightness offset does the same. This sensitivity is why the ITU standardized a dedicated alignment-compensated PSNR, ITU-T J.340 (2010), which corrects for constant spatial shift, temporal shift, and luminance gain before scoring. The practical rule: if a PSNR score looks shockingly bad, suspect misalignment before you suspect the encoder. Calibrate first, score second.

PSNR in image processing

In image processing, PSNR is computed exactly as it is for video: the mean squared error between a reference image and a processed copy, converted to decibels with 10 · log₁₀(MAX² / MSE). It is the usual score for JPEG, WebP and AVIF compression tests, denoising, deblurring and super-resolution, because it is cheap and every library ships it. For a color image you either average the squared error over all three RGB channels or score only the luma (Y) channel; both are common, and the two give different numbers for the same image, so state which one you used.

The trap in image work is the peak value. The formula needs MAX, and each library guesses it differently when you do not pass it:

Library Call Peak value if you do not set it
scikit-image 0.26skimage.metrics.peak_signal_noise_ratio(image_true, image_test, data_range=...)estimated from the image data type; pass data_range explicitly
OpenCVcv2.PSNR(src1, src2, R)R = 255
MATLAB (Image Processing Toolbox)psnr(A, ref, peakval)255 for uint8, 1 for double/single
TorchMetrics 1.9PeakSignalNoiseRatio(data_range=...)set data_range yourself (a number, or a min/max tuple)

If your images are floats scaled to 0–1 and the tool assumes 255, the result is off by about 48 dB. A 10-bit or 16-bit image scored with a peak of 255 is wrong in the other direction. Set the peak to 2B − 1 for B-bit integer data, or to 1.0 for normalized floats, and write it down next to the number.

PSNR calculation in Python

The whole calculation fits in a few lines of NumPy. Convert to float first: subtracting two uint8 arrays wraps around below zero and silently corrupts the MSE.

import numpy as np

def psnr(ref, test, max_val=255.0):
    ref = ref.astype(np.float64)
    test = test.astype(np.float64)
    mse = np.mean((ref - test) ** 2)
    if mse == 0:
        return float("inf")  # identical images
    return 10 * np.log10(max_val ** 2 / mse)

# Every pixel off by 5 levels: MSE = 25, PSNR = 34.15 dB
ref = np.full((4, 4), 100, dtype=np.uint8)
print(psnr(ref, ref + 5))

The same pair through skimage.metrics.peak_signal_noise_ratio(ref, ref + 5, data_range=255) or cv2.PSNR(ref, ref + 5) returns the same 34.15 dB, which is a quick way to check that your peak value is set the way you think.

Why PSNR is a poor predictor of perceived quality

Here is the heart of the matter, and the reason every metric after PSNR exists. PSNR measures pixel error with perfect arithmetic and almost no understanding of vision. It has three blind spots that matter every day.

First, it treats every pixel as equally important. A pixel error in the sharp edge of a face and an identical error in a patch of flat sky contribute the same amount to the MSE, even though the eye forgives the sky and notices the face instantly. The metric has no idea where you are looking.

Second, it ignores structure and masking. Human vision hides errors in busy, textured, or high-contrast regions and exposes them in smooth ones — a property called visual masking. PSNR has no model of this, so it over-penalizes harmless noise in textured areas and under-penalizes banding in smooth gradients, exactly backwards from perception.

Third, it cannot tell two very different distortions apart if they have the same total error. A faint, even haze of noise spread across the whole frame and a chunk of ugly blocking concentrated in one corner can produce the same MSE — and therefore the same PSNR — while looking nothing alike to a viewer.

Two panels showing the same frame after two different encodes. On the left, light noise spread evenly across the whole picture, including the subject. On the right, a clean picture with heavy blocking concentrated on the subject's face. Both panels are labelled PSNR 34.1 dB; the left one looks fine to a viewer, the right one looks broken. A closing line reads: same average pixel error, so the same PSNR - the eye sees two very different pictures. Figure 3. Same PSNR, different quality. PSNR sums pixel error and cannot see that one distortion lands where the eye is looking and the other does not.

This is not a fringe complaint. The defining academic study on the question, Huynh-Thu and Ghanbari's "Scope of validity of PSNR in image/video quality assessment" (2008), showed that PSNR's agreement with human opinion holds only within the same content and codec and breaks down across them. A 2025 study from TU Ilmenau and RWTH Aachen puts numbers on both halves of that finding: 216 4K sequences encoded with AV1, VVC and two neural codecs (DCVC-FM, DCVC-RT), rated by 30 viewers. Within one source clip, PSNR had the highest rank correlation of all tested metrics with viewer scores (SRCC 0.953). Across different clips, its Pearson correlation fell to 0.750, against 0.886 for VMAF (Herb et al., arXiv, November 2025). Same content: PSNR ranks encodes as well as anything. Different content: it is the weakest proxy in the table. The honest framing is the one to carry: every objective metric, PSNR included, is a proxy for human opinion that gets graded against subjective tests, and PSNR is among the weakest proxies we have.

Where PSNR is still the right tool

If PSNR predicts perception poorly, why is it everywhere — and why do we still use it? Because for several specific jobs its weaknesses do not bite and its strengths are decisive.

It is fast and free. PSNR is a handful of arithmetic operations per pixel, with no model to load, no training data, and no license. It runs in real time on anything, which is why every video encoder uses MSE or PSNR inside its rate-distortion optimization — the inner loop that decides, thousands of times per frame, whether spending another bit is worth the error it removes. A perceptual metric is too slow to call in that loop; PSNR is perfect for it.

It is a clean signal for same-codec, same-content comparison. When you change one encoder setting and re-encode the same master, PSNR will faithfully tell you whether pixel error went up or down. That makes it a fine sanity check and a cheap regression gate: if a code change drops PSNR on your fixed test clips, something broke, and you want to know before perceptual scoring even runs.

It is the universal baseline. Because PSNR has been computed the same way for decades, it is the one number every paper, every codec, and every tool can produce, which makes it the common currency for BD-rate and other rate-distortion comparisons. And it is exact for verifying losslessness: an infinite PSNR proves two files are bit-identical, which is the right tool for confirming a transcode changed nothing.

The rule is simple. Reach for PSNR when you are comparing encodes of the same source, when you need speed, or when you need a baseline everyone recognizes. Reach for a perceptual metric when you are predicting how good the video will look to a viewer.

The perceptual cousins: PSNR-HVS, PSNR-HVS-M, and XPSNR

PSNR's weaknesses were obvious enough that researchers built perceptually weighted versions that keep its speed. PSNR-HVS weights the pixel errors by a model of human contrast sensitivity, so errors the eye barely sees count less. PSNR-HVS-M goes further and adds visual masking — the way busy regions hide errors — and in its 2007 evaluation it tracked human judgement far better than both PSNR and SSIM.

The newest and most practical of these is XPSNR, the Extended Perceptually Weighted PSNR from Fraunhofer HHI. Its xpsnr filter shipped in FFmpeg 7.1 (September 2024) and is still documented in the current FFmpeg 9.0 "Lei" branch (9.0.2, September 2026). It is a low-complexity, psychovisually weighted PSNR whose values sit in the same decibel range as ordinary PSNR but follow perceived quality more closely; Fraunhofer HHI's evaluations on VVC-coded UHD video report XPSNR tracking subjective scores more closely than plain PSNR (Helmrich et al., 2020; Menon et al., 2024), which is why it is used for VVC encoder tuning and convex-hull ladder estimation. If you like PSNR's simplicity but want a number closer to the eye, xpsnr in a current FFmpeg build is worth knowing about:

# Extended perceptually weighted PSNR (Fraunhofer HHI, FFmpeg 2024+).
ffmpeg -i distorted.mp4 -i reference.mp4 -lavfi xpsnr -f null -

These variants matter because they show the real lesson of PSNR: the problem was never the decibel scale, it was treating all pixel errors as equal. Weight the errors by how the eye actually works, and a PSNR-style metric becomes useful again.

PSNR vs SSIM vs VMAF: when to reach for which

PSNR is one of three metrics you will meet constantly, and the fastest way to hold them in your head is side by side. The columns that matter are not just the scores but what each metric actually measures and where each one lies.

Metric Scale What it measures Where it lies (blind spot) Best for
PSNR dB (≈20–50, ∞ if identical) Average pixel error vs the original Ignores where errors are; same score for very different-looking distortions Same-codec comparison, RDO, regression gates, lossless checks
SSIM 0–1 (higher better) Structural similarity — luminance, contrast, structure Misses some color and temporal errors; still a spatial model A better-than-PSNR perceptual proxy, per-frame structure
VMAF 0–100 (higher better) Fused, perception-trained quality (model-dependent) Meaningless without the model named; gameable by sharpening Predicting viewer-perceived streaming quality at scale

Table 1. The three full-reference metrics at a glance. All need the original; they differ in how close they get to the eye and what they miss. Pick the row by the job, and always name the conditions.

The progression is the story of the field: PSNR measures error, SSIM measures structure, VMAF is trained directly on human scores. Each is a better perceptual proxy than the last, and each costs more to compute. None replaces a subjective test as ground truth. The full catalogue of where each objective metric misleads is in where objective metrics lie.

Common mistakes with PSNR

Mistake: comparing PSNR across different content, resolutions, or codecs. A 40 dB encode of a cartoon and a 34 dB encode of a grainy film do not tell you the cartoon "looks better" — PSNR is only valid comparing encodes of the same source. Cross-content PSNR rankings are the single most common abuse of the metric.

Mistake: quoting one PSNR number with no context. "PSNR 38" hides whether it is luma or average, mean-pooled or worst-case, and on what content. A single mean PSNR can hide a few terrible seconds inside an otherwise clean clip — which is why pooling matters. Report the component, the pooling, and the content.

Mistake: optimizing for PSNR instead of the viewer. Tuning an encoder to maximize PSNR can push it toward choices that score well on pixel error but look worse — over-smoothing detail, for instance. The metric is a proxy; optimizing the proxy past the point where it tracks perception is how teams ship video that scores high and looks flat.

PSNR FAQ

What does PSNR stand for?

PSNR stands for Peak Signal-to-Noise Ratio. "Peak signal" is the largest possible pixel value, "noise" is the error between the original and the processed frame, and the ratio between them is expressed in decibels.

What is the PSNR formula?

PSNR = 10 · log₁₀(MAX² / MSE), where MAX is the maximum pixel value (255 for 8-bit, 1023 for 10-bit) and MSE is the mean of the squared per-pixel differences between the original and the compressed frame. The equivalent form is 20 · log₁₀(MAX) − 10 · log₁₀(MSE).

Is a higher or lower PSNR better?

Higher PSNR is better: it means less pixel error. Every +3 dB roughly halves the mean squared error, and identical frames have infinite PSNR.

What is a good PSNR value?

For 8-bit video, roughly 35 dB and above is good: 30–40 dB is the normal streaming range, above 40 dB is close to the original, and below 30 dB errors are usually visible. Compare values only between encodes of the same source with the same codec.

What is the range of PSNR in dB?

PSNR runs from 0 dB upwards with no fixed maximum: identical frames give infinity. In practice 8-bit lossy video lands between 30 and 50 dB, and tools such as libvmaf clamp the top end at 60 dB for 8-bit content.

What does PSNR measure in video?

PSNR measures the average pixel error between a decoded video and its original master, usually on the luma (Y) channel and averaged over frames. It does not measure where the errors are or how visible they are to a viewer.

What is PSNR in image processing?

In image processing, PSNR scores how close a compressed, denoised or upscaled image is to its original, in decibels. It uses the same formula as video, 10 · log₁₀(MAX² / MSE), with MAX set to the image's peak value: 255 for 8-bit images, 1.0 for images normalized to 0–1.

Is PSNR measured in dB?

Yes. PSNR is a logarithmic ratio expressed in decibels (dB). Each +10 dB means the mean squared error is ten times smaller, and each +3 dB means it is roughly halved.

What is XPSNR?

XPSNR (Extended Perceptually Weighted PSNR) is a Fraunhofer HHI variant that weights pixel errors by how visible they are, keeping PSNR's speed and dB scale. It is available as the xpsnr filter in FFmpeg 7.1 and later, including FFmpeg 9.0.

PSNR vs SSIM: which should I use?

Use PSNR for fast same-source comparisons, encoder tuning and lossless checks; use SSIM or VMAF when you need to predict how the video looks to people, especially across different content.

↓ Free download: From-scratch PSNR calculatorA dependency-light Python script that computes PSNR between two image or frame files from first principles - Mean Squared Error, then the decibel conversion - printing every intermediate value, per-channel MSE, MAX, MSE and PSNR in dB, so you can see exactly where the number comes from.

Where Fora Soft fits in

Fora Soft has built video software since 2005 — streaming, WebRTC conferencing, OTT, e-learning, telemedicine, and surveillance — and PSNR is the first metric we compute on almost every encoding task, then the first one we refuse to trust on its own. We use it where it is strong: as a fast regression check that an encoder change did not increase pixel error, and as the baseline currency for rate-distortion comparison. We stop trusting it the moment the question becomes "how good does this look to the viewer," where we move to VMAF with its model named and pooling stated, anchored on real subjective testing. Our benchmark methodology documents which metric produced every number, and why PSNR was or was not the right one for that comparison. When an encoder change has to be signed off, our video processing and encoding developers build the PSNR and VMAF regression gates into the pipeline, and our streaming software team ties those numbers to the bitrate ladder viewers actually receive.

Video Streaming: From ABR and CDNs to Players, WebRTC, DRM, and the Economics of Streaming - book coverVideo Encoding: A Complete Guide to Video Compression - book coverAudio for Video: From Jitter Buffers and Lip Sync to Atmos, Quality Metrics, and Neural Codecs - book cover

The handbook

Fora Soft Video Engineering Handbook

We wrote a seven-volume handbook that takes the whole video stack apart across 9,000+ pages - encoding, delivery, audio and AI - so that an engineer who works through it can design and build the systems these decibels grade. Volume 1 runs from the quantizer that creates the pixel error to the metrics that score it, PSNR first and then the perceptual ones built because pixel error was not enough; volume 3 is where a quality target stops being a number and becomes an ABR ladder, a player and a CDN bill; volume 5 does the same job for sound, whose quality metrics have their own decibel history. Written by Nikolay Sapunov, CEO at Fora Soft.

Browse the handbook on Amazon →7 volumes · Kindle & paperback

Is the PSNR number in your pipeline answering the question you are actually asking?

Send us your test clips and the numbers your CI produces, and we will tell you which comparisons are sound, which ones are cross-content tea leaves, and which metric belongs in each gate. 250+ video products shipped since 2005.

Book a 30-min call →WhatsApp →Email us →

See our case studies

References

  1. Recommendation ITU-T J.340 (06/2010), Reference algorithm for computing peak signal to noise ratio of a processed video sequence with compensation for constant spatial shifts, constant temporal shift, and constant luminance gain and offset. International Telecommunication Union. Tier 1. The standardized alignment-compensated PSNR computation for video. https://www.itu.int/rec/T-REC-J.340
  2. Recommendation ITU-T P.1401 (01/2020), Methods, metrics and procedures for statistical evaluation, qualification and comparison of objective quality prediction models. International Telecommunication Union. Tier 1. Defines PCC, SROCC, and RMSE — how any objective metric, PSNR included, is graded against subjective scores. https://www.itu.int/rec/T-REC-P.1401
  3. Recommendation ITU-R BT.500-15 (2023), Methodologies for the subjective assessment of the quality of television images. International Telecommunication Union. Tier 1. The subjective ground truth against which objective metrics like PSNR are validated. https://www.itu.int/rec/R-REC-BT.500
  4. Q. Huynh-Thu and M. Ghanbari, "Scope of validity of PSNR in image/video quality assessment," Electronics Letters, vol. 44, no. 13, pp. 800–801, 2008. Tier 5 (peer-reviewed). The defining study showing PSNR is valid only within the same content and codec. doi:10.1049/el:20080522 (https://doi.org/10.1049/el:20080522)
  5. Q. Huynh-Thu and M. Ghanbari, "The accuracy of PSNR in predicting video quality for different video scenes and frame rates," Telecommunication Systems, vol. 49, no. 1, pp. 35–48, 2012. Tier 5 (peer-reviewed). Quantifies how PSNR's predictive accuracy varies with content and frame rate. https://doi.org/10.1007/s11235-010-9351-x
  6. K. Egiazarian, J. Astola, N. Ponomarenko, V. Lukin, F. Battisti, M. Carli, "New full-reference quality metrics based on HVS," Proc. 2nd Int. Workshop on Video Processing and Quality Metrics (VPQM), 2006. Tier 5. Introduces PSNR-HVS, weighting pixel error by human contrast sensitivity. http://www.ponomarenko.info/psnrhvsm.htm
  7. N. Ponomarenko, F. Silvestri, K. Egiazarian, M. Carli, J. Astola, V. Lukin, "On between-coefficient contrast masking of DCT basis functions," Proc. 3rd Int. Workshop on Video Processing and Quality Metrics (VPQM), 2007. Tier 5. Defines PSNR-HVS-M, adding visual masking; outperformed PSNR and SSIM in evaluation. http://www.ponomarenko.info/vpqm07_p.pdf
  8. C. R. Helmrich, M. Siekmann, S. Becker, S. Bosse, D. Marpe, T. Wiegand, "XPSNR: A Low-Complexity Extension of the Perceptually Weighted Peak Signal-to-Noise Ratio for High-Resolution Video Quality Assessment," Proc. IEEE ICASSP, 2020; and the Fraunhofer HHI XPSNR FFmpeg plug-in. Tier 5 / Tier 3. The perceptually weighted PSNR now integrated into FFmpeg (2024). https://github.com/fraunhoferhhi/xpsnr
  9. FFmpeg, psnr and xpsnr filter documentation, accessed 2026-11-10. Tier 3 (first-party tooling). The psnr filter (two inputs, per-plane and average output, stats_file) and the xpsnr filter added in FFmpeg 7.1 (2024) and present in 9.0 (2026). https://ffmpeg.org/ffmpeg-filters.html#psnr
  10. Netflix, VMAF documentation and repository, accessed 2026-10-10. Tier 3 (first-party / metric-author). Netflix's rationale for building a perception-trained metric rather than relying on PSNR. https://github.com/Netflix/vmaf
  11. Z. Wang, A. C. Bovik, H. R. Sheikh, E. P. Simoncelli, "Image Quality Assessment: From Error Visibility to Structural Similarity," IEEE Transactions on Image Processing, vol. 13, no. 4, pp. 600–612, 2004. Tier 1 (metric-author). The SSIM paper, whose opening argument is precisely PSNR's failure to model perception. https://ece.uwaterloo.ca/~z70wang/publications/ssim.html
  12. B. Herb, R. R. Ramachandra Rao, S. Göring, A. Raake, "Evaluating Video Quality Metrics for Neural and Traditional Codecs using 4K/UHD-1 Videos," arXiv:2511.00969, November 2025. Tier 5 (preprint, TU Ilmenau / RWTH Aachen). 216 sequences, 30 viewers; PSNR within-sequence SRCC 0.953, overall PCC 0.750; VMAF overall PCC 0.886. https://arxiv.org/abs/2511.00969
  13. V. V. Menon, C. R. Helmrich, A. Wieckowski, B. Bross, D. Marpe, "Convex-hull Estimation using XPSNR for Versatile Video Coding," arXiv:2406.13712, June 2024. Tier 5 (Fraunhofer HHI). XPSNR's correlation with subjective scores on VVC-coded UHD content. https://arxiv.org/abs/2406.13712
  14. Netflix libvmaf, float_psnr.c (PSNR feature extractor), accessed 2026-11-10. Tier 3 (first-party tooling). PSNR clamp values per bit depth: 60 / 72 / 84 / 108 dB. https://github.com/Netflix/vmaf/blob/master/libvmaf/src/feature/float_psnr.c
  15. FFmpeg download page, "FFmpeg 9.0.2 'Lei'," released 2026-09-18 (9.0 branch since August 2026), accessed 2026-11-10. Tier 3 (first-party). Current stable FFmpeg release; the psnr and xpsnr filters are in the current filter documentation. https://ffmpeg.org/download.html
  16. scikit-image 0.26.0, skimage.metrics.peak_signal_noise_ratio API reference, accessed 2026-11-10. Tier 3 (first-party tooling). Signature and data_range default. https://scikit-image.org/docs/stable/api/skimage.metrics.html
  17. OpenCV source, core.hpp, declaration of cv::PSNR (4.x branch), accessed 2026-11-10. Tier 3 (first-party tooling). R, the maximum pixel value, defaults to 255. https://github.com/opencv/opencv/blob/4.x/modules/core/include/opencv2/core.hpp
  18. MathWorks, psnr (Image Processing Toolbox) reference page, accessed 2026-11-10. Tier 3 (first-party tooling). Default peakval: 255 for uint8, 1 for double and single. mathworks.com/help/images/ref/psnr.html
  19. TorchMetrics 1.9.0, Peak Signal-to-Noise Ratio (PSNR), accessed 2026-11-10. Tier 3 (first-party tooling). PeakSignalNoiseRatio and data_range semantics. https://lightning.ai/docs/torchmetrics/stable/image/peak_signal_noise_ratio
  20. "Peak signal-to-noise ratio," Wikipedia, accessed 2026-10-10. Tier 6 (educational, orientation only). Source for the typical dB ranges by bit depth (its "maximum PSNR" figures are the MSE = 1 values, not true limits); primary claims are cited to the standards and papers above. https://en.wikipedia.org/wiki/Peak_signal-to-noise_ratio