Compare Netpbm Images with pnmpsnr and PSNR Thresholds
Turning down a JPEG-style quality setting and eyeballing the result only gets you so far, so pnmpsnr gives compression tuning an actual number. You will finish with a repeatable way to compare two PBM, PGM or PPM images, read their peak signal-to-noise ratio (PSNR), and turn a quality limit into a simple match or nomatch result. The examples use pnmpsnr from Netpbm 11.5.2, installed here as Debian package version 2:11.05.02-1.1build1.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about fifteen minutes. You need a shell, the netpbm package, and two readable images with the same dimensions and compatible formats. pnmpsnr only reads its inputs and writes its report to standard output, so these checks do not alter either image and do not need sudo.
1. Check the installed command
Confirm which executable is being used and record the version before putting its output into a script:
$ command -v pnmpsnr
/usr/bin/pnmpsnr
$ pnmpsnr -version
pnmpsnr: Using libnetpbm from Netpbm Version: Netpbm 11.5.2
The exact build information includes a source date and Debian build details, which can vary. The important checkpoint is the Netpbm version and the fact that the command resolves to the installation you intended. The manual page supplied with this installation documents the options used below.
2. Read a human-friendly comparison
Pass the reference image first and the image being checked second. The order does not change the PSNR calculation, but a consistent order makes logs easier to understand:
$ pnmpsnr /path/to/reference.pgm /path/to/encoded.pgm
pnmpsnr: PSNR between '/path/to/reference.pgm' and '/path/to/encoded.pgm':
pnmpsnr: lumina 9.07 dB
The file names in the report are yours, and the numeric value will depend on the images. A higher PSNR means a smaller mean square difference. For a monotone PBM or PGM image, the report contains one luminance result. With colour input, the default report uses luminance and chrominance components, shown as Y, Cb and Cr.
Do not treat a particular dB value as a universal pass mark. A useful threshold depends on the image type and the tolerance of the work you are doing. Establish that threshold from representative pairs, then record it in the command or script.
3. Check dimensions and format when a result looks wrong
Before investigating the number, check that both files describe the images you think they do:
$ pnmfile /path/to/reference.pgm /path/to/encoded.pgm
/path/to/reference.pgm: PGM raw, 1920 by 1080 maxval 255
/path/to/encoded.pgm: PGM raw, 1920 by 1080 maxval 255
Output wording varies with the Netpbm build, but the useful checks are the image type, width, height and maximum value. pnmpsnr compares corresponding pixel positions. A wrong crop, resize or channel layout makes the result describe that mismatch, not merely the compression error you intended to measure. If a file cannot be opened, fix its path or read permission first. Do not run the comparison as root just to hide a permissions problem.
Keep the original input files while reviewing results. There is no rollback operation because pnmpsnr does not change them. If you redirect output to a report file, choose a new destination or back up an existing report before using >, which truncates its destination before the command starts.
4. Produce a value that a script can parse
Use -machine when another program needs numbers rather than diagnostic labels:
$ pnmpsnr -machine /path/to/reference.pgm /path/to/encoded.pgm
9.07
There is one space-separated number for a monotone image. Colour output has three numbers. Without -rgb, they are Y, Cb and Cr; with -rgb, they are red, green and blue:
$ pnmpsnr -machine -rgb /path/to/reference.ppm /path/to/encoded.ppm
inf 9.07 inf
inf means that the corresponding component did not differ. That is valid output, but some consumers only accept finite decimals. Add -max to cap the printed value:
$ pnmpsnr -machine -max=50 /path/to/reference.pgm /path/to/reference.pgm
50.00
-max only has meaning with -machine. It changes the reported value, so keep the cap documented beside the parser and do not compare capped values as though they were exact PSNRs.
5. Turn a quality limit into match or nomatch
Use -target when the caller only needs a decision. pnmpsnr prints match when every computed component exceeds the target, and nomatch otherwise:
$ pnmpsnr -target=20 /path/to/reference.pgm /path/to/encoded.pgm
nomatch
$ printf 'exit status: %s\n' "$?"
exit status: 1
The threshold is a floating-point PSNR value in decibels. In a script, capture the status immediately. A successful match returns status 0; a failed comparison returns a non-zero status. A missing file or another operational error is also non-zero, so keep the command's diagnostic output and distinguish input failures from a genuine nomatch.
For colour images, use -target1, -target2 and -target3 when each component needs its own limit. The component order follows the selected colour space:
$ pnmpsnr -rgb -target1=30 -target2=25 -target3=25 \
/path/to/reference.ppm /path/to/encoded.ppm
match
An omitted per-component target is ignored when deciding the result. These per-component options are intended for colour input; on PBM or PGM they select comparison mode but do not provide a usable single-image target. Use plain -target for a monotone image.
6. Avoid option and automation traps
The installed manual accepts the option forms shown here, including an equals sign or whitespace before a value. It also permits minimum unique abbreviations and double hyphens, but full names are safer in scripts because future options can make an abbreviation ambiguous. Prefer -target=20 and -machine over shortened spellings.
-machine has no effect when any target option is present because target mode prints only match or nomatch. Choose one output contract. Likewise, -rgb has no effect on a monotone image. It changes the interpretation of colour results, not the pixels in the input files.
Quote paths that contain spaces or shell characters:
$ pnmpsnr -machine --max=50 "$reference" "$candidate"
If a variable can be empty or supplied by another user, validate it before invoking the command. Do not build an option string with untrusted text and pass it through eval. The comparison itself is read-only, but unsafe shell construction can still run an unintended command.
Done means
- You confirmed the installed pnmpsnr executable and Netpbm version.
- You checked that the two inputs are readable and have the expected dimensions and formats.
- You can read the human report and understand that higher PSNR means closer images.
- You can parse one or three machine values, including the possible
infoutput. - You chose a documented threshold and can distinguish
match,nomatchand input errors. - You have not changed either image or any system configuration.