Generally for an image of h
rows and w
,
and ignoring boundary considerations, we loop over rows and then over columns:
for (j=0; j<h; j++) { for (i=0; i<w; i++) { do_the_convolution; save_the_pixel_value; } }
To do the convolution we might fill a data array the same size as the
convolution mask. For a convolution kernel mask[mh][mw]
, we
could store the pixel data under the mask in data[mh][mw]
.
Then we can generally do the convolution as
sum = 0; for (j1=0; j1<mh; j1++) { for (i1=0; i1<mw; i1++) { sum = sum + mask[j1][i1]*data[j1][i1]; } }
The method doConvolve
uses this algorithm.
For simple convolution masks, such as a 3 x 3 operator, we can save the pixel data under the mask as independent variables and the mask itself as constants. For example:
pixel data | mask data |
---|---|
p00 p01 p02 p10 p11 p12 p20 p21 p22 |
0 -1 0 -1 4 -1 0 -1 0 |
The convolution for a single pixel could be calculated in one line of code:
sum = (p11>>2) - (p01+p10+p12+p21);
The method doEdgeMag uses this approach.
To keep the output confined to abs(sum)≤1, we need to divide the result by 8.
For positive integers the code s>>3
is equivalent to s/8
For negative integers the results are generally different, as
shown by the example Java program test.java