在大型矩阵中获取后续 ID 的最有效方法

Most efficient way to get consequent IDs in a large matrix

在做3D CT的分水岭后,我只选择小于某个值和大于另一个值的粒子。然而,作为最终输出,我需要一个仅包含连续 ID 的矩阵。我的实现如下:

% Get unique IDs
grain_id = unique(L);

% Get rid of artefacts
% Compute histogram for each ID
% and compare volume numv with thresholds

% Reject grains smaller or larger than threshold
reject = grain_id(or(numv<vmin,numv>vmax));

% Keep 0s (boundaries) and 1 (voids)
reject = reject(3:end);        

% Rejected become void
L(ismember(L,reject))=1;

% Get number of grains
grain_id = unique(L);
numgrains = numel(grain_id);

% Consecutive IDs
idx = false(size(L));
for i=1:numel(reject)
    idx = L>reject(numel(reject)+1-i);
    L = L-uint16(idx);
end

我有一个 1226x1226x3600 矩阵,所以性能非常重要。一个循环大约需要。 5 秒。这很可能不是实现目标的最有效方法,但目前我没有更好的想法。你呢?

如果我没有正确理解您的问题陈述,那么这正是 third output of the unique 函数的用途。它检查您的数据,对于每个元素,第三个输出提供一个映射,告诉您对应元素需要 unique 输出的哪个索引。巧合的是,这提供了一个新的整数映射,它从 1 到与输入中一样多的唯一标签是连续的。

但是,对于作为输入 unique 的向量以外的任何其他内容,这将作为列展开向量返回,因此您需要 reshape 将其返回到与输入相同的维度最后。

因此,您只需要:

[~,~,id] = unique(L);
id = reshape(id, size(L));

id 将是与您用作 L.

输入的 L 大小相同的矩阵

这是一个玩具示例,可确保我们在同一页面上:

>> rng(123); L = randi(50, 10, 10)

L =

    35    18    32     5    32     7    34     5    16    36
    15    37    43    22     6    42    30    45    35    50
    12    22    37    22    16    31    32    32    28    18
    28     3    31    25    21    28    34    37    20    39
    36    20    37    22    44    18    43     1    47    30
    22    37    17    16    13    16     5    30    43    35
    50    10    19    22    25    21    39    28    18     8
    35     9    12    45    50    35    13     8     3    20
    25    27    15    48    26    44    10     8    16    13
    20    27    32    26    31    26    29    35    20    18

这里我创建了一个 10 x 10 的不连续随机数矩阵。我们可以通过查看此矩阵中的所有唯一数字来了解这一点:

>> unique(L).'

ans =

  Columns 1 through 19

     1     3     5     6     7     8     9    10    12    13    15    16    17    18    19    20    21    22    25

  Columns 20 through 38

    26    27    28    29    30    31    32    34    35    36    37    39    42    43    44    45    47    48    50

注意从 1 到 3 的跳跃,例如从 13 到 15 的跳跃。通过执行我上面写的代码,我们现在得到:

>> id

id =

    28    14    26     3    26     5    27     3    12    29
    11    30    33    18     4    32    24    35    28    38
     9    18    30    18    12    25    26    26    22    14
    22     2    25    19    17    22    27    30    16    31
    29    16    30    18    34    14    33     1    36    24
    18    30    13    12    10    12     3    24    33    28
    38     8    15    18    19    17    31    22    14     6
    28     7     9    35    38    28    10     6     2    16
    19    21    11    37    20    34     8     6    12    10
    16    21    26    20    25    20    23    28    16    14

正如你在这里看到的,标签3变成了标签2,以确保标签是连续的。同样,标签 13 和 15 变为 10 和 11 以确保您要求的连续顺序等等。可以肯定的是,这是输出中所有唯一值的列表:

>> unique(id).'

ans =

  Columns 1 through 19

     1     2     3     4     5     6     7     8     9    10    11    12    13    14    15    16    17    18    19

  Columns 20 through 38

    20    21    22    23    24    25    26    27    28    29    30    31    32    33    34    35    36    37    38