Sharpen Netpbm Images Safely with pammasksharpen
You will create a blurred copy of a Netpbm image, use it as an unsharp mask, and write a sharpened image to a new file. Allow about 15 minutes for a first run. You need the Netpbm package, a readable input image, and enough free space for the intermediate files. The examples use Netpbm 11.5.2, installed here as 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.
Checkpoint
This workflow only reads the source image and creates new output files. It does not need sudo and does not alter a service or system configuration.
1. Check the installed command
Confirm that the executable is available and record the version that will process your image:
$ command -v pammasksharpen
/usr/bin/pammasksharpen
$ pammasksharpen --version
pammasksharpen: Using libnetpbm from Netpbm Version: Netpbm 11.5.2
pammasksharpen: Built from source dated 2024-03-31 09:09:47
The installed manual page is dated June 2006. Its rules still describe the local command: the mask comes first, the original input comes second, and the sharpened image is written to standard output. Keep that argument order visible in scripts because swapping the two files can produce a plausible-looking but unintended result.
2. Build a Gaussian mask
An unsharp mask is usually a blurred version of the original. The Netpbm manual's reproducible pipeline starts with pamgauss, which emits a Gaussian kernel, then converts that kernel to PGM for pnmconvol:
$ pamgauss 5 5 -sigma=.7 -tupletype=GRAYSCALE | pamtopnm > gauss.pgm
$ pnmfile gauss.pgm
gauss.pgm: PGM raw, 5 by 5 maxval 255
The kernel is 5 by 5, so it represents a radius of 2 pixels: the radius is half the kernel width after subtracting its centre, or (5 - 1) / 2. A larger odd square kernel affects detail over a wider area. Start small, especially for faces or fine texture. A large radius can erase detail rather than improve it.
Do not confuse the Gaussian kernel with the final mask. It is the recipe for blurring. The next step applies it to the actual image.
3. Blur the source image
Run pnmconvol with the kernel file and your source image. The -nooffset option is required for the kernel made by pamgauss:
$ pnmconvol -nooffset gauss.pgm /path/to/input.ppm > blurred.ppm
$ pnmfile /path/to/input.ppm blurred.ppm
/path/to/input.ppm: PPM raw, 1600 by 1200 maxval 255
blurred.ppm: PPM raw, 1600 by 1200 maxval 255
The output format remains a Netpbm format, but the exact file spelling depends on the input and installed tools. Check the dimensions and maxval, not just the filename. The convolution tool copies edge pixels directly when the kernel would extend beyond the image. An image that is smaller than the kernel can fail instead of producing a useful mask.
Checkpoint
Stop here and inspect blurred.ppm if the result looks unexpectedly dark, clipped or unchanged. Do not continue until the blur is a valid image with the same dimensions as the source.
4. Sharpen without replacing the source
Pass the blurred image first and the original image second. Redirect standard output to a fresh destination:
$ pammasksharpen -sharpness=1.2 -threshold=.02 blurred.ppm /path/to/input.ppm > sharpened.ppm
$ pnmfile sharpened.ppm
sharpened.ppm: PPM raw, 1600 by 1200 maxval 255
-sharpness is the amount applied to the difference between the original sample and the corresponding mask sample. Its default is 1.0; it must be a non-negative real number. Zero disables sharpening. The example uses 1.2 as a deliberate starting point, not a universal best value.
-threshold ignores small differences, which can reduce speckling in smooth areas. It is a fraction of the image maxval and must be between 0 and 1.0. Its default is 0, so the command considers every difference unless you set a threshold. Increase it cautiously: too much can remove genuine low-contrast detail.
The mask and input must have identical dimensions and the same maxval. If the command rejects them, check both files with pnmfile and rebuild the mask from the same source. The program clips samples that would fall outside the representable range, so a strong setting can create flat bright or dark areas.
5. Protect an existing output
Shell redirection with > truncates its destination before the command runs. If sharpened.ppm already matters, write to a temporary name and replace it only after verification:
$ pammasksharpen -sharpness=1.2 -threshold=.02 blurred.ppm /path/to/input.ppm > sharpened.ppm.new
$ pnmfile sharpened.ppm.new
sharpened.ppm.new: PPM raw, 1600 by 1200 maxval 255
$ mv sharpened.ppm.new sharpened.ppm
The mv command changes the destination name, so run it only after checking the image. If the command fails, leave the old file in place and investigate the error. Remove an unwanted temporary file with rm -- sharpened.ppm.new only when you are certain it is disposable. That removal is irreversible.
6. Diagnose the usual failures
- An error about a missing magic number usually means an empty or non-Netpbm input. Check the path and run
pnmfileon both the mask and source. - A dimension or maxval mismatch means the mask was not made from the same image, or the source was converted between steps. Recreate
blurred.ppmfrom the current source. - Unexpected speckles suggest a threshold that is too low. Try a modest value such as
.01or.02, then compare the result at the same display scale. - Lost fine detail or halos suggest that the kernel radius or sharpness is too high. Use a smaller odd kernel, reduce
-sharpness, or both. - Do not run the pipeline as root to solve a file-permission problem. Fix ownership or permissions in the working directory through your normal administration process, and keep the original image until the result has been inspected.
Done means
pammasksharpen --versionidentifies the expected Netpbm installation.- The Gaussian kernel and blurred mask are valid Netpbm images.
- The mask and source have matching dimensions and maxval.
- The sharpened output has been checked with
pnmfileand, ideally, an image viewer. - The source image remains untouched, and an existing output was not overwritten before verification.