Normalise Netpbm Contrast Safely with pnmnorm
You will turn a low-contrast PBM, PGM or PPM image into a new image whose useful brightness range is spread towards black and white. The examples use the installed Netpbm 11.5.2 command, and keep the source file untouched. Allow about fifteen minutes for one image, including a basic verification.
The route
Jump straight to the step you need, or tick off Done means at the end.
You need the netpbm package, a readable input image, and enough free space for a second image. The examples run as an ordinary user. Do not use sudo unless filesystem permissions genuinely require it.
1. Check the installed command
Confirm which executable your shell will run and record the package version. These are read-only checks:
$ command -v pnmnorm
/usr/bin/pnmnorm
$ dpkg-query -W -f='${Package} ${Version}\n' netpbm
netpbm 2:11.05.02-1.1build1
$ pnmnorm -version 2>&1 | head -3
pnmnorm: Using libnetpbm from Netpbm Version: Netpbm 11.5.2
pnmnorm: Built from source dated 2024-03-31 09:09:47
pnmnorm: Built by Debian
Option spelling and edge cases can differ between old Netpbm releases. This guide describes the installed version. The manual says options may be abbreviated to a shortest unique prefix, but full names are clearer in scripts.
2. Make a new normalised image
pnmnorm reads from the named file, or from standard input when no file is supplied, and writes the same kind of PNM image to standard output. Redirect that output to a new path. The redirection is the part that creates a file:
$ pnmnorm /path/to/input.pgm > /path/to/output.pgm
pnmnorm: remapping 0..255 to 0..255
The diagnostic reports the brightness range selected for the remapping. It normally appears on standard error, while the image bytes go to standard output. Do not redirect both streams into the image file.
Checkpoint: test the result without opening a binary file in an editor:
$ file /path/to/output.pgm
/path/to/output.pgm: Netpbm image data, size 1600 x 1200, rawbits, grayscale
$ test -s /path/to/output.pgm && echo 'output is non-empty'
output is non-empty
Your file wording will vary. Check that the output exists, is non-empty, and has the expected dimensions and image type. A successful command does not prove that the visual result suits your purpose, so inspect it with an image viewer or a later converter as well.
3. Understand the default stretch points
By default, pnmnorm maps the darkest 2 percent of pixels to black and the brightest 1 percent to white. It then spreads the values between those points. This is useful for ordinary contrast improvement, but it deliberately discards detail at both ends of the selected range. It is not a neutral format conversion.
Use explicit percentages when you want the choice recorded in a script:
$ pnmnorm -bpercent=1.5 -wpercent=0.5 /path/to/input.pgm > /path/to/output-percent.pgm
pnmnorm: remapping 12..248 to 0..255
The exact diagnostic depends on the image histogram. Percentages are floating-point decimal values, and whole pixels mean the requested percentage cannot always be exact. The program arranges that at least the requested proportion is remapped.
4. Use fixed brightness values for repeatable control
When you have inspected a histogram, use -bvalue and -wvalue to choose exact input brightness values. The values are in the image's native range, so a typical 8-bit image uses 0 through 255:
$ pnmnorm -bvalue=20 -wvalue=235 /path/to/input.pgm > /path/to/output-values.pgm
pnmnorm: remapping 20..235 to 0..255
ppmhist can help you choose values for a PPM image, while pgmhist is the corresponding choice for a PGM image. If you supply both a value and a percentage for the same end, the installed manual says pnmnorm uses the setting that produces the least change. If you need maximum change, make the two decisions in separate runs rather than guessing.
There is also a single-pixel mode:
$ pnmnorm -bsingle -wsingle /path/to/input.pgm > /path/to/output-extremes.pgm
pnmnorm: remapping 10..240 to 0..255
This maps the single least and greatest brightness values. It can be too aggressive when an isolated sensor speck or highlight is present, so prefer percentages or fixed values when outliers matter.
5. Protect colour and limit excessive expansion
For a PPM image, the default operation normalises each RGB component independently. That can change the hue. Add -keephues when preserving each pixel's hue is more important than reaching the exact target brightness:
$ pnmnorm -keephues /path/to/input.ppm > /path/to/output-keephues.ppm
Hue preservation can clip a saturated component, so the brightest or dimmest pixels may still be approximate. The option has no meaning for grayscale images.
If a narrow input range would be stretched too far, cap the expansion with -maxexpand:
$ pnmnorm -maxexpand=50 /path/to/input.pgm > /path/to/output-capped.pgm
pnmnorm: limiting expansion of 150% to 50%
pnmnorm: remapping 25..75 to 0..100
The exact values and whether the limiting message appears depend on the image. This cap is a useful guard for batch work where you cannot inspect every histogram first.
6. Avoid overwriting a useful result
Shell redirection with > truncates its destination before pnmnorm starts. Write to a temporary name in the same directory, verify it, then replace the old output only if you deliberately want that change:
$ pnmnorm /path/to/input.pgm > /path/to/output.pgm.new
$ test -s /path/to/output.pgm.new && file /path/to/output.pgm.new
$ mv /path/to/output.pgm.new /path/to/output.pgm
The final mv changes the destination and can remove its previous contents. Treat it as the irreversible step: keep a backup if the old image matters. If pnmnorm fails, leave the original output alone and remove the incomplete .new file after checking its path. The source image itself is never modified by pnmnorm.
7. Diagnose common mistakes
- An error opening the input usually means the path or read permission is wrong. Check with
ls -l /path/to/input.pgmandtest -r /path/to/input.pgm; do not immediately run the conversion as root. - If the result is unexpectedly flat or clipped, reduce the percentage, choose less extreme
-bvalueand-wvaluesettings, or add-maxexpand. - If a colour image changes hue, rerun from the original with
-keephues. Do not try to repair a derived image repeatedly, because each run applies another remapping. - If a PNM viewer rejects the output, check the command's exit status and the first bytes with
file. Keep standard error separate from standard output.
Done means
- The installed Netpbm version and input format are known.
- A new, non-empty PNM file has the expected dimensions and type.
- The chosen stretch points and any expansion cap are recorded in the command.
- PPM work uses
-keephueswhen retaining hue matters. - The original input remains available, and no destination was overwritten before verification.