简体   繁体   English

获取矩阵子集的边界单元的索引。 MATLAB

[英]Get the indexes of the boundary cells of a subset of a matrix. Matlab

Given a matrix where 1 is the current subset 给定矩阵,其中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

Is there a function, or quick method to get change the subset to the boundary of the current subset? 是否有函数或快速方法将子集更改为当前子集的边界?

Eg. 例如。 Get this subset from 'test' above 从上面的'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

In the end I just want to get the minimum of the cells surrounding a subset of a matrix. 最后,我只想获得围绕矩阵子集的最小单元格。 Sure I could loop through and get the minimum of the boundary (cell by cell), but there must be a way to do it with the method i've shown above. 当然,我可以循环并获得最小的边界(逐个单元格),但必须有一种方法来实现我上面显示的方法。

Note the subset WILL be connected, but may not be rectangular. 请注意,子集将连接,但可能不是矩形。 This may be the big catch. 这可能是最大的收获。

This is a possible subset.... (Would pad this with a NaN border) 这是一个可能的子集....(用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

Ideas? 想法?

The basic steps I'd use are: 我使用的基本步骤是:

  1. Perform a dilation on the shape to get a new area which is the shape plus its boundary 对形状进行扩张以获得形状加上其边界的新区域
  2. Subtract the original shape from the dilated shape to leave just the boundary 从扩张的形状中减去原始形状,只留下边界
  3. Use the boundary to index your data matrix, then take the minimum. 使用边界索引数据矩阵,然后采用最小值。

Dilation 扩张

What I want to do here is pass a 3x3 window over each cell and take the maximum value in that window: 我想在这里做的是在每个单元格上传递一个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

Shape subtraction 形状减法

This is basically a logical AND and a logical NOT to remove the intersection: 这基本上是一个逻辑AND和逻辑NOT来删除交集:

ABoundary = ADilated & (~APadded);

At this stage you may want to remove the border we added to do the dilation, since we don't need it any more. 在这个阶段,你可能想要删除我们添加的边框进行扩张,因为我们不再需要它了。

ABoundary = ABoundary(2:end-1, 2:end-1);

Find the minimum data point along the boundary 找到边界的最小数据点

We can use our logical boundary to index the original data into a vector, then just take the minimum of that vector. 我们可以使用逻辑边界将原始数据索引到向量中,然后只取最小值。

dataMinimum = min(data(ABoundary));

You should look at this as morphology problem, not set theory. 你应该将其视为形态学问题,而不是理论问题。 This can be solved pretty easily with imdilate() (requires the image package). 使用imdilate() (需要图像包)可以很容易地解决这个问题。 You basically only need to subtract the image to its dilation with a 3x3 matrix of 1. 你基本上只需要用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

It does not, however, pads with NaN. 但是,它不会填充NaN。 If you really want that, you could pad your original matrix with false, do the operation, and then check if there's any true values in the border. 如果你真的想要,你可以用false填充原始矩阵,进行操作,然后检查边框中是否有任何真值。

Note that you don't have to use logical() in which case you'll have to use ones() instead of true() . 请注意,您不必使用logical()在这种情况下,您必须使用ones()而不是true() But that takes more memory and has worse performance. 但这需要更多的内存并且性能更差。

EDIT: since you are trying to do it without using any matlab toolbox, take a look at the source of imdilate() in Octave . 编辑:因为你试图不使用任何matlab工具箱,所以看看Octave中imdilate()来源 For the case of logical matrices (which is your case) it's a simple usage of filter2() which belongs to matlab core. 对于逻辑矩阵的情况(这是你的情况),它是filter2()的一个简单用法,它属于matlab核心。 That said, the following one line should work fine and be much faster 也就是说,以下一行应该可以正常运行并且速度更快

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

One possible solution is to take the subset and add it to the original matrix, but ensure that each time you add it, you offset its position by +1 row, -1 row and +1 column, -1 column. 一种可能的解决方案是获取子集并将其添加到原始矩阵,但确保每次添加它时,将其位置偏移+1行,-1行和+1列,-1列。 The result will then be expanded by one row and column all around the original subset. 然后,结果将在原始子集周围扩展一行和一列。 You then use the original matrix to mask the original subet to zero. 然后使用原始矩阵将原始子集掩盖为零。

Like this: 像这样:

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.

The result for this on your test matrix is: 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

Edited - it now grabs the corners as well, by moving the subset up and to the left, up and to the right, down then left and down then right. 编辑 - 它现在抓住角落,通过向上和向左移动子集,向上和向右,向下然后向左和向下然后向右移动。

I expect this would be a very quick way to achieve this - it doesn't have any loops, nor functions - just matrix operations. 我希望这将是一种非常快速的方法来实现这一点 - 它没有任何循环,也没有函数 - 只是矩阵运算。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM