Dilate, Erode and Filter PGM Images with pgmmorphconv
pgmmorphconv runs classic morphology, dilation, erosion, opening, closing or a gradient, over a PGM image using a small template you define yourself. Reading the whole page and testing each operation takes about fifteen minutes, and everything here writes to standard output, so your original image is never at risk.
The route
Jump straight to the step you need, or tick off Done means at the end.
You need a shell, the pgmmorphconv command, a PGM image to process, and a PBM template: a small black-and-white image that says which neighbouring pixels take part in the calculation. These examples read and transform; nothing overwrites an input unless you redirect output over it yourself.
1. Check the installed command
Confirm the executable and package version before an option you rely on turns out to be missing:
$ command -v pgmmorphconv
/usr/bin/pgmmorphconv
$ dpkg-query -W -f='${Package} ${Version}\n' netpbm
netpbm 2:11.05.02-1.1build1
$ pgmmorphconv --version
pgmmorphconv: Using libnetpbm from Netpbm Version: Netpbm 11.5.2
The command takes a template file, then an optional PGM input; leave the input out and it reads from standard input instead. It writes the transformed image to standard output. No elevated privileges are needed anywhere in this guide.
Checkpoint
If command -v finds nothing, install the package through your normal process. Do not copy a binary in from another host and assume its template handling matches.
2. Build a small template
- Odd dimensions. A template needs an odd number of rows and an odd number of columns, so the centre pixel lines up exactly with the pixel being calculated.
- At least one white pixel. A template with none selects nothing at all.
- Plain PBM text.
1is white,0is black.
This 3 by 3 template picks the centre pixel plus its four direct neighbours:
$ cat > cross.pbm <<'EOF'
P1
3 3
0 1 0
1 1 1
0 1 0
EOF
That command does change state, it creates a file, but it is trivial to undo:
$ rm -- cross.pbm
Never use an even-sized template (no single centre) or an all-black one (no pixels selected). Keep the template next to your script and glance at it before running it over a large image.
3. Run the default dilation
Start with a named output file rather than touching your input:
$ pgmmorphconv cross.pbm input.pgm > dilated.pgm
$ printf 'exit status: %s\n' "$?"
exit status: 0
$ file dilated.pgm
dilated.pgm: Netpbm image data, size 5 x 5, rawbits, grayscale
With no operation flag, pgmmorphconv dilates: for each output pixel it looks at the input values under the template's white cells and keeps the brightest. Bright regions grow, dark regions shrink, and the output keeps the input's exact dimensions.
That output is binary PGM by default. To read it in a terminal, convert it without touching the source:
$ pgmmorphconv cross.pbm input.pgm | pnmtoplainpnm | sed -n '1,8p'
P2
5 5
9
0 5 5 5 0
Your own dimensions and values will differ. What actually matters is a clean exit status, a valid PGM header and the dimensions you expected.
4. Choose erosion or a compound operation
Pass exactly one operation flag before the template file:
-dilatekeeps the brightest selected pixel. This is also the default.-erodekeeps the darkest, so bright regions contract.-openerodes then dilates, which can strip small bright specks while keeping the overall shape.-closedilates then erodes, which can fill small dark gaps inside bright regions.-gradientgives you the difference between the eroded and dilated images.
$ pgmmorphconv -erode cross.pbm input.pgm > eroded.pgm
$ pgmmorphconv -open cross.pbm input.pgm > opened.pgm
$ pgmmorphconv -close cross.pbm input.pgm > closed.pgm
$ pgmmorphconv -gradient cross.pbm input.pgm > gradient.pgm
$ for image in eroded.pgm opened.pgm closed.pgm gradient.pgm; do
> pnmfile "$image"
> done
eroded.pgm: 5 by 5 grayscale, maxval 9
opened.pgm: 5 by 5 grayscale, maxval 9
closed.pgm: 5 by 5 grayscale, maxval 9
gradient.pgm: 5 by 5 grayscale, maxval 9
These are image operations, not a guaranteed edge detector. What you actually see depends on the template, the image's own intensities and how borders are handled, so test on a small known image before trusting a template for automated recognition work.
5. Read from standard input safely
Drop the PGM file argument and pgmmorphconv reads the input stream instead, handy when another Netpbm command is generating the image:
$ pnmscale -width 800 source.pgm | pgmmorphconv --dilate cross.pbm > scaled-dilated.pgm
$ pnmfile scaled-dilated.pgm
scaled-dilated.pgm: 800 by 600 grayscale, maxval 255
The long option form works in place of the single hyphen, and unique abbreviations are accepted too. Prefer the full option name in anything you save: an abbreviation can turn ambiguous the day a future version adds a similarly named option.
Warning
Never redirect output to the same path as the input. The shell opens the destination, and therefore truncates it, before pgmmorphconv has read a single byte of the source. A truncated source with no separate copy cannot be recovered; regenerate it from a backup if you have one.
6. Work through the common failures
If the command complains that the image is smaller than the convolution matrix, check both files' dimensions:
$ pnmfile input.pgm cross.pbm
input.pgm: 5 by 5 grayscale, maxval 9
cross.pbm: 3 by 3 bilevel, maxval 1
The input has to be at least as large as the template, so a 3 by 3 template cannot process a 2 by 2 image. If the template itself is rejected, check it is PBM, has odd dimensions and contains white pixels. When a pipeline fails partway, save the intermediate output and run pnmfile on it: an error message masquerading as image data is a common source of confusing downstream failures.
Checkpoint
A finished transformation shows a zero exit status, a readable PGM at the destination, an untouched input and dimensions matching the source.
Done means
- Installation confirmed. The Netpbm version and executable were checked before use.
- Template valid. The PBM template has odd dimensions, a clear centre and at least one white pixel.
- Operation deliberate. The chosen operation is explicit, or the dilation default was the intended choice.
- Result checked. The output went to a separate file and was verified with
pnmfile. - Original preserved. The source PGM is still available for comparison or recovery.