【问题标题】:Get the neighbors of a matrix element获取矩阵元素的邻居
【发布时间】:2014-01-30 16:58:30
【问题描述】:

我有一个矩阵,对于每个元素,我想获取其周围元素的索引。所有这些结果都必须以下列方式存储到矩阵中。矩阵的每一行对应一个矩阵元素,并且该矩阵的每一列都包含 s 个相邻索引。例如,对于一个 4x4 矩阵,我们将得到一个 16x8 结果数组。一些矩阵元素没有 8 个邻居。

有一个例子,我认为它正在工作,我有什么办法可以避免for循环?:

ElementNeighbors = [];
for n = 1:numel(Matrix)
    NeighborsMask = [ n-1 n+1 n+size(matrix,1) n-size(Matrix,1) n-size(Matrix,1)-1 n-size(Matrix,1)+1 ...
        n+size(Matrix,1)-1 n+size(Matrix,1)+1 ];

    ElementNeighbors = [ElementNeighbors ; NeighborsMask ];
end
ElementNeighbors (ElementNeighbors ==0|ElementNeighbors <0) = NaN;

【问题讨论】:

  • 我不理解所需输出的描述。可以举个例子吗?
  • 这个问题到处都有解决方案(例如,here)。矩阵边缘少于八个邻居的元素呢?
  • 我在想,一个面具。对于边框元素,不会有 8 个邻居。

标签: matlab


【解决方案1】:

给定矩阵 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 情况显示的线条来解决边缘问题。

未经测试 - 请查看您是否发现上述任何问题。

【讨论】:

  • M(i-1 + n * (j-2)) 为什么是j-2 而不是j-1
  • 为什么在“线性索引”空间中的偏移量是-n-1 而不仅仅是n?另外,为什么“用第二维代替n”而不是第一维?谢谢。
  • 对不起 - 你是对的;那应该是“第一维”。我更新了答案。至于j-2——真的是(j-1) - 1(左上角=向左一,上方一排。)。
  • 好的,我认为现在可以了。感谢您的宝贵时间!
  • @Tin 感谢您所做的编辑 - 他们在审核过程中被“拒绝”;我无法通过单击按钮撤消的事情。所以我尽我所能重新应用你的编辑,谢谢。今天晚些时候我会再看看你的另一篇文章;我认为只需稍作改动即可完成相同的操作 - 计算邻域偏移向量,而不是对其进行硬编码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-19
  • 1970-01-01
  • 2016-04-06
  • 1970-01-01
  • 2012-10-04
  • 2019-04-09
  • 1970-01-01
相关资源
最近更新 更多