summary refs log tree commit diff
path: root/pnmconvol.html
blob: d32b3a24c6e4a97241f9299e9ccd387cb773a9b2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.3//EN">
<html><head><title>Pnmconvol User Manual</title></head>
<body>
<h1>pnmconvol</h1>
Updated: 30 November 2018
<br>
<a href="#index">Table Of Contents</a>

<h2>NAME</h2>
pnmconvol - general MxN convolution on a Netpbm image

<h2 id="synopsis">SYNOPSIS</h2>

<b>pnmconvol</b>
{
<b>-matrix=</b><i>convolution_matrix</i>
|
<b>-matrixfile=</b><i>filename</i>[<b>,</b><i>filename</i>[<b>,</b> ...]]
}
[<b>-normalize</b>]
[<b>-bias=<i>n</i></b>]

[<i>netpbmfile</i>]

<p>

<b>pnmconvol</b>
<i>convolution_matrix_file</i>
[<b>-normalize</b>]
[<b>-nooffset</b>]
[<i>netpbmfile</i>]


<p>Minimum unique abbreviation of option is acceptable.  You may use double
hyphens instead of single hyphen to denote options.  You may use white
space in place of the equals sign to separate an option name from its value.


<h2 id="description">DESCRIPTION</h2>

<p>This program is part of <a href="index.html">Netpbm</a>.

<p><b>pnmconvol</b> reads a Netpbm image as input, convolves it with
a specified convolution matrix, and writes a Netpbm image as output.

<p>A command use for convolution is blurring.  See examples in the
<a href="pamgauss.html"><b>pamgauss</b></a> manual.
  
<p>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 <a href="#convolmatrix">
Convolution Matrix</a>.

<p>At the edges of the convolved image, where the convolution matrix would
extend over the edge of the image, <b>pnmconvol</b> 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 <b>pnmpad</b> 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
<kbd>pnmpad -left=2 -right=2 -top=1 -bottom=1</kbd>).  Feed that enlarged
image to <b>pnmconvol</b>, then use <b>pamcut</b> to chop the edges off the
convolved output, getting back to your original image dimensions.  (E.g.
<kbd>pamcut -left=2 -right=-2 -top=1 -bottom=-1</kbd>).

<p>The convolution computation can result in a value which is outside the
range representable in the output.  When that happens, <b>pnmconvol</b> just
clips the output, which means brightness is not conserved.

<p>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.

<p>Clipping negative numbers deserves special consideration.  If your
convolution matrix includes negative numbers, it is possible for
<b>pnmconvol</b> to calculate an output pixel as a negative value,
which <b>pnmconvol</b> would of course clip to zero, since Netpbm formats
cannot represent negative numbers.


<h3 id="convolmatrix">Convolution Matrix</h3>

<p>There are three ways to specify the convolution matrix:

<ul>
<li>directly with a <b>-matrix</b> option.

<li>In a file (or set of them) named by a <b>-matrixfile</b> option, whose
contents are similar to a <b>-matrix</b> option value.

<li>With a special PNM file.
</ul>

<p>The PNM file option is the hardest, and exists only because
until Netpbm 10.49 (December 2009), it was the only way.

<p>The regular convolution matrix file is slightly easier to read
than the <b>-matrix</b> 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 <b>-matrix</b>.

<p>In any case, the convolution matrix <b>pnmconvol</b> uses is a
matrix of real numbers.  They can be whole or fractional, positive,
negative, or zero.

<p>The convolution matrix always has an odd width and height, so that
there is a center element.  <b>pnmconvol</b> 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.

<p>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,
<b>pnmconvol</b> warns you.

<p>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.


<h4 id="matrixopt">Directly On the Command Line</h4>

<p>Here are examples of a <b>-matrix</b> option:

<pre>
<kbd>
    -matrix=0,.2,0;.2,.2,.2;0,.2,0
</kbd>
</pre>

<pre>
<kbd>
    -matrix=-1,3,-1
</kbd>
</pre>


<p>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.

<p>Note that when you supply this option via a shell, semicolon
(";") probably means something to the shell, so use quotation
marks.

<p>There is no way with this method to have different weights for different
components of a pixel.

<p>The <b>-normalize</b> option is often quite handy with <b>-matrix</b>
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
<b>-normalize</b> option, the weights in the matrix aren't actually the
numbers you specify in the <b>-matrix</b> option.


<h4 id="matrixfile">Regular Matrix File</h4>

<p>Specify the name of the matrix file with a <b>-matrixfile</b>
option.  Or specify a list of them, one for each plane of the image.

<p>Examples:

<pre>
<kbd>
    -matrixfile=mymatrix
</kbd>

<kbd>
    -matrixfile=myred,mygreen,myblue
</kbd>
</pre>

<p>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.

<p><b>pnmconvol</b> interprets the file as text, with lines delimited by Unix
newline characters (line feeds).

<p>Each line of the file is one row of the matrix, in order from top to
bottom.

<p>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.

<p>There is no way to put comments in the file.  There is no signature
or any other metadata in the file.

<p>Note that if you use the <b>-normalize</b> option, the weights in the
matrix aren't actually what is in the file.


<h4 id="matrixpnm">PNM File</h4>

<p>Before Netpbm 10.49 (December 2009), this was the only way to 
specify a convolution matrix.  <b>pnmconvol</b> 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, <b>pnmconvol</b> 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.

<p>The way you select this method of supplying the convolution matrix is to
<em>not</em> specify <b>-matrix</b> or <b>-matrixfile</b>.  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).

<p>There are two ways <b>pnmconvol</b> interprets the PNM convolution matrix
image pixels as weights: with offsets, and without offsets.

<p>The simpler of the two is without offsets.  That is what happens
when you specify the <b>-nooffset</b> option.  In that case,
<b>pnmconvol</b> simply normalizes the sample values in the PNM image
by dividing by the maxval.

<p>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:

<pre>
    P2
    3 3
    18
    2 2 2
    2 2 2
    2 2 2
</pre>

<p>(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
<a href="pgm.html">the PGM format specification</a>).

<p><b>pnmconvol</b> 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.  <b>pnmconvol</b> creates an output pixel by multiplying the
values of each of 9 pixels by 1/9 and adding.

<p>Note that with maxval 18, the range of possible values is 0 to 18.
After scaling, the range is 0 to 1.

<p>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
<b>-normalize</b> option to scale the scaled values further to make them all
add up to 1 automatically.

<p>When you <em>don't</em> specify <b>-nooffset</b>, <b>pnmconvol</b>
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, <b>pnmconvol</b> 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 <b>-nooffset</b>, the convolution
matrix PNM image would have to look like this:

<pre>
    P2
    3 3
    18
    10 10 10
    10 10 10
    10 10 10
</pre>

<p>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.

<p>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.

<p>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.


<h3 id="otherconvol">Other Forms of Convolution</h3>

<p><b>pnmconvol</b> does only arithmetic, linear combination convolution.
There are other forms of convolution that are especially useful in image
processing.

<p><b>pgmmedian</b> 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.

<p><b>pgmmorphconv</b> 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.


<h2 id="options">OPTIONS</h2>

<p>In addition to the options common to all programs based on libnetpbm
(most notably <b>-quiet</b>, see <a href="index.html#commonoptions">
Common Options</a>), <b>pnmconvol</b> recognizes the following
command line options:

<dl compact>

<dt><b>-matrix=</b><i>convolution_matrix</i>
<dd>The value of the convolution matrix.  See
<a href="#matrixopt">Convolution Matrix</a>.

<p>You may not specify both this and <b>-matrixfile</b>.

<p>This option was new in Netpbm 10.49 (December 2009).  Before
that, use a PNM file for the convolution matrix.

<dt><b>-matrixfile=</b><i>filename</i>
<dd>This specifies that you are supplying the convolution matrix in
a file and names that file.  See
<a href="#matrixfile">Convolution Matrix</a>.

<p>You may not specify both this and <b>-matrix</b>.

<p>This option was new in Netpbm 10.49 (December 2009).  Before
that, use a PNM file for the convolution matrix.

<dt><b>-normalize</b>

<dd>This option says to adjust the weights in your convolution matrix so they
all add up to one.  You usually want them to add up to one so that the
convolved result tends to have the same overall brightness as the input.  With
<b>-normalize</b>, <b>pnmconvol</b> scales all the weights by the same factor
to make the sum one.  It does this for each plane.

<p>This can be quite convenient because you can just throw numbers into
the matrix that have roughly the right relationship to each other and let
<b>pnmconvol</b> do the work of normalizing them.  And you can adjust a matrix
by raising or lowering certain weights without having to modify all the other
weights to maintain normalcy.  And you can use friendly integers.

<p>Example:

<pre>
<kbd>
    $ pnmconvol myimage.ppm -normalize -matrix=1,1,1;1,1,1;1,1,1
</kbd>
</pre>

<p>This is of course a basic 3x3 average, but without you having to
specify 1/9 (.1111111) for each weight.

<p>This option was new in Netpbm 10.50 (March 2010).  But before Netpbm 10.79
(June 2017), it has no effect when you specify the convolution matrix via
pseudo-PNM file.

<dt><b>-bias=</b><i>n</i>
<dd>

<p>This specifies an amount to add to the convolved value for each sample.

<p>The purpose of this addition is normally to handle negative convolution
results.  Because the convolution matrix can contain negative numbers, the
convolved value for a pixel could be negative.  But Netpbm formats cannot
contain negative sample values, so without any bias, such samples would get
clipped to zero.  The bias allows the output image to retain the information,
and a program that pocesses that output, knowing the bias value, could
reconstruct the real convolved values.

<p>For example, with <b>bias=100</b>, a sample whose convolved value is -5
appears as 95 in the output, whereas a sample whose convolved value is 5
appears as 105 in the output.

<p>A typical value for the bias is half the maxval, allowing the same range on
either side of zero.

<p>If the sample value, after adding the bias, is still less than
zero, <b>pnmconvol</b> clips it to zero.  If it exceeds the maxval of the
output image, it clips it to the maxval.

<p>The default is zero.

<p>This option was new in Netpbm 10.68 (September 2014).

<dt><b>-nooffset=</b>
<dd>This is part of the obsolete PNM image method of specifying the
convolution matrix.  See
<a href="#matrixpnm">Convolution Matrix</a>.

</dl>

<h2 id="history">HISTORY</h2>

<p>The <b>-nooffset</b> option was new in Netpbm 10.23 (July 2004),
making it substantially easier to specify a convolution matrix, but
still hard.  In Netpbm 10.49 (December 2009), the PNM convolution
matrix tyranny was finally ended with the <b>-matrix</b> and
<b>-matrixfile</b> options.  In between, <b>pnmconvol</b> was broken
for a while because the Netpbm library started enforcing the
requirement that a sample value not exceed the maxval of the
image.  <b>pnmconvol</b> used the Netpbm library to read the PNM
convolution matrix file, but in the pseudo-PNM format
that <b>pnmconvol</b> uses, a sample value sometimes has to exceed the
maxval.

<h2 id="seealso">SEE ALSO</h2>

<b><a href="pnmsmooth.html">pnmsmooth</a></b>,
<b><a href="pgmmorphconv.html">pgmmorphconv</a></b>,
<b><a href="pgmmedian.html">pgmmedian</a></b>,
<b><a href="pnmnlfilt.html">pnmnlfilt</a></b>,
<b><a href="pgmkernel.html">pgmkernel</a></b>,
<b><a href="pamgauss.html">pamgauss</a></b>,
<b><a href="pammasksharpen.html">pammasksharpen</a></b>,
<b><a href="pnmpad.html">pnmpad</a></b>,
<b><a href="pamcut.html">pamcut</a></b>,
<b><a href="pnm.html">pnm</a></b>

<h2 id="authors">AUTHORS</h2>

Copyright (C) 1989, 1991 by Jef Poskanzer.
<br>

Modified 26 November 1994 by Mike Burns, <a
href="mailto:burns@chem.psu.edu">burns@chem.psu.edu</a>


<hr>
<h2 id="index">Table Of Contents</h2>
<ul>
<li><a href="#synopsis">SYNOPSIS</a>
<li><a href="#description">DESCRIPTION</a>
  <ul>
  <li><a href="#convolmatrix">Convolution Matrix</a>
    <ul>
    <li><a href="#matrixopt">Directly On the Command Line</a>
    <li><a href="#matrixfile">Regular Matrix File</a>
    <li><a href="#matrixpnm">PNM File</a>
    </ul>
  <li><a href="#otherconvol">Other Forms of Convolution</a>
  </ul>
<li><a href="#options">OPTIONS</a>
<li><a href="#history">HISTORY</a>
<li><a href="#seealso">SEE ALSO</a>
<li><a href="#authors">AUTHORS</a>
</ul>
</body>
</html>