矢量卷积 - 计算邻居元素的索引

时间:2015-07-29 12:57:51

标签: java image-processing vector convolution neighbours

我正在尝试使用两个向量来实现卷积方法:图像;和一个内核。我的问题是当我在图像矢量上“滑动”内核时,我不知道如何计算图像邻居元素的索引。例如,使用两个相同的向量{0,1,2,3,4,5,6,7,8},我希望得到以下结果:

enter image description here

到目前为止我的代码如下:

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;
}

2 个答案:

答案 0 :(得分:2)

由于i + j - (kernel.length / 2)可能太短而无法回答:

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;
    }
}

请注意,这仅在内核具有奇数长度时才能正常工作。实际上,你在那里做的是通过图像空间移动内核的 center (这是kernel.length/2来自的地方)。对于甚至长度内核,例如0 1 2 3,您必须决定是否要包含...

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

答案 1 :(得分:1)

听起来像你想要像滑块一样的东西:

static class Slider implements Iterable<List<Integer>> {

    final List<Integer> kernel;
    final int imageWidth;
    final int center;

    public Slider(int imageWidth, int kernelWidth) {
        // Build my kernel offsets list.
        this.kernel = new ArrayList<>(kernelWidth);
        for (int i = 0; i < kernelWidth; i++) {
            kernel.add(i, i);
        }
        // Which kernel cell is in the center.
        center = kernelWidth / 2;
        // Remember the image width.
        this.imageWidth = imageWidth;
    }

    @Override
    public Iterator<List<Integer>> iterator() {
        return new Iterator<List<Integer>>() {
            int x = 0;

            @Override
            public boolean hasNext() {
                return x < imageWidth;
            }

            @Override
            public List<Integer> next() {
                List<Integer> slice = kernel.subList(Math.max(0, center - x), Math.min(kernel.size(), center - x + kernel.size()));
                x += 1;
                return slice;
            }

        };
    }

}

public void test() {
    List<Integer> image = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    List<Integer> kernel = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8);
    // Keep track of image position.
    int x = 0;
    for (List<Integer> slice : new Slider(image.size(), kernel.size())) {
        System.out.println(slice);
        int outputValue = 0;
        int imageValue = image.get(x++);
        for (Integer o : slice) {
            int kernelValue = kernel.get(o);
            outputValue += imageValue * kernelValue;
        }
        System.out.println("outputValue=" + outputValue);
    }
}