向量卷积 - 计算相邻元素的索引
Vector Convolution - Calculating the Index of a Neighbour Element
我正在尝试实现一种采用两个向量的卷积方法:一个图像;和一个内核。我的问题是,当我 "slide" 图像向量上的内核时,我不知道如何计算图像相邻元素的索引。例如,对于两个相同的向量 {0, 1, 2, 3, 4, 5, 6, 7, 8} 我想实现以下结果:
到目前为止我的代码如下:
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;
}
我觉得你想要滑块之类的东西:
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);
}
}
因为 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;
}
}
请注意,这仅在内核具有 奇数 长度时才能正常工作。事实上,你在那里做的是通过图像 space 移动内核的 center (这是 kernel.length/2
的来源)。对于 even 长度的内核,例如 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
我正在尝试实现一种采用两个向量的卷积方法:一个图像;和一个内核。我的问题是,当我 "slide" 图像向量上的内核时,我不知道如何计算图像相邻元素的索引。例如,对于两个相同的向量 {0, 1, 2, 3, 4, 5, 6, 7, 8} 我想实现以下结果:
到目前为止我的代码如下:
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;
}
我觉得你想要滑块之类的东西:
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);
}
}
因为 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;
}
}
请注意,这仅在内核具有 奇数 长度时才能正常工作。事实上,你在那里做的是通过图像 space 移动内核的 center (这是 kernel.length/2
的来源)。对于 even 长度的内核,例如 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