Search code examples
javaimage-processingvectorconvolutionneighbours

Vector Convolution - Calculating the Index of a Neighbour Element


I am trying to implement a convolution method taking two vectors: an image; and a kernel. My problem is that i don't know how to calculate the index of the image neighbour element when I "slide" the kernel over the image vector. For example, with two identical vectors {0, 1, 2, 3, 4, 5, 6, 7, 8} I would like to achieve the following result:

enter image description here

My code so far is as follows:

public int[] convolve(int[] image, int[] kernel)
{       
  int imageValue; 
  int kernelValue;
  int outputValue;
  int[] outputImage = new int[image.length()];

  // loop through image
  for(int i = 0; i < image.length(); i++)
  {      
    outputValue = 0;

    // loop through kernel
    for(int j = 0; j < kernel.length(); j++)
    {
      neighbour = ?;

      // discard out of bound neighbours 
      if (neighbour >= 0 && neighbour < imageSize)
      {
        imageValue = image[neighbour];
        kernelValue = kernel[j];          
        outputValue += imageValue * kernelValue;
      }
    }

    output[i] = outputValue;
  }        

  return output;
}

Solution

  • As i + j - (kernel.length / 2) may be too short for an answer:

    public class Convolution
    {
        public static void main(String[] args)
        {
            int image[] = { 0,1,2,3,4,5,6,7,8 };
            int kernel[] = { 0,1,2,3,4,5,6,7,8 };
    
            int output[] = convolve(image, kernel);
    
            for (int i=0; i<image.length; i++)
            {
                System.out.printf(output[i]+" ");
            }
        }
    
        public static int[] convolve(int[] image, int[] kernel)
        {       
            int[] output = new int[image.length];
    
            // loop through image
            for(int i = 0; i < image.length; i++)
            {      
                System.out.println("Compute output["+i+"]");
                int outputValue = 0;
    
                // loop through kernel
                for(int j = 0; j < kernel.length; j++)
                {
                    int neighbour = i + j - (kernel.length / 2);
    
                    // discard out of bound neighbours 
                    if (neighbour >= 0 && neighbour < image.length)
                    {
                        int imageValue = image[neighbour];
                        int kernelValue = kernel[j];          
                        outputValue += imageValue * kernelValue;
    
                        System.out.println("image["+neighbour+"] and kernel["+j+"]");
                    }
                }
    
                output[i] = outputValue;
            }        
    
            return output;
        }
    }
    

    Note that this only works properly when the kernel has an odd length. In fact, what you are doing there is to move the center of the kernel through the image space (this is where the kernel.length/2 comes from). For even length kernels, like 0 1 2 3, you would have to decide whether you wanted to include...

    0 1 2 3 4 (image)
    3                   <- This line and/or ...
    2 3
    1 2 3
    0 1 2 3
      0 1 2 3
        0 1 2
          0 1 
            0           <- ... this line