简体   繁体   English

如何使用逻辑索引MATLAB获得3d矩阵中每个切片中某些区域的平均值

[英]How to get mean values of certain regions in each slice in 3d matrix using logical indexing MATLAB

In Matlab, 在Matlab中,

If I have a 3d matrix as following, I want to know the mean of the regions that have values greater than 5 in each slice. 如果我有一个3d矩阵如下,我想知道每个切片中值大于5的区域的平均值。 How can I use logical index to do this, with no loops please? 如何使用逻辑索引来执行此操作,请不要使用循环?

I would like to end up with an array of 3 by 1, with each element indicating the mean of the regions in their corresponding slice. 我想最终得到一个3乘1的数组,每个元素指示相应切片中区域的平均值。

m3d = randi(10,[3,3,3])

m3d(:,:,1) = m3d(:,:,1)=

 7     7     8
 1     9     8
 9     7     6

m3d(:,:,2) = m3d(:,:,2)=

10    10     5
 9     7     8
 5     3     3

m3d(:,:,3) = m3d(:,:,3)=

 9     7     5
 4     1     9
 5     9     1

Getting index 获得索引

3d_index = m3d > 5;

My final 我的决赛

result = mean(m3d(3d_index));

in which I dont want to have the mean of all regions 我不希望拥有所有地区的平均值

One approach - 一种方法 -

%// 3d mask of elements greater than 5
mask = m3d>5

%// Sum of all elements greater than 5 in each slice
sumvals = sum(reshape(m3d.*mask,[],size(m3d,3)))

%// Count of elements great than 5 in each slice
counts = sum(reshape(mask,[],size(m3d,3)))

%// Final output of mean values for the regions with >5 only
out = sumvals./counts

Benchmarking 标杆

Here's some runtime tests to see where all the posted approaches stand. 这是一些运行时测试,以查看所有已发布的方法的位置。 For the tests, we have taken a random 3D array of size 1500 x 1500 x 100 with values in the interval [1,255] . 对于测试,我们采用了大小为1500 x 1500 x 100的随机3D数组,其值为区间[1,255] The benchmarking code is listed next - 接下来列出基准代码 -

m3d = randi(255,1500,1500,100); %// Input 3D array

%// Warm up tic/toc.
for k = 1:50000
    tic(); elapsed = toc();
end

disp('------------------------ With SUMMING and COUNTING ')
tic
%// .... Proposed approach in this solution
toc, clear out counts sumvals mask

disp('------------------------ With FOR-LOOP ')
tic
N   = size(m3d, 3);
out = zeros(N, 1);
for k = 1:size(m3d,3)
        val    = m3d(:,:,k);
        lix    = val>5;
        out(k) = mean(val(lix));
end;
toc, clear out lix val k N

disp('----------------------- With ACCUMARRAY')
tic
ind = m3d>5;
result = accumarray(ceil(find(ind)/size(m3d,1)/size(m3d,2)), m3d(ind), [], @mean);
toc, clear ind result

disp('----------------------- With NANMEAN')
tic
m3d(m3d<5) = NaN; %// Please note: This is a bad practice to change input
out = nanmean(nanmean(m3d,1),2);
toc

Runtimes 运行时

------------------------ With SUMMING and COUNTING 
Elapsed time is 0.904139 seconds.
------------------------ With FOR-LOOP 
Elapsed time is 2.321151 seconds.
----------------------- With ACCUMARRAY
Elapsed time is 4.350005 seconds.
----------------------- With NANMEAN
Elapsed time is 1.827613 seconds.

You can use a mask array to do this as follows, 您可以使用掩码数组执行以下操作,

m3d = randi(10,[3,3,3]);

%Set values less than 5 to NaN
m3d(m3d<5) = NaN
nanmean(nanmean(m3d,1),2)

This can be done very easily with accumarray : 这可以通过accumarray非常容易地accumarray

ind = m3d>5;
result = accumarray(ceil(find(ind)/size(m3d,1)/size(m3d,2)), m3d(ind), [], @mean);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM