Main Content

L*a*b* 컬러스페이스를 사용한 색 기반 분할

이 예제에서는 L*a*b* 컬러스페이스를 분석하여 직물에서 서로 다른 색을 식별하는 방법을 보여줍니다.

1단계: 영상 수집하기

형형색색의 직물을 촬영한 영상인 fabric.png를 읽어 들입니다.

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

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

2단계: 각 영역의 샘플 색을 L*a*b* 컬러스페이스로 계산하기

영상에서 6가지 주요 색 즉, 배경색, 빨간색, 녹색, 자주색, 노란색, 자홍색을 볼 수 있습니다. 이러한 색을 눈으로 얼마나 쉽게 구별할 수 있는지 보십시오. L*a*b* 컬러스페이스(CIELAB 또는 CIE L*a*b*라고도 함)를 사용하면 이러한 시각적 차이를 수량화할 수 있습니다.

L*a*b* 컬러스페이스는 CIE XYZ 3자극값에서 파생됩니다. L*a*b* 컬러스페이스는 광도층 'L*'(밝기층에 해당함)과 색도층 'a*'(빨간색-녹색 축에 놓인 색의 위치를 나타냄)와 색도층 'b*'(파란색-노란색 축에 놓인 색의 위치를 나타냄)로 구성됩니다.

각 색에 대해 작은 샘플 영역을 선택하고 각 샘플 영역의 평균 색을 'a*b*' 컬러스페이스로 계산하는 접근 방식을 사용합니다. 이러한 색 마커는 각 픽셀을 분류하는 데 사용됩니다.

이 예제에서는 간단히 MAT 파일에 저장된 영역 좌표를 불러옵니다.

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 axes object with title Sample Region for Red contains an object of type image.

rgb2lab 함수를 사용하여 직물 RGB 영상을 L*a*b* 영상으로 변환합니다.

lab_fabric = rgb2lab(fabric);

roipoly를 사용하여 추출한 각 영역의 평균 'a*' 및 'b*' 값을 계산합니다. 이러한 값은 'a*b*' 컬러스페이스에서 색 마커로 사용됩니다.

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

예를 들어, a*b* 컬러스페이스에서 빨간색 샘플 영역의 평균 색은 다음과 같습니다.

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

3단계: 최근접이웃 규칙을 사용하여 각 픽셀 분류하기

이제 각 색 마커는 a* 값과 b* 값을 갖습니다. 해당 픽셀과 각 색 마커 사이의 유클리드 거리를 계산하여 lab_fabric 영상의 각 픽셀을 분류할 수 있습니다. 거리가 가장 작다는 것은 픽셀이 해당 색 마커와 거의 일치한다는 것을 의미합니다. 예를 들어, 픽셀과 빨간색 마커 간의 거리가 가장 작은 경우 이 픽셀은 빨간색 픽셀로 레이블이 지정됩니다.

다음의 색 레이블을 포함하는 배열을 만듭니다. 0 = 배경색, 1 = 빨간색, 2 = 녹색, 3 = 자주색, 4 = 자홍색, 5 = 노란색.

color_labels = 0:nColors-1;

최근접이웃 분류에 사용하기 위해 행렬을 초기화합니다.

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

분류를 수행합니다.

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;

4단계: 최근접이웃 분류에 대한 결과 표시하기

레이블 행렬에는 직물 영상의 각 픽셀에 대한 색 레이블이 포함되어 있습니다. 레이블 행렬을 사용하여 원래 직물 영상에 있는 객체를 색상별로 분리합니다.

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 

5개의 분할된 색을 몽타주 형태로 표시합니다. 영상에서 색으로 분류되지 않은 배경 픽셀도 표시합니다.

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 axes object with title Montage of Red, Green, Purple, Magenta, and Yellow Objects, and Background contains an object of type image.

5단계: 레이블이 지정된 색의 a* 값과 b* 값 표시하기

별도의 색으로 분류된 픽셀의 a* 값과 b* 값을 플로팅해 최근접이웃 분류가 서로 다른 색 모집단을 얼마나 잘 분리했는지 알 수 있습니다. 표시 목적으로 각 점의 색 레이블을 사용하여 해당 점에 레이블을 지정합니다. 자주색은 명명된 색 값이 아니므로 16진수 색 코드 값의 string형을 사용하여 자주색을 지정합니다.

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