Remove Speckle Noise from PGM Images with pgmmedian
You will apply a median filter to a PGM image and write a new, verified PGM file. The filter replaces a pixel with the median of values in a rectangular neighbourhood, which can remove isolated bright or dark speckles while retaining more edge detail than a simple blur. Allow about ten minutes for a first run. You need the Netpbm package, a readable PGM file and enough disk space for another copy of the image.
The route
Jump straight to the step you need, or tick off Done means at the end.
This guide describes Netpbm 11.5.2, installed here as Debian package netpbm 2:11.05.02-1.1build1. The command's manual page is dated 20 January 2022. Check your local version if you are scripting across distributions.
1. Check the command and preserve the source
Start with an unprivileged shell. No elevated privileges are needed for an image in your own working directory, and pgmmedian does not need to modify the input.
$ command -v pgmmedian
/usr/bin/pgmmedian
$ pgmmedian --version
pgmmedian: Using libnetpbm from Netpbm Version: Netpbm 11.5.2
...
The version command also prints build details and the instruction to use the manual page. If command -v finds nothing, install Netpbm through your normal package-management process. Do not use sudo just to run the filter.
Checkpoint
Identify the input with a path such as /path/to/input.pgm. Keep that file untouched until the filtered image has been inspected.
2. Run the default 3 by 3 filter
With no mask dimensions specified, pgmmedian uses a width of 3 and a height of 3. Redirect its standard output to a different file:
$ pgmmedian /path/to/input.pgm > /path/to/filtered.pgm
$ printf 'exit status: %s\n' "$?"
exit status: 0
The output is a PGM image on standard output, not a status report. In Netpbm 11.5.2, a successful result is written as a raw, binary PGM with the P5 magic number. It can look empty or contain unreadable characters if you print it in a terminal. Use an image-aware inspection command instead:
$ file /path/to/filtered.pgm
/path/to/filtered.pgm: Netpbm image data, size = 5 x 5, rawbits, greymap
$ head -c 2 /path/to/filtered.pgm
P5
The exact file wording varies. Confirm that the output exists, is non-empty and has the expected dimensions. The source file remains unchanged.
3. Choose the mask size deliberately
A larger mask considers more neighbouring pixels and can remove broader noise, but it also changes more of the image. Set the width and height explicitly when the default is not appropriate:
$ pgmmedian -width 5 -height 5 /path/to/input.pgm > /path/to/filtered-5x5.pgm
$ file /path/to/filtered-5x5.pgm
/path/to/filtered-5x5.pgm: Netpbm image data, size = 5 x 5, rawbits, greymap
The dimensions describe the median mask, not a resize operation. Each value must not exceed the corresponding input image dimension. The manual does not describe an automatic choice based on the file name, so do not assume that a small image has a small optimal mask.
At the image edges, where the complete mask would extend outside the image, the program copies the input pixels. This means the outer part of a result can remain unchanged even when the centre is filtered. Inspect the whole image rather than judging the first or last rows alone.
4. Select the median algorithm when needed
By default, the program chooses between histogram sorting and a select-kth-value method using the image maxval, mask area and a cutoff. The default cutoff is 250. For a reproducible processing pipeline, choose the method directly:
$ pgmmedian -width 3 -height 3 -type histogram_sort \
/path/to/input.pgm > /path/to/filtered-histogram.pgm
$ pgmmedian -width 3 -height 3 -type select \
/path/to/input.pgm > /path/to/filtered-select.pgm
The accepted values are exactly histogram_sort and select. The -cutoff option has no effect when -type is supplied. If you leave the method unset, the default selection is normally the useful choice; specify -cutoff only when you have measured a reason to change the trade-off for your images.
5. Avoid losing an existing result
Shell redirection with > truncates its destination before pgmmedian starts. Write to a temporary name, verify it, then replace the old result only if that is what you intend:
$ pgmmedian /path/to/input.pgm > /path/to/filtered.pgm.new
$ test -s /path/to/filtered.pgm.new && file /path/to/filtered.pgm.new
/path/to/filtered.pgm.new: Netpbm image data, size = 5 x 5, rawbits, greymap
$ mv /path/to/filtered.pgm.new /path/to/filtered.pgm
Warning
The final mv replaces an existing destination. Omit it if the old file is still your recovery copy. If filtering fails, inspect the command's diagnostic, keep the source, and remove the incomplete .new file only after checking its path. There is no need to alter the original PGM.
6. Diagnose the common failures
An input error usually means the path, permissions or PGM data is wrong. Check read access without changing anything:
$ ls -l /path/to/input.pgm
$ test -r /path/to/input.pgm && echo readable
readable
If the command writes binary-looking output to your terminal, that is a redirection mistake, not necessarily a filter failure. Interrupt the display if needed and rerun with > pointing to a new file. If the result has unexpected dimensions, check the source with file and review any explicit mask values. If the image looks unchanged around its boundary, remember the documented edge-copy behaviour.
Do not treat exit status 0 as proof that the image looks right. Verify the dimensions and magic number, then inspect the result with an image viewer or a later Netpbm conversion. Keep the original until that visual check is complete.
Done means
pgmmedianis installed and its local version is known.- The source PGM remains untouched.
- The filtered output is a non-empty PGM with the expected dimensions.
- The mask size is suitable for the image, rather than being mistaken for a resize setting.
- Any algorithm choice is explicit and uses an accepted
-typevalue. - An existing output was not overwritten until the replacement had been checked.