Slow Find Loop no vectorisation

1 vue (au cours des 30 derniers jours)
Craig Russell
Craig Russell le 20 Avr 2016
Commenté : Andrei Bobrov le 20 Avr 2016
Hi,
I have a 3d image where each colour is a unique labelled cell. I'm trying to find the centre of mass of each of these individual colours.
for colour = 1:2^16
disp(100*colour/(2^16));
coords = find(image == colour);
[y_pos,x_pos,z_pos] = ind2sub(size(image),coords);
data(colour,:) = mean([x_pos,y_pos,z_pos]);
end
This loop does the job but it is incredible slow across all 2^16 colours. Is there a way of vectorising this problem?
Thanks,
Craig

Réponse acceptée

Andrei Bobrov
Andrei Bobrov le 20 Avr 2016
Please try it:
co = (1:2^16)';
[l0,i0] = ismember(image1(:),co);
s = size(image1);
[ii jj k] = ndgrid(1:s(1),1:s(2),1:s(3));
coor = [ii(:),jj(:),k(:)];
i1 = (1:numel(image1))';
v = accumarray(i0(l0),i1(l0),[numel(co) 1],@(x){mean(coor(x,:),1)});
out = [co(~cellfun(@isempty,v)), cell2mat(v)];
  1 commentaire
Craig Russell
Craig Russell le 20 Avr 2016
This works! I don't understand how, but it works.

Connectez-vous pour commenter.

Plus de réponses (2)

Teja Muppirala
Teja Muppirala le 20 Avr 2016
FOR loops are not necessarily slow. This is in R2016a.
%%Make some data...
rng(0);
image = randi(2^16,[30 40 50]);
%% 1. Original method takes 7 seconds. (By the way, it should be MEAN([...],1) not just MEAN([...])
tic
numColors = 2^16;
data = zeros(numColors,3);
for colour = 1:numColors
%disp(100*colour/(2^16));
coords = find(image == colour);
[y_pos,x_pos,z_pos] = ind2sub(size(image),coords);
data(colour,:) = mean([x_pos,y_pos,z_pos],1);
end
toc
% Elapsed time is 7.447380 seconds
%% Using a for loop more efficiently takes less than 0.1 seconds.
tic
data2 = zeros(numColors,4);
for n1 = 1:size(image,1)
for n2 = 1:size(image,2)
for n3 = 1:size(image,3)
data2(image(n1,n2,n3),:) = data2(image(n1,n2,n3),:) + [1 n2 n1 n3];
end
end
end
data2 = bsxfun(@rdivide,data2(:,2:4),data2(:,1));
toc
% Elapsed time is 0.091517 seconds
%% Show they are the same.
isequaln(data,data2)
% ans =
%
% 1

Guillaume
Guillaume le 20 Avr 2016
Modifié(e) : Guillaume le 20 Avr 2016
I don't think you can get rid of the colour loop, but you can speed up the loop code with:
[y_pos, x_pos, z_pos] = ndgrid(1:size(image, 2), 1:size(image, 1), 1:size(image, 3));
for colour = 1 : pow2(16)
iscolour = image == colour; %use logical instead of find
data(colour, :) = mean([x_pos(iscolour), y_pos(iscolour), z_pos(iscolour)]);
end
edit: I've just thought that you can replace the loop with accumarray and I see that Andrei answered with that in the meantime.
edit-edit: Here is a (more readable?) alternative to andrei's answer:
[y_pos, x_pos, z_pos] = ndgrid(1:size(image, 2), 1:size(image, 1), 1:size(image, 3));
datarows = [pow2(16), 1];
data = [accumarray(image(:), x_pos(:), datarows, @mean), ...
accumarray(image(:), y_pos(:), datarows, @mean), ...
accumarray(image(:), z_pos(:), datarows, @mean)];

Catégories

En savoir plus sur Logical dans Help Center et File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by