[英]Get the indexes of the boundary cells of a subset of a matrix. Matlab
给定矩阵,其中1是当前子集
test =
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 1 0 0
0 0 1 1 0 0
0 0 0 0 0 0
0 0 0 0 0 0
是否有函数或快速方法将子集更改为当前子集的边界?
例如。 从上面的'test'获取此子集
test =
0 0 0 0 0 0
0 1 1 1 1 0
0 1 0 0 1 0
0 1 0 0 1 0
0 1 1 1 1 0
0 0 0 0 0 0
最后,我只想获得围绕矩阵子集的最小单元格。 当然,我可以循环并获得最小的边界(逐个单元格),但必须有一种方法来实现我上面显示的方法。
请注意,子集将连接,但可能不是矩形。 这可能是最大的收获。
这是一个可能的子集....(用NaN边框填充它)
test =
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 1 0 0
0 0 1 1 0 0
0 0 1 1 1 1
0 0 1 1 1 1
想法?
我使用的基本步骤是:
我想在这里做的是在每个单元格上传递一个3x3窗口,并在该窗口中取最大值:
[m, n] = size(A); % assuming A is your original shape matrix
APadded = zeros(m + 2, n + 2);
APadded(2:end-1, 2:end-1) = A; % pad A with zeroes on each side
ADilated = zeros(m + 2, n + 2); % this will hold the dilated shape.
for i = 1:m
for j = 1:n
mask = zeros(size(APadded));
mask(i:i+2, j:j+2) = 1; % this places a 3x3 square of 1's around (i, j)
ADilated(i + 1, j + 1) = max(APadded(mask));
end
end
这基本上是一个逻辑AND和逻辑NOT来删除交集:
ABoundary = ADilated & (~APadded);
在这个阶段,你可能想要删除我们添加的边框进行扩张,因为我们不再需要它了。
ABoundary = ABoundary(2:end-1, 2:end-1);
我们可以使用逻辑边界将原始数据索引到向量中,然后只取最小值。
dataMinimum = min(data(ABoundary));
你应该将其视为形态学问题,而不是理论问题。 使用imdilate()
(需要图像包)可以很容易地解决这个问题。 你基本上只需要用1x3的3x3矩阵将图像减去其扩张 。
octave> test = logical ([0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 1 0 0
0 0 1 1 0 0
0 0 1 1 1 1
0 0 1 1 1 1]);
octave> imdilate (test, true (3)) - test
ans =
0 0 0 0 0 0
0 1 1 1 1 0
0 1 0 0 1 0
0 1 0 0 1 1
0 1 0 0 0 0
0 1 0 0 0 0
但是,它不会填充NaN。 如果你真的想要,你可以用false填充原始矩阵,进行操作,然后检查边框中是否有任何真值。
请注意,您不必使用logical()
在这种情况下,您必须使用ones()
而不是true()
。 但这需要更多的内存并且性能更差。
编辑:因为你试图不使用任何matlab工具箱,所以看看Octave中imdilate()
的来源 。 对于逻辑矩阵的情况(这是你的情况),它是filter2()
的一个简单用法,它属于matlab核心。 也就是说,以下一行应该可以正常运行并且速度更快
octave> (filter2 (true (3), test) > 0) - test
ans =
0 0 0 0 0 0
0 1 1 1 1 0
0 1 0 0 1 0
0 1 0 0 1 1
0 1 0 0 0 0
0 1 0 0 0 0
一种可能的解决方案是获取子集并将其添加到原始矩阵,但确保每次添加它时,将其位置偏移+1行,-1行和+1列,-1列。 然后,结果将在原始子集周围扩展一行和一列。 然后使用原始矩阵将原始子集掩盖为零。
像这样:
test_new = test + ...
[[test(2:end,2:end);zeros(1,size(test,1)-1)],zeros(size(test,1),1)] + ... %move subset up-left
[[zeros(1,size(test,1)-1);test(1:end-1,2:end)],zeros(size(test,1),1)] + ... %move down-left
[zeros(size(test,1),1),[test(2:end,1:end-1);zeros(1,size(test,1)-1)]] + ... %move subset up-right
[zeros(size(test,1),1),[zeros(1,size(test,1)-1);test(1:end-1,1:end-1)]]; %move subset down-right
test_masked = test_new.*~test; %mask with original matrix
result = test_masked;
result(result>1)=1; % ensure that there is only 1's, not 2, 3, etc.
test
矩阵的结果如下:
result =
0 0 0 0 0 0
0 1 1 1 1 0
0 1 0 0 1 0
0 1 0 0 1 1
0 1 0 0 0 0
0 1 0 0 0 0
编辑 - 它现在抓住角落,通过向上和向左移动子集,向上和向右,向下然后向左和向下然后向右移动。
我希望这将是一种非常快速的方法来实现这一点 - 它没有任何循环,也没有函数 - 只是矩阵运算。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.