在大型矩阵中获取后续 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
在做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