Convolution Remarks

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 datamask 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