shijie xu
shijie xu

Reputation: 2097

Calculate the pixel distance to three defined pixel in matlab

I want to classify pixels of one tiff image according to pixel's RGB colour. The input is an image and three predefined colours for water(r0,g0,b0), forest(r1,g1,b1) and building(r2,g2,c2). The classification is based on the distance between image pixel and these three colors. If a pixel is closet to the water, the pixel is water and changed it the water RGB. The distance is calculated as (one sample) sqrt((x-r0)^2+(y-g0)^2+(z0-b0)^2)

The sample implementation is:

a=imread(..);
[row col dim] = size(a);   % dim =3 
for i=1:row
   for j=1:col
       dis1=sqrtCal(a(i,j,:)-water) 
       dis2=sqrtCal(a(i,j,:)-forest) 
       dis3=sqrtCal(a(i,j,:)-build)
       a(i,j,:) = water;
       if  dis2< dis1
           dis1 = dis2
           a(i,j,:) = forest
       end
       dis3=sqrt(a(i,j,:)-build)
       if dis3<dis1
          a(i,j,:) = build
       end
   end
end

This implementation should work. The problem is that the two for loops is not a good choice.

So is there any good alternatives in the Matlab? The D = pdist(X,distance) Seems not appliable for my case.

Upvotes: 2

Views: 166

Answers (3)

knedlsepp
knedlsepp

Reputation: 6084

If you have the statistics toolbox installed, you can use this version based on knnsearch, that scales well for a large number of colors.

result_index = knnsearch(ref_colors, reshape(im,[],3));
result = reshape(ref_colors(result_index,:), size(im));

Upvotes: 0

Luis Mendo
Luis Mendo

Reputation: 112659

I think this does what you want. The number of reference colors is arbitrary (3 in your example). Each reference color is defined as a row of the matrix ref_colors. Let MxN denote the number of pixels in the original image. Thus the original image is an MxNx3 array.

result_index is an MxN array which for each original pixel contains the index of the closest reference color.

result is a MxNx3 array in which each pixel has been assigned the RBG values of the closest reference color.

im = rand(10,12,3);          %// example image
ref_colors = [ .1 .1 .8; ... %// water
               .3 .9 .2; ... %// forest
               .6 .6 .6 ];   %// build: example reference colors
dist = sum(bsxfun(@minus, im, permute(ref_colors, [3 4 2 1])).^2, 3);
    %// 4D array containing the distance from each pixel to each reference color.
    %// Dimensions are: 1st: pixel row, 2nd: pixel col, 3rd: not used,
    %// 4th: index of reference color
[~, result_index] = min(dist, [], 4); %// compute arg min along 4th dimension
result = reshape(ref_colors(result_index,:), size(im,1), size(im,2), 3);

Upvotes: 2

Divakar
Divakar

Reputation: 221504

This one is another bsxfun based solution, but stays in 3D and could be more efficient -

%// Concatenate water, forest, build as a 2D array for easy processing
wfb = cat(2,water(:),forest(:),build(:))

%// Calculate square root of squared distances & indices corresponding to min vals
[~,idx] = min(sum(bsxfun(@minus,reshape(a,[],3),permute(wfb,[3 1 2])).^2,2),[],3)

%// Get the output with the minimum from the set of water, forest & build
a_out = reshape(wfb(:,idx).',size(a))

Upvotes: 1

Related Questions