【问题标题】:Correspondence label and coordinates' points对应标签和坐标点
【发布时间】:2017-03-23 10:24:54
【问题描述】:

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

标签矩阵示例(其中标签为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 包含垂直坐标,第 3rd 列包含标签。每个标签应该有 2 行。

【问题讨论】:

  • M的第一行不应该是1 1 1吗?
  • 是的,你说得对!,我编辑
  • 另外,您使用的是哪个版本的 MATLAB?
  • 版本 R2015a

标签: matlab matrix coordinates subset matrix-indexing


【解决方案1】:

使用 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 选项你可以在没有循环的情况下做到这一点......

【讨论】:

  • 我完全同意你的建议,但我不明白为什么在某些点上我得到了矩阵 [255 255 标签],标签很好,但为什么 x 和 y 是 255? : -o
  • 没关系,我找到了原因!我不是一个双矩阵,而是一个 uint8 ^^。感谢您的帮助:-)
【解决方案2】:

我只需要用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 scriptAdiel'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 之间。对于更大尺寸或更多数量的标签,我的解决方案开始领先。

【讨论】:

  • 干得好!矢量化 FTW :)
【解决方案3】:

如果您正在寻找矢量化解决方案,您可以这样做:

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

【讨论】:

  • 创意+1!但除了阅读复杂的代码之外,我不确定它是否更快......有时bsxfun 在这种方式下可能会很糟糕。
  • 哇,好吧,我根本不习惯这种写作,但谢谢你,它会让我理解矢量化:-D。谢谢!
  • 谢谢大家! @Adiel 是否愿意用基准来支持这些主张(使用更大的数据集......)? :)
  • 所以,我检查了它的 L 为 800x800,有 20100 个不同的标签。我的解决方案需要 12.03 秒,您的第一个解决方案需要 17.64 秒。你的第二个需要 21.88 秒。最终解决方案是相同的。所以bsxfun 很漂亮,但并不总是最好的方式......
  • @Adiel 我也对它进行了基准测试。偏好是标签数量的函数。我用 20 个标签在 4000x4000 上进行了尝试,我的第二种方法要好 30% 左右。那是除非矩阵是gpuArray,在这种情况下循环每次都会失败(它比 x1.3 - x4 慢)。
【解决方案4】:

您可以使用unique 检索矩阵的唯一值(您的标签)。

检索它们后,您可以使用find 获取它们的索引。

把你的矩阵和它放在一起。

【讨论】:

  • 其他三个答案提供了一个完整的方法,而不是这个非常一般的指导方针,我建议要么扩展这个答案以提供一个完整的方法,或者如果你认为它会添加它完全删除它鉴于其他答案,这个问题没有价值。
猜你喜欢
  • 2015-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-09
  • 2021-05-08
相关资源
最近更新 更多