对应标签和坐标点
Correspondence label and coordinates' points
如何获取矩阵中每个标签的第一次出现和最后一次出现(按列优先排序)的坐标?
标签矩阵示例(其中标签为 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
的第1st列包含横坐标,第2nd列包含纵坐标,第3列rd 列包含标签。每个标签应该有 2 行。
您可以使用 unique
.
检索矩阵的唯一值(您的 标签)
检索它们后,您可以使用 find
获取它们的索引。
将你的矩阵与它放在一起。
使用 for-loop 你可以这样做:
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 选项以某种方式在没有循环的情况下完成...
如果您正在寻找矢量化解决方案,您可以这样做:
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
我只需要尝试 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
这是我用 and 计时得到的结果(请注意,由于 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 之间。对于更大的尺寸或更多的标签,我的解决方案开始占据主导地位。
如何获取矩阵中每个标签的第一次出现和最后一次出现(按列优先排序)的坐标?
标签矩阵示例(其中标签为 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
的第1st列包含横坐标,第2nd列包含纵坐标,第3列rd 列包含标签。每个标签应该有 2 行。
您可以使用 unique
.
检索它们后,您可以使用 find
获取它们的索引。
将你的矩阵与它放在一起。
使用 for-loop 你可以这样做:
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 选项以某种方式在没有循环的情况下完成...
如果您正在寻找矢量化解决方案,您可以这样做:
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
我只需要尝试 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
这是我用 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 之间。对于更大的尺寸或更多的标签,我的解决方案开始占据主导地位。