给定矩阵 M(n,m) 的线性索引,您可以确信元素 M(i,j) = M(i-1, j-1) = M(i-1 + n * (j-2)) 的左上角邻域
在“线性索引”空间中,表示该元素的偏移量是
-n-1
对所有其他位置执行此操作,我们会发现
-n-1 | -1 | n-1
-n | x | n => [-n-1, -n, -n+1, -1, +1, +n-1, +n, +n+1]
-n+1 | +1 | n+1
因此,您可以使用上述值创建矢量偏移量(将 n 替换为第一维)。例如,如果 M 是 (5x4),那么
offset = [-6 -5 -4 -1 1 4 5 6];
然后创建所有索引:
indices = bsxfun(@plus, (1:m*n), offset(:));
bsxfun 是“在这些元素上执行此功能;其中一个元素具有单一维度而另一个没有,相应地扩展”的一种很酷的简写。您可以对 repmat 执行相同的操作,但这会创建不必要的中间矩阵(有时可能非常大)。
该命令将创建一个包含所有 8 个邻居的索引的 (8 x m*n) 矩阵,包括可能不是真正邻居的那些...您需要修复的问题。
几种可能的方法:
- 在开始之前填充矩阵
- 不关心换行,只要去掉掉边缘的元素就行了
- 为所有“边缘”的蒙版创建一个蒙版。
我更喜欢后者。 “离边”的意思是:
- 在顶行上升
- 在左列中向左移动
- 在底行向下
- 在右栏中向右移动
在这四种情况下,都有 3 个索引“无效”。它们在上述矩阵中的位置可以确定如下:
mask = zeros(size(M));
mask(:,1) = 1;
left = find(mask == 1);
mask(:,end) = 2;
right = find(mask == 2);
mask(1,:) = 3;
top = find(mask == 3);
mask(end,:) = 4;
bottom = find(mask == 4);
edgeMask = ones(8,m*n);
edgeMask(1:3, top) = 0;
edgeMask([1 4 6], left) = 0;
edgeMask([3 5 8], right) = 0;
edgeMask(6:8, bottom) = 0;
现在您拥有所需的一切 - 所有索引和“无效”索引。没有循环。
如果你有野心,你可以把它变成一个元胞数组,但它会比使用完整数组 + 掩码慢。例如,如果你想找到一个值的所有邻居的平均值,你可以这样做
meanNeighbor = reshape(sum(M(indices).*edgeMask, 1)./sum(edgeMask, 1), size(M));
编辑重新阅读您的问题,我看到您想要一个 M*N,8 维。我的代码被转置了。我相信你可以弄清楚如何适应它......
ATTRIBUTION @Tin 很有帮助地建议对上述帖子进行许多出色的修改,但在审核过程中被拒绝了。我不能完全消除这种不公正 - 但想在这里记录我的感谢。
扩展到不同的地区和多维度
如果你有一个 N 维图像矩阵 M,你可以按如下方式找到邻居:
temp = zeros(size(M));
temp(1:3,1:3,1:3) = 1;
temp(2,2,2) = 2;
offsets = find(temp==1) - find(temp==2);
如果你想要一个大小一定半径的区域,你可以这样做
sz = size(M);
[xx yy zz] = meshgrid(1:sz(1), 1:sz(2), 1:sz(3));
center = round(sz/2);
rr = sqrt((xx - center(1)).^2 + (yy - center(2)).^2 + (zz - center(3)).^2);
offsets = find(rr < radius) - find(rr < 0.001);
您大概可以按照前面针对 2D 情况显示的线条来解决边缘问题。
未经测试 - 请查看您是否发现上述任何问题。