Main Content

Color-Based Segmentation Using the L*a*b* Color Space

This example shows how to identify different colors in fabric by analyzing the L*a*b* colorspace.

Step 1: Acquire Image

Read in the fabric.png image, which is an image of colorful fabric.

fabric = imread("fabric.png");
imshow(fabric)
title("Fabric")

Figure contains an axes object. The hidden axes object with title Fabric contains an object of type image.

Step 2: Calculate Sample Colors in L*a*b* Color Space for Each Region

You can see six major colors in the image: the background color, red, green, purple, yellow, and magenta. Notice how easily you can visually distinguish these colors from one another. The L*a*b* colorspace (also known as CIELAB or CIE L*a*b*) enables you to quantify these visual differences.

The L*a*b* color space is derived from the CIE XYZ tristimulus values. The L*a*b* space consists of a luminosity (L*) channel indicating the brightness, a chromaticity channel (a*) indicating where color falls along the red-green axis, and a chromaticity channel (b*) indicating where the color falls along the blue-yellow axis.

Your approach is to choose a small sample region for each color and to calculate each sample region's average color in a*b* space. You will use these color markers to classify each pixel.

To simplify this example, load the region coordinates that are stored in a MAT file.

load regioncoordinates;

nColors = 6;
sample_regions = false([size(fabric,1) size(fabric,2) nColors]);

for count = 1:nColors
  sample_regions(:,:,count) = roipoly(fabric,region_coordinates(:,1,count), ...
      region_coordinates(:,2,count));
end

imshow(sample_regions(:,:,2))
title("Sample Region for Red")

Figure contains an axes object. The hidden axes object with title Sample Region for Red contains an object of type image.

Convert your fabric RGB image into an L*a*b* image using the rgb2lab function.

lab_fabric = rgb2lab(fabric);

Calculate the mean 'a*' and 'b*' value for each area that you extracted with roipoly. These values serve as your color markers in 'a*b*' space.

a = lab_fabric(:,:,2);
b = lab_fabric(:,:,3);
color_markers = zeros([nColors, 2]);

for count = 1:nColors
  color_markers(count,1) = mean2(a(sample_regions(:,:,count)));
  color_markers(count,2) = mean2(b(sample_regions(:,:,count)));
end

For example, the average color of the red sample region in a*b* space is

disp([color_markers(2,1), color_markers(2,2)]);
   69.8278   20.1056

Step 3: Classify Each Pixel Using the Nearest Neighbor Rule

Each color marker now has an a* and a b* value. You can classify each pixel in the lab_fabric image by calculating the Euclidean distance between that pixel and each color marker. The smallest distance will tell you that the pixel most closely matches that color marker. For example, if the distance between a pixel and the red color marker is the smallest, then the pixel would be labeled as a red pixel.

Create an array that contains your color labels: 0 = background, 1 = red, 2 = green, 3 = purple, 4 = magenta, and 5 = yellow.

color_labels = 0:nColors-1;

Initialize matrices to be used in the nearest neighbor classification.

a = double(a);
b = double(b);
distance = zeros([size(a), nColors]);

Perform classification

for count = 1:nColors
  distance(:,:,count) = ( (a - color_markers(count,1)).^2 + ...
      (b - color_markers(count,2)).^2 ).^0.5;
end

[~,label] = min(distance,[],3);
label = color_labels(label);
clear distance;

Step 4: Display Results of Nearest Neighbor Classification

The label matrix contains a color label for each pixel in the fabric image. Use the label matrix to separate objects in the original fabric image by color.

rgb_label = repmat(label,[1 1 3]);
segmented_images = zeros([size(fabric), nColors],"uint8");

for count = 1:nColors
  color = fabric;
  color(rgb_label ~= color_labels(count)) = 0;
  segmented_images(:,:,:,count) = color;
end 

Display the five segmented colors as a montage. Also display the background pixels in the image that are not classified as a color.

montage({segmented_images(:,:,:,2),segmented_images(:,:,:,3) ...
    segmented_images(:,:,:,4),segmented_images(:,:,:,5) ...
    segmented_images(:,:,:,6),segmented_images(:,:,:,1)});
title("Montage of Red, Green, Purple, Magenta, and Yellow Objects, and Background")

Figure contains an axes object. The hidden axes object with title Montage of Red, Green, Purple, Magenta, and Yellow Objects, and Background contains an object of type image.

Step 5: Display a* and b* Values of Labeled Colors

You can see how well the nearest neighbor classification separated the different color populations by plotting the a* and b* values of pixels that were classified into separate colors. For display purposes, label each point with its color label. Purple is not a named color value, so specify the color purple using a string with a hexadecimal color code.

purple = "#774998";
plot_labels = ["k", "r", "g", purple, "m", "y"];

figure
for count = 1:nColors
    plot_label = plot_labels(count);
    plot(a(label==count-1),b(label==count-1),".", ...
       MarkerEdgeColor=plot_label,MarkerFaceColor=plot_label);
  hold on
end
  
title("Scatterplot of Segmented Pixels in a*b* Space")
xlabel("a* Values")
ylabel("b* Values")

Figure contains an axes object. The axes object with title Scatterplot of Segmented Pixels in a*b* Space, xlabel a* Values, ylabel b* Values contains 6 objects of type line. One or more of the lines displays its values using only markers