如何获取矩阵中每个标签的第一个和最后一个出现的坐标(在列主要排序下)?
标签矩阵示例(标签为1
至4
):
L = [
1 1 1 1 0 0 0 0
0 0 0 0 2 2 0 0
0 0 0 0 0 0 2 0
0 0 0 0 0 0 0 0
0 0 0 0 0 3 0 0
0 0 0 0 0 0 3 3
0 0 0 4 0 0 0 0
4 4 4 0 0 0 0 0
];
对于上面的示例L
,我想获得一个坐标矩阵,如:
M = [
1 1 1
1 4 1
2 5 2
3 7 2
5 6 3
6 8 3
8 1 4
7 4 4 ];
M
的1 st 列包含水平坐标,2 nd 包含垂直坐标,3 rd 列包含标签。每个标签应该有2行。
答案 0 :(得分:5)
使用for循环,您可以这样做:
M=zeros(2*max(L(:)),3);
for k=1:max(L(:))
[r,c]=find(L==k);
s=sortrows([r c],2);
M(k*2-1:k*2,:)=[s(1,:) k; s(end,:) k];
end
M =
1 1 1
1 4 1
2 5 2
3 7 2
5 6 3
6 8 3
8 1 4
7 4 4
也许以某种方式使用regionprops选项,你可以在没有循环的情况下完成...
答案 1 :(得分:5)
如果您正在寻找矢量化解决方案,您可以这样做:
nTags = max(L(:));
whois = bsxfun(@eq,L,reshape(1:nTags,1,1,[]));
% whois = L == reshape(1:nTags,1,1,[]); % >=R2016b syntax.
[X,Y,Z] = ind2sub(size(whois), find(whois));
tmp = find(diff([0; Z; nTags+1])); tmp = reshape([tmp(1:end-1) tmp(2:end)-1].',[],1);
M = [X(tmp), Y(tmp), repelem(1:nTags,2).'];
或者使用极端变量重用:
nTags = max(L(:));
Z = bsxfun(@eq,L,reshape(1:nTags,1,1,[]));
[X,Y,Z] = ind2sub(size(Z), find(Z));
Z = find(diff([0; Z; nTags+1]));
Z = reshape([Z(1:end-1) Z(2:end)-1].',[],1);
M = [X(Z), Y(Z), repelem(1:nTags,2).'];
这是我的基准代码:
function varargout = b42973322(isGPU,nLabels,lMat)
if nargin < 3
lMat = 1000;
end
if nargin < 2
nLabels = 20; % if nLabels > intmax('uint8'), Change the type of L to some other uint.
end
if nargin < 1
isGPU = false;
end
%% Create L:
if isGPU
L = sort(gpuArray.randi(nLabels,lMat,lMat,'uint8'),2);
else
L = sort(randi(nLabels,lMat,lMat,'uint8'),2);
end
%% Equality test:
M{3} = DeviL2(L);
M{2} = DeviL1(L);
M{1} = Adiel(L);
assert(isequal(M{1},M{2},M{3}));
%% Timing:
% t(3) = timeit(@()DeviL2(L)); % This is always slower, so it's irrelevant.
t(2) = timeit(@()DeviL1(L));
t(1) = timeit(@()Adiel(L));
%% Output / Print
if nargout == 0
disp(t);
else
varargout{1} = t;
end
end
function M = Adiel(L)
M=[];
for k=1:max(L(:))
[r,c]=find(L==k);
s=sortrows([r c],2);
M=[M;s(1,:) k; s(end,:) k];
end
end
function M = DeviL1(L)
nTags = max(L(:));
whois = L == reshape(1:nTags,1,1,[]); % >=R2016b syntax.
[X,Y,Z] = ind2sub(size(whois), find(whois));
tmp = find(diff([0; Z; nTags+1])); tmp = reshape([tmp(1:end-1) tmp(2:end)-1].',[],1);
M = [X(tmp), Y(tmp), repelem(1:nTags,2).'];
end
function M = DeviL2(L)
nTags = max(L(:));
Z = L == reshape(1:nTags,1,1,[]);
[X,Y,Z] = ind2sub(size(Z), find(Z));
Z = find(diff([0; Z; nTags+1]));
Z = reshape([Z(1:end-1) Z(2:end)-1].',[],1);
M = [X(Z), Y(Z), repelem(1:nTags,2).'];
end
答案 2 :(得分:5)
我只需要使用accumarray
:
R = size(L, 1);
[rowIndex, colIndex, values] = find(L); % Find nonzero values
index = (colIndex-1).*R+rowIndex; % Create a linear index
labels = unique(values); % Find unique values
nLabels = numel(labels);
minmax = zeros(2, nLabels);
minmax(1, :) = accumarray(values, index, [nLabels 1], @min); % Collect minima
minmax(2, :) = accumarray(values, index, [nLabels 1], @max); % Collect maxima
temp = ceil(minmax(:)/R);
M = [minmax(:)-R.*(temp-1) temp repelem(labels, 2, 1)]; % Convert index to subscripts
M =
1 1 1
1 4 1
2 5 2
3 7 2
5 6 3
6 8 3
8 1 4
7 4 4
以下是我使用Dev-iL's script和Adiel's newest code计算的内容(请注意,由于Adiel的代码使用uint8
值,标签数量不能超过127作为索引):
| Adiel | Dev-iL | gnovice
-----------------------+---------+---------+---------
20 labels, 1000x1000 | 0.0753 | 0.0991 | 0.0889
20 labels, 10000x10000 | 12.0010 | 10.2207 | 8.7034
120 labels, 1000x1000 | 0.1924 | 0.3439 | 0.1387
因此,对于中等数量的标签和(相对)较小的尺寸,Adiel的循环解决方案看起来最好,我的解决方案位于他和Dev-iL之间。对于更大尺寸或更多数量的标签,我的解决方案开始起带头作用。
答案 3 :(得分:0)