您的代码中有几个错误,因此我将尝试一一解决。这是您的原始代码,重新格式化了一下:
img = [0 0 0 0 0;
0 1 1 0 0;
0 0 0 0 0;];
[m n] = size(img)
img = padarray(img, [2 2], 0)
fi_neighbors = zeros(1,8);
for i = 1:m
for j = 1:n
for r = 3:m
for c = 3:n
neighbors(1) = img(r-1,c-1); % Upper left.
neighbors(2) = img(r-1,c); % Upper middle.
neighbors(3) = img(r-1,c+1); % Upper right.
neighbors(4) = img(r,c-1); % left.
neighbors(5) = img(r,c+1); % right.
neighbors(6) = img(r+1,c+1); % Lower right. <-- corrected
neighbors(7) = img(r+1,c); % lower middle.
neighbors(8) = img(r+1,c-1); % Lower left.
end
end
fi_neighbors = [neighbors;fi_neighbors]
end
end
第一个错误是循环变量i 和j 从未使用过。因此它们是无用的(除了让我们执行相同的计算m x n 次)。让我们把它们拿出来。
img = [0 0 0 0 0;
0 1 1 0 0;
0 0 0 0 0;];
[m n] = size(img)
img = padarray(img, [2 2], 0)
fi_neighbors = zeros(1,8);
for r = 3:m
for c = 3:n
neighbors(1) = img(r-1,c-1); % Upper left.
neighbors(2) = img(r-1,c); % Upper middle.
neighbors(3) = img(r-1,c+1); % Upper right.
neighbors(4) = img(r,c-1); % left.
neighbors(5) = img(r,c+1); % right.
neighbors(6) = img(r+1,c+1); % Lower right.
neighbors(7) = img(r+1,c); % lower middle.
neighbors(8) = img(r+1,c-1); % Lower left.
end
end
fi_neighbors = [neighbors;fi_neighbors]
排除这些循环后,我们可以看到您在完成所有计算后才更新fi_neighbors 数组一次。这就是为什么您之前得到相同的结果m x n 次。我们需要将它移到循环中,在每组计算后更新结果(这次我省略了设置,只列出了循环):
for r = 3:m
for c = 3:n
neighbors(1) = img(r-1,c-1); % Upper left.
neighbors(2) = img(r-1,c); % Upper middle.
neighbors(3) = img(r-1,c+1); % Upper right.
neighbors(4) = img(r,c-1); % left.
neighbors(5) = img(r,c+1); % right.
neighbors(6) = img(r+1,c+1); % Lower right.
neighbors(7) = img(r+1,c); % lower middle.
neighbors(8) = img(r+1,c-1); % Lower left.
fi_neighbors = [neighbors;fi_neighbors] %// moved inside loops
end
end
接下来是我们循环的范围。您在数组的每一侧填充了 2 个零,因此您从行/列3 开始。这很好,但你仍然在m 和n 结束循环。这意味着您处理(m-2) x (n-2) 像素。你需要扩大范围。但实际上,您填充的内容超出了您的需要。每边一个像素的填充就足够了,所以让我们同时做两个,更改填充并更正范围:
img = [0 0 0 0 0;
0 1 1 0 0;
0 0 0 0 0;];
[m n] = size(img)
img = padarray(img, [1 1], 0)
fi_neighbors = zeros(1,8);
for r = 2:m+1
for c = 2:n+1
neighbors(1) = img(r-1,c-1); % Upper left.
neighbors(2) = img(r-1,c); % Upper middle.
neighbors(3) = img(r-1,c+1); % Upper right.
neighbors(4) = img(r,c-1); % left.
neighbors(5) = img(r,c+1); % right.
neighbors(6) = img(r+1,c+1); % Lower right.
neighbors(7) = img(r+1,c); % lower middle.
neighbors(8) = img(r+1,c-1); % Lower left.
fi_neighbors = [neighbors;fi_neighbors]
end
end
现在您应该有一个可以为您提供正确输出的工作程序:
fi_neighbors =
0 0 0 0 0 0 0 0 <-- img(m,n) neighbors
1 0 0 0 0 0 0 0
1 1 0 0 0 0 0 0
0 1 1 0 0 0 0 0
0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0
0 0 0 0 1 0 0 0
0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1
0 0 0 0 0 0 1 1
0 0 0 0 0 1 1 0
0 0 0 0 0 1 0 0 <-- img(1,1) neighbors
0 0 0 0 0 0 0 0
这可行,但请查看我添加到输出中的注释。结果的第一行包含像素img(m,n) 的邻居:图像中的最后一个 像素。倒数第二行包含 img(1,1) 的邻居,而 last 行只是因为您对 zeros(1,8) 的初始化而挂在那里。所有这些对我来说似乎都不自然,所以我将翻转结果数组,使img(1,1) 成为第一行。此外,在每次循环迭代中增长一个数组也很慢。我们要预先分配数组,然后将数据放在适当的位置。
由于我们引用原始图像中的像素,但在填充图像上进行计算,添加计数器变量比进行所有行/列索引计算要容易得多,所以我添加了 pix 为一个计数器:
img = [0 0 0 0 0;
0 1 1 0 0;
0 0 0 0 0;];
[m n] = size(img);
img = padarray(img, [1 1], 0)
fi_neighbors = zeros(m*n,8); % preallocate result array
pix = 0; % pixel counter
for r = 2:m+1
for c = 2:n+1
pix = pix + 1; % find neighbors for next pixel
neighbors(1) = img(r-1,c-1); % Upper left.
neighbors(2) = img(r-1,c); % Upper middle.
neighbors(3) = img(r-1,c+1); % Upper right.
neighbors(4) = img(r,c-1); % left.
neighbors(5) = img(r,c+1); % right.
neighbors(6) = img(r+1,c+1); % Lower right.
neighbors(7) = img(r+1,c); % lower middle.
neighbors(8) = img(r+1,c-1); % Lower left.
fi_neighbors(pix,:) = neighbors; % update the correct row
end
end
结果:
fi_neighbors =
0 0 0 0 0 1 0 0
0 0 0 0 0 1 1 0
0 0 0 0 0 0 1 1
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0
0 0 0 0 1 0 0 0
0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0
0 1 1 0 0 0 0 0
1 1 0 0 0 0 0 0
1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
现在,img(1,1) 的邻居在第 1 行,img(m,n) 的邻居在 m*n 行。
最后,您可以进行一些快速优化。它们都需要更改结果的顺序。如果您愿意以不同的顺序显示像素和邻居(我会尽量清楚地显示),那么我们可以首先更改循环的顺序以利用 MATLAB 的列优先顺序。
代替:
for r = 2:m+1
for c = 2:n+1
...
end
end
我们将使用:
for c = 2:n+1 % be sure to swap m and n as well!
for r = 2:m+1
...
end
end
对于大型矩阵,这应该有助于将我们正在使用的当前列保留在缓存中。这将改变像素的顺序,因此第二个像素不是img(1,2),而是img(2,1),然后是img(3,1),再到img(m,1),然后是img(1,2)。
第二个更改将您所有的邻居计算压缩为 2 行(可能是 3 行),但它会更改顺序,如下所示:
pix = 0; % pixel counter
for c = 2:n+1
for r = 2:m+1
pix = pix + 1; % find neighbors for next pixel
neighbors = img(r-1:r+1,c-1:c+1);
neighbors = neighbors(:).';
fi_neighbors(pix,:) = neighbors; % update the correct row
end
end
这会将img 的子矩阵围绕当前像素,然后使用冒号符号将其转换为列向量,最后将其转置为行向量。以下是neighbors 内生成的邻居位置:
neighbors(1) % Upper left.
neighbors(2) % left.
neighbors(3) % Lower left.
neighbors(4) % Upper middle.
neighbors(5) % *** current pixel ***
neighbors(6) % Lower middle.
neighbors(7) % Upper right.
neighbors(8) % right.
neighbors(9) % Lower right.
但是现在neighbors 中有 9 个元素,包括当前像素!如果您真的不想列出当前像素,我们可以解决这个问题,但无论哪种方式,我们都需要将fi_neighbors 的大小更改为(m*n,9)。如果需要,我们可以在最后从结果中删除第 5 列。
这是最终代码:
img = [0 0 0 0 0;
0 1 1 0 0;
0 0 0 0 0;];
[m n] = size(img);
img = padarray(img, [1 1], 0);
fi_neighbors = zeros(m*n,9); % preallocate result array
pix = 0; % pixel counter
for c = 2:n+1
for r = 2:m+1
pix = pix + 1; % find neighbors for next pixel
neighbors = img(r-1:r+1,c-1:c+1);
neighbors = neighbors(:).';
fi_neighbors(pix,:) = neighbors; % update the correct row
end
end
fi_neighbors(:,5) = []; % OPTIONAL - remove current pixel from each row
显然,您还可以做更多事情,但这应该是一个很好的开始。