dtr43
dtr43

Reputation: 155

Mean color for each superpixel in an image in the CIELAB color space

According to the MATLAB's help for measuring mean color for each superpixel, I segment an image to 200 superpixels and I tried to set the color of each pixel in the output image to the mean CIELAB color of the superpixel region. The input image is shown below:

The input image

B=imread('H.jpg');
A=rgb2lab(B);    // conversion from rgb to lab

output of command of imshow(A,[])

[L,N] = superpixels(A,200);
figure
BW = boundarymask(L);
imshow(imoverlay(A,BW,'cyan'),'InitialMagnification',67);


outputImage = zeros(size(A),'like',A);
idx = label2idx(L);
numRows = size(A,1);
numCols = size(A,2);
for labelVal = 1:N
  redIdx = idx{labelVal};
  greenIdx = idx{labelVal}+numRows*numCols;
  blueIdx = idx{labelVal}+2*numRows*numCols;
  outputImage(redIdx) = mean(A(redIdx));
  outputImage(greenIdx) = mean(A(greenIdx));
  outputImage(blueIdx) = mean(A(blueIdx));
end    
figure
imshow(outputImage,'InitialMagnification',67);

segmented image in the CIELAB color space

mean color of each superpixel in the CIELAB color space

I am not sure that output of this code gives me the correct mean color of each superpixel in the CIELAB color space correctly. Does the image have such a different color compared to the RGB color space or is the code incorrect? In the measurement of mean color of channels of CIELAB color space, is there any problem in the code?

Upvotes: 1

Views: 1071

Answers (2)

Alex Taylor
Alex Taylor

Reputation: 1412

Note that though the superpixels algorithm, SLIC, operates in L*a*b* space, it expects an RGB image as input. If you want the pre-compute the L*a*b* representation for downstream use like in your use case, you need to use the 'IsInputLab' Name/Value. Otherwise, the algorithm is going to attempt to convert an already L*a*b* image to L*a*b*.

You want:

B=imread('H.jpg');
A=rgb2lab(B);  
[L,N] = superpixels(A, 200,'IsInputLab',true);

Chris Lueno has aleady answered the mean computation of features in the superpixel graph. Distance between superpixels is similar, where you essentially compute centroid features for each superpixel to describe their position and then measure the distance between them. Note that in the code below, the matrix is symmetric about its diagonal and 0 on the diagonal. I'll leave it to you to make this more efficient if you care about that.

distanceMatrix = zeros(N,N);
for m = 1:N
    for n = 1:n
        [i1,j1] = ind2sub(size(A),idx{m});
        [i1,j2] = ind2sub(size(A),idx{n});
        Icenter1 = mean(i1);
        Jcenter1 = mean(j1);
        Icenter2 = mean(i2);
        Jcenter2 = mean(j2);
        distanceMatrix(m,n) = sqrt((Icenter1-Icenter2)^2+(Jcenter1-Jcenter2)^2);
    end 
end

Upvotes: 3

Cris Luengo
Cris Luengo

Reputation: 60680

The main issue here is that what imshow shows you is not what the data contains.

imshow assumes, for double inputs, that the pixel values are in the range [0,1]. Lab has a range of [0,100] in the first channel, and I believe it is [-20,20] in the other two channels (maybe it’s different, but these two channels are symmetric around 0, which is gray).

If you do imshow(A,[]) then the data will be scaled to show you everything. Thus will scale all the channels the same, so it’s not the best way to look at your data either, but in any case the L channel will be shown in red, and the a and b channels in green and blue. Don’t expect this to look like your original image at all, even though you still have all the data to recover your original image.

Next, superpixels expects an RGB image as input, consider passing the original image B, rather than the Lab image A. This will not preclude you from computing means of the Lab channels within superpixels found. (it turns out there is an option to use an Lab input image).

If you want to measure the mean Lab values within each superpixel and use that in further processing, don't create the outputImage, but rather a table with these values:

data = zeros(N,3);
for labelVal = 1:N
  redIdx = idx{labelVal};
  greenIdx = idx{labelVal}+numRows*numCols;
  blueIdx = idx{labelVal}+2*numRows*numCols;
  data(labelVal,1) = mean(A(redIdx));
  data(labelVal,2) = mean(A(greenIdx));
  data(labelVal,3) = mean(A(blueIdx));
end    

Now, data(ii,:) is the Lab values for superpixel number ii. L==ii are the pixels that belong to this superpixel.

Upvotes: 4

Related Questions