使用 K 均值聚类准确检测图像中的颜色区域 [英] Accurately detect color regions in an image using K-means clustering

查看:28
本文介绍了使用 K 均值聚类准确检测图像中的颜色区域的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在基于颜色的图像分割中使用 K 均值聚类.我有一个 2D 图像,它有 3 种颜色,黑色、白色和绿色.这是图片,

I'm using K-means clustering in color-based image segmentation. I have a 2D image which has 3 colors, black, white, and green. Here is the image,

我想让 K-means 产生 3 个簇,一个代表绿色区域,第二个代表白色区域,最后一个代表黑色区域.

I want K-means to produce 3 clusters, one represents the green color region, the second one represents the white region, and the last one represents the black region.

这是我使用的代码,

%Clustering color regions in an image. 

%Step 1: read the image using imread, and show it using imshow. 

img =  (imread('img.jpg'));

figure, imshow(img), title('X axis rock cut'); %figure is for creating a figure window.
text(size(img,2),size(img,1)+15,...
     'Unconventional shale x axis cut', ...
     'FontSize',7,'HorizontalAlignment','right');

 %Step 2: Convert Image from RGB Color Space to L*a*b* Color Space
 conversionform = makecform('srgb2lab'); %the form of the conversion is defined as from rgb to l a b
 lab_img = applycform(img,conversionform); %converting the rgb image to l a b image using the conversion form defined above.

 %Step 3: Classify the Colors in 'a*b*' Space Using K-Means Clustering
 ab = double(lab_img(:,:,2:3));
 nrows = size(ab,1);
 ncols = size(ab,2);
 ab = reshape(ab,nrows*ncols,2);

 nColors = 3;
% repeat the clustering 3 times to avoid local minima
[cluster_idx, cluster_center] = kmeans(ab,nColors,'distance','sqEuclidean', ...
                                      'Replicates',3);
%Step 4: Label Every Pixel in the Image Using the Results from KMEANS

%For every object in your input, kmeans returns an index corresponding to a cluster. The cluster_center output from kmeans will be used later in the example. Label every pixel in the image with its cluster_index.

pixel_labels = reshape(cluster_idx,nrows,ncols);
figure, imshow(pixel_labels,[]), title('image labeled by cluster index');

segmented_images = cell(1,3);
rgb_label = repmat(pixel_labels,[1 1 3]);

for k = 1:nColors
    color = img;
    color(rgb_label ~= k) = 0;
    segmented_images{k} = color;
end

figure, imshow(segmented_images{1}), title('objects in cluster 1');
figure, imshow(segmented_images{2}), title('objects in cluster 2');
figure, imshow(segmented_images{3}), title('objects in cluster 3');

但是我没有得到要求的结果.我得到一个带有绿色区域的集群,一个带有绿色区域边界的集群,以及一个带有灰色、黑色和白色的集群.这是生成的集群.

But I'm not getting the results as required. I get one cluster with green regions, one cluster with green region boundaries, and one with gray, black, and white colors. Here are the resulting clusters.

这样做的目的是在得到正确的聚类结果后,我想用连通分量的概念计算每个区域的像素数.

The aim of doing this is that after getting the correct clustering results, I want to count the number of pixels in every region using the concept of connected components.

所以,我的目标是知道每个颜色区域有多少像素.我尝试了另一种更简单的方法,即获取 2D 图像的矩阵并尝试找出每种颜色的像素数.但是,我在矩阵中发现了 3 种以上的 RGB 颜色,可能是因为相同颜色的像素具有略有不同的色阶.这就是我去图像分割的原因.

So, my aim is to know how many pixels there are in every color region. I tried another simpler way by getting the matrix of the 2D image and trying to figure out the number of pixels for every color. However, I found more than 3 RGB colors in the matrix, maybe because pixels of the same color have a slightly different color levels. That's why I went to image segmentation.

谁能告诉我如何修复上面的代码以获得所需的结果?

Can anyone please tell me how to fix the code above in order to get the required results?

如果您能以更简单的方式告诉我如何做到这一点,我也将不胜感激.

I would also appreciate it if you give me hints on how to do this in an easier way, if there is any.

这是我用来迭代图像中每个像素的代码.请注意,我使用了红色、黄色、蓝色和白色 4 种颜色,而不是绿色、白色和黑色,但想法是相同的.rgb2name 是返回给定 RGB 颜色的颜色名称的函数.

Here is a code I made to iterate over every pixel in the image. Please notice I use 4 colors red, yellow, blue, and white instead of green, white, and black, but the idea is the same. rgb2name is the function that returns the color name given RGB color.

im= imread ('img.jpg'); 

[a b c] = size (im); 
%disp ([a b]);
yellow=0; 
blue=0; 
white=0; 
red=0; 


for i=1:a
    for j=1:b
        x= impixel(im, i, j)/255 ;
        color= rgb2name (x);
        if (~isempty (strfind (color, 'yellow')))
            yellow= yellow+1; 
        elseif (~isempty (strfind(color, 'red')))
            red= red+1; 
        elseif (~isempty (strfind (color, 'blue')))
            blue= blue+1; 
        elseif (~isempty (strfind (color, 'white')))
           white= white+1; 
        else 
            %disp ('warning'); break; 
        end            
        disp (color);
        disp (i);
    end
end
disp (yellow)
disp (red)
disp (blue)
disp (white)

谢谢.

推荐答案

这是我计算每个区域像素数的方法.鉴于(如评论中所述):

This is my approach to count the number of pixels in every region. Given that (as discussed in the comments):

  • 颜色的值 (RGB) 和数量 (K) 是先验已知的
  • 压缩伪影和抗锯齿会生成额外的颜色,必须将其视为 K 种已知颜色中的最近邻.

因为您先验地知道颜色,所以您不需要 k 均值.正如您的问题,它实际上可能会导致不良结果.@crowdedComputeeer 的方法解决了这方面的问题.

Since you know a priori the colors, you don't need k-means. It could actually lead to bad results as in your question. The approach of @crowdedComputeeer take care of this aspect.

您可以直接在像素值上使用 pdist2 计算最近邻.无需使用查找颜色名称的非常​​缓慢的函数.

You can compute nearest neighbor with pdist2 directly on the pixel values. There's no need to use the really slow function that looks for the color name.

这是代码.您只需修改变量 colors 即可更改颜色的数量和值.这将计算每种颜色的像素数,并输出掩码.

Here is the code. You can change the number and values of colors simply modifying the variable colors. This will compute the number of pixels in each color, and output the masks.

img =  (imread('path_to_image'));

colors = [  0 0 0;    % black
            0 1 0;    % green
            1 1 1];   % white


% % You can change the colors        
% colors = [  0 0 1;    % red
%             1 1 0;    % yellow
%             1 0 0;    % blue
%             1 1 1];   % white


% Find nearest neighbour color
list = double(reshape(img, [], 3)) / 255;
[~, IDX] = pdist2(colors, list, 'euclidean', 'Smallest', 1);
% IDX contains the indices to the nearest element


N = zeros(size(colors, 1), 1);
for i = 1 : size(colors, 1)
    % Count the number of pixels for each color
    N(i) = sum( IDX == i );
end

% This will display the number of pixels for each color
disp(N);



% Eventually build the masks
indices = reshape(IDX, [size(img,1), size(img,2)]);

figure();
szc = size(colors,1);
for i = 1 : szc
    subplot(1,szc,i);
    imagesc(indices == i);
end

结果计数:

97554     % black
16894     % green
31852     % white

产生的掩码:

这篇关于使用 K 均值聚类准确检测图像中的颜色区域的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆