This program is part of Netpbm(1).
pnmconvol reads a Netpbm image as input, convolves it with a specified convolution matrix, and writes a
Netpbm image as output.
A command use for convolution is blurring. See examples in the pamgauss(1) manual.
Convolution means replacing each pixel with a weighted average of the nearby pixels. The weights and the
area to average are determined by the convolution matrix (sometimes called a convolution kernel), which
you supply in one of several ways. See Convolution Matrix .
At the edges of the convolved image, where the convolution matrix would extend over the edge of the
image, pnmconvol just copies the input pixels directly to the output. It's often better to deal with the
pixels near an edge by assuming some blank or background color beyond the edge. To do that, use pnmpad
to add a margin all around whose size is half that of your convolution matrix size, not counting its
center, in the same dimension. (E.g. if your convolution matrix is 5 wide by 3 high, use pnmpad -left=2
-right=2 -top=1 -bottom=1). Feed that enlarged image to pnmconvol, then use pamcut to chop the edges off
the convolved output, getting back to your original image dimensions. (E.g. pamcut -left=2 -right=-2
-top=1 -bottom=-1).
The convolution computation can result in a value which is outside the range representable in the output.
When that happens, pnmconvol just clips the output, which means brightness is not conserved.
To avoid clipping, you may want to scale your input values. For example, if your convolution matrix
might produce an output value as much as double the maximum value in the input, then make sure the maxval
of the input (which is also the maxval of the output) is at least twice the actual maximum value in the
input.
Clipping negative numbers deserves special consideration. If your convolution matrix includes negative
numbers, it is possible for pnmconvol to calculate an output pixel as a negative value, which pnmconvol
would of course clip to zero, since Netpbm formats cannot represent negative numbers.
ConvolutionMatrix
There are three ways to specify the convolution matrix:
• directly with a -matrix option.
• In a file (or set of them) named by a -matrixfile option, whose contents are similar to a -matrix
option value.
• With a special PNM file.
The PNM file option is the hardest, and exists only because until Netpbm 10.49 (December 2009), it was
the only way.
The regular convolution matrix file is slightly easier to read than the -matrix option value, and makes
your command line less messy, but requires you to manage a separate file. With the file, you can have
separate convolution matrices for the individual color components, which you can't do with -matrix.
In any case, the convolution matrix pnmconvol uses is a matrix of real numbers. They can be whole or
fractional, positive, negative, or zero.
The convolution matrix always has an odd width and height, so that there is a center element. pnmconvol
figuratively places that center element over a pixel of the input image and weights that pixel and its
neighbors as indicated by the convolution matrix to produce the pixel in the same location of the output
image.
For a normal convolution, where you're neither adding nor subtracting total value from the image, but
merely moving it around, you'll want to make sure that all the numbers in the matrix add up to 1. If
they don't, pnmconvol warns you.
The elements of the matrix are actually tuples, one for each sample in the input. (I.e. if the input is
an RGB image, each element of the convolution matrix has one weight for red, one for green, and one for
blue.
DirectlyOntheCommandLine
Here are examples of a -matrix option:
-matrix=0,.2,0;.2,.2,.2;0,.2,0
-matrix=-1,3,-1
The value consists of each row of the matrix from top to bottom, separated by semicolons. Each row
consists of the elements of the row from left to right, separated by commas. You must of course have the
same number of elements in each row. Each element is a decimal floating point number and is the weight
to give to each component of a pixel that corresponds to that matrix location.
Note that when you supply this option via a shell, semicolon (";") probably means something to the shell,
so use quotation marks.
There is no way with this method to have different weights for different components of a pixel.
The -normalize option is often quite handy with -matrix because it lets you quickly throw together the
command without working out the math to make sure the matrix isn't biased. Note that if you use the
-normalize option, the weights in the matrix aren't actually the numbers you specify in the -matrix
option.
RegularMatrixFile
Specify the name of the matrix file with a -matrixfile option. Or specify a list of them, one for each
plane of the image.
Examples:
-matrixfile=mymatrix
-matrixfile=myred,mygreen,myblue
Each file applies to one plane of the image (e.g. red, green, or blue), in order. The matrix in each
file must have the same dimensions. If the input image has more planes than the number of files you
specify, the first file applies to the extra planes as well.
pnmconvol interprets the file as text, with lines delimited by Unix newline characters (line feeds).
Each line of the file is one row of the matrix, in order from top to bottom.
For each row, the file contains a floating point decimal number for each element in the row, from left to
right, separated by spaces. This is not just any old white space -- it is exactly one space. Two spaces
in a row mean you've specified a null string for an element (which is invalid). If you want to line up
your matrix visually, use leading and trailing zeroes in the floating point numbers to do it.
There is no way to put comments in the file. There is no signature or any other metadata in the file.
Note that if you use the -normalize option, the weights in the matrix aren't actually what is in the
file.
PNMFile
Before Netpbm 10.49 (December 2009), this was the only way to specify a convolution matrix. pnmconvol
used this method in an attempt to exploit the generic matrix processing capabilities of Netpbm, but as
the Netpbm formats don't directly allow matrices with the kinds of numbers you need in a convolution
matrix, it is quite cumbersome. In fact, there simply is no way to specify some convolution matrices
with a legal Netpbm image, so to make it work, pnmconvol has to relax the Netpbm file requirement that
sample values be no greater than the image's maxval. I.e. it isn't even a real PNM file.
The way you select this method of supplying the convolution matrix is to not specify -matrix or
-matrixfile. When you do that, you must specify the name of the PNM file (or PNM equivalent PAM file) as
a non-option argument (before the optional input file name).
There are two ways pnmconvol interprets the PNM convolution matrix image pixels as weights: with offsets,
and without offsets.
The simpler of the two is without offsets. That is what happens when you specify the -nooffset option.
In that case, pnmconvol simply normalizes the sample values in the PNM image by dividing by the maxval.
For example, here is a sample convolution file that causes an output pixel to be a simple average of its
corresponding input pixel and its 8 neighbors, resulting in a smoothed image:
P2
3 3
18
2 2 2
2 2 2
2 2 2
(Note that the above text is an actual PGM file -- you can cut and paste it. If you're not familiar with
the plain PGM format, see thePGMformatspecification(1)).
pnmconvol divides each of the sample values (2) by the maxval (18) so the weight of each of the 9 input
pixels gets is 1/9, which is exactly what you want to keep the overall brightness of the image the same.
pnmconvol creates an output pixel by multiplying the values of each of 9 pixels by 1/9 and adding.
Note that with maxval 18, the range of possible values is 0 to 18. After scaling, the range is 0 to 1.
For a normal convolution, where you're neither adding nor subtracting total value from the image, but
merely moving it around, you'll want to make sure that all the scaled values in (each plane of) your
convolution PNM add up to 1, which means all the actual sample values add up to the maxval.
Alternatively, you can use the -normalize option to scale the scaled values further to make them all add
up to 1 automatically.
When you don't specify -nooffset, pnmconvol applies an offset, the purpose of which is to allow you to
indicate negative weights even though PNM sample values are never negative. In this case, pnmconvol
subtracts half the maxval from each sample and then normalizes by dividing by half the maxval. So to get
the same result as we did above with -nooffset, the convolution matrix PNM image would have to look like
this:
P2
3 3
18
10 10 10
10 10 10
10 10 10
To see how this works, do the above-mentioned offset: 10 - 18/2 gives 1. The normalization step divides
by 18/2 = 9, which makes it 1/9 - exactly what you want. The equivalent matrix for 5x5 smoothing would
have maxval 50 and be filled with 26.
Note that with maxval 18, the range of possible values is 0 to 18. After offset, that's -9 to 9, and
after normalizing, the range is -1 to 1.
The convolution file will usually be a PGM, so that the same convolution gets applied to each color
component. However, if you want to use a PPM and do a different convolution to different colors, you can
certainly do that.
OtherFormsofConvolutionpnmconvol does only arithmetic, linear combination convolution. There are other forms of convolution
that are especially useful in image processing.
pgmmedian does median filtering, which is a form of convolution where the output pixel value, rather than
being a linear combination of the pixels in the window, is the median of a certain subset of them.
pgmmorphconv does dilation and erosion, which is like the median filter but the output value is the
minimum or maximum of the values in the window.