Matlab: How to vectorize a nested loop over a 2D s

2019-01-28 17:36发布

问题:

I have a function in the following form:

function Out = DecideIfAPixelIsWithinAnEllipsoidalClass(pixel,means,VarianceCovarianceMatrix)  
   ellipsoid = (pixel-means)'*(VarianceCovarianceMatrix^(-1))*(pixel-means);  
   if ellipsoid <= 1
      Out = 1;
   else
      Out = 0;
   end
end  

I am doing remote-sensing processes with matlab and I want to classify a LandSatTM images.This picture has 7 bands and is 2048*2048.So I stored them in 3 dimentinal 2048*2048*7 matrix.in this function means is a 7*1 matrix calculated earlier using the sample of the class in a function named ExtractStatisticalParameters and VarianceCovarianceMatrix is a 7*7 matrix in fact you see that:

ellipsoid = (pixel-means)'*(VarianceCovarianceMatrix^(-1))*(pixel-means);  

is the equation of an ellipsoid.My problem is that each time you can pass a single pixel(it is a 7*1 vector where each row is the value of the pixel in a seperated band) to this function so I need to write a loop like this:

for k1=1:2048  
   for k2=1:2048  
      pixel(:,1)=image(k1,k2,:); 
      Out = DecideIfAPixelIsWithinAnEllipsoidalClass(pixel,means,VarianceCovarianceMatrix);  
   end  
end  

and you know it will take alot of time and energy of the system.Can you suggest me a way to reduce the pressure applied on the systam?

回答1:

No need for loops!

pMinusMean = bsxfun( @minus, reshape( image, [], 7 ), means' ); %//' subtract means from all pixes
iCv = inv( arianceCovarianceMatrix );
ell = sum( (pMinusMean * iCv ) .* pminusMean, 2 ); % note the .* the second time!
Out = reshape( ell <= 1, size(image(:,:,1)) ); % out is 2048-by-2048 logical image

Update:

After a (somewhat heated) debate in the comments below I add a correction made by Rody Oldenhuis:

pMinusMean = bsxfun( @minus, reshape( image, [], 7 ), means' ); %//' subtract means from all pixes
ell = sum( (pMinusMean / varianceCovarianceMatrix ) .* pminusMean, 2 ); % note the .* the second time!
Out = reshape( ell <= 1, size(image(:,:,1)) );

The key issue in this change is that Matlab's inv() is poorly implemented and it is best to use mldivide and mrdivide (operators / and \) instead.