对应标签和坐标点

Correspondence label and coordinates' points

如何获取矩阵中每个标签的第一次出现和最后一次出现(按列优先排序)的坐标?

标签矩阵示例(其中标签为 14):

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 之间。对于更大的尺寸或更多的标签,我的解决方案开始占据主导地位。