我在MATALB中有一个带有{0, 1}
条目的矩阵。我希望按照以下规则收集成员1
:
1
开始,然后我将其放入group1
。 group1
。group1
)。group2
这里我举一个简单的例子:
A = [ 1 0 0 1 0
1 0 0 0 0
0 0 0 1 0
0 0 0 1 0
0 1 1 0 0 ]
group1 = {(1, 1)}
% I put in group1 the first element A(1, 1) (arbitrarly)
% Since in row 1 and column 1 we have A(1, 4) = 1 and A(2, 1) = 1 so I
% add them to group1
group1 = {(1, 1), (1, 4), (2, 1)}
% We see now that I have no one that correspond to the element A(2, 1) since
% A(2, :) = 0 and A(:, 1) = 0. But I have ones that correspond to element A(1, 4)
% which are A(3, 4) and A(4, 4) so I add them to group1
group1 = {(1, 1), (1, 4), (2, 1), (3, 4), (4, 4)}
% Also A(3, 4) and A(4, 4) have no corresponding ones. Hence I stop and I go to group2
group2 = {(5, 2)}
% I do the same and I get:
group1 = {(1, 1), (1, 4), (2, 1), (3, 4), (4, 4)}
group2 = {(5, 2), (5, 3)}
我想到的是这样的:
for i = 1:size(A, 1)
e{i} = find(A(i, :)~=0);
end
for j = 1:size(A, 1)
for i = e{j}
a{i} = find(A(:, i)~=0);
end
end
有什么建议吗?我可以不用循环吗?
非常感谢你的帮助。
答案 0 :(得分:2)
如果您有图像处理工具箱,一种方法是创建包含给定行或列中所有项的段。以下是矩阵的示例:
首先,用零边框填充数组:
Apad=padarray(A, [1,1], 0, 'both');
然后使用水平和垂直线对此阵列执行形态学闭合:
se1 = strel('line',3,0);
se2 = strel('line',3,90);
closedA = imclose(Apad,se1);
closedA = imclose(closedA,se2);
摆脱边框像素,
Segments=closedA(2:end-1, 2:end-1);
结果是:
Segments =
1 1 1 1 0
1 0 0 1 0
0 0 0 1 0
0 0 0 1 0
0 1 1 0 0
然后,您可以提取连接的组件:
CC = bwconncomp(Segments,4);
沿着组循环并识别每个组中包含的A
中的像素:
LinIndices=find(A);
for k=1:CC.NumObjects
Pixels{k}=LinIndices(ismember(LinIndices, CC.PixelIdxList{k}))
end
像素现在分组在数组Pixels
中,每个单元格包含给定组中像素的线性索引:
Pixels{1}= [1 2 16 18 19]
Pixels{2}= [10 15]
图形:
A(Pixels{1})=1
A(Pixels{2})=2
A =
1 0 0 1 0
1 0 0 0 0
0 0 0 1 0
0 0 0 1 0
0 2 2 0 0
注意结构元素se1
和se2
的大小必须优化到孤立像素之间的最大距离。有关加入细分的替代方法,请参阅this other answer by @Bentoy13。
答案 1 :(得分:2)
按照@Jigg的想法,我提出了另一个非常类似的解决方案。
为每个行和列定位第一个和最后一个索引,其中有一个索引。将这两个索引之间的段填充为另一个矩阵中的索引:
B = zeros(size(A));
for i=1:size(A,1)
m1 = find(A(i,:),1,'first');
m2 = find(A(i,:),1,'last');
B(i,m1:m2) = 1;
end
for i=1:size(A,2)
m1 = find(A(:,i),1,'first');
m2 = find(A(:,i),1,'last');
B(m1:m2,i) = 1;
end
(可能有更短的方法来做那件事......)
然后标记新阵列B的所有连接组件,并用阵列A:
对其进行掩码Result = bwlabel(A,4).*A;
答案 2 :(得分:1)
在过去尝试解决类似的问题时(主要是为了解决某些逻辑谜题),我总是发现最简单的方法是保留一堆你仍然需要查看的点,然后逐个处理它们直到堆栈为空。
写在pseudocode,这很简单:
groups = []
while any_points_left(A):
group = []
stack = [pick_random_point(A)]
while not_empty(stack):
p = stack.pop()
group.append(p)
mark_as_done(p)
for q in all_points_in_same_row_or_column(p):
stack.append(q)
groups.append(group)
翻译成Matlab(这不是这种代码的理想语言):
groups = {};
while nnz(A) > 0 % any points left?
% find random point
[i, j] = ind2sub(size(A), find(A, 1, 'first'));
stack = {[i, j]};
group = {};
while ~isempty(stack)
p = stack{end}; stack = stack(1:end-1); % pop point from stack
i = p(1); j = p(2);
if A(i, j) == 0 % check if point is not already removed
continue
end
A(i, j) = 0; % mark as done
group{end+1} = p; % add to group
for ii = 1:size(A, 1) % check same column
if A(ii, j) == 1
stack{end+1} = [ii, j]; % add to stack
end
end
for jj = 1:size(A, 2) % check same row
if A(i, jj) == 1
stack{end+1} = [i, jj]; % add to stack
end
end
end
groups{end+1} = group;
end
% print result
for ig = 1:length(groups)
fprintf('Group %i: ', ig)
group = groups{ig};
for ip = 1:length(group)
fprintf('(%i, %i) ', group{ip}(1), group{ip}(2))
end
fprintf('\n')
end
应该可以以清晰为代价将此代码编写得更紧凑。结果:
Group 1: (1, 1) (1, 4) (4, 4) (3, 4) (2, 1)
Group 2: (5, 2) (5, 3)