用于图像压缩的 K 均值仅给出黑白结果

K-means for image compression only gives black-and-white result

我正在做这个由 Andrew NG 做的关于使用 k-means 减少图像中颜色数量的练习。但问题是我的代码只给出了黑白图像:(。我已经检查了算法中的每一步,但它仍然不会给出正确的结果。请帮助我,非常感谢

这里是link of the exercise, and here is the dataset。 正确的结果在练习的 link 中给出。这是我的黑白图像:

这是我的代码:

function [] = KMeans()

    Image = double(imread('bird_small.tiff'));
    [rows,cols, RGB] = size(Image);
    Points = reshape(Image,rows * cols, RGB);
    K = 16;
    Centroids = zeros(K,RGB);    
    s = RandStream('mt19937ar','Seed',0);
    % Initialization :
    % Pick out K random colours and make sure they are all different
    % from each other! This prevents the situation where two of the means
    % are assigned to the exact same colour, therefore we don't have to 
    % worry about division by zero in the E-step 
    % However, if K = 16 for example, and there are only 15 colours in the
    % image, then this while loop will never exit!!! This needs to be
    % addressed in the future :( 
    % TODO : Vectorize this part!
    done = false;
    while done == false
        RowIndex = randperm(s,rows);
        ColIndex = randperm(s,cols);
        RowIndex = RowIndex(1:K);
        ColIndex = ColIndex(1:K);
        for i = 1 : K
            for j = 1 : RGB
                Centroids(i,j) = Image(RowIndex(i),ColIndex(i),j);
            end
        end
        Centroids = sort(Centroids,2);
        Centroids = unique(Centroids,'rows'); 
        if size(Centroids,1) == K
            done = true;
        end
    end;
%     imshow(imread('bird_small.tiff'))
%    
%     for i = 1 : K
%         hold on;
%         plot(RowIndex(i),ColIndex(i),'r+','MarkerSize',50)
%     end



    eps = 0.01; % Epsilon
    IterNum = 0;
    while 1
        % E-step: Estimate membership given parameters 
        % Membership: The centroid that each colour is assigned to
        % Parameters: Location of centroids
        Dist = pdist2(Points,Centroids,'euclidean');

        [~, WhichCentroid] = min(Dist,[],2);

        % M-step: Estimate parameters given membership
        % Membership: The centroid that each colour is assigned to
        % Parameters: Location of centroids
        % TODO: Vectorize this part!
        OldCentroids = Centroids;
        for i = 1 : K
            PointsInCentroid = Points((find(WhichCentroid == i))',:);
            NumOfPoints = size(PointsInCentroid,1);
            % Note that NumOfPoints is never equal to 0, as a result of
            % the initialization. Or .... ???????
            if NumOfPoints ~= 0 
                Centroids(i,:) = sum(PointsInCentroid , 1) / NumOfPoints ;
            end
        end    

        % Check for convergence: Here we use the L2 distance
        IterNum = IterNum + 1;
        Margins = sqrt(sum((Centroids - OldCentroids).^2, 2));
        if sum(Margins > eps) == 0
            break;
        end

    end
    IterNum;
    Centroids ;


    % Load the larger image
    [LargerImage,ColorMap] = imread('bird_large.tiff');
    LargerImage = double(LargerImage);
    [largeRows,largeCols,~] = size(LargerImage);  % RGB is always 3 
    % Dist = zeros(size(Centroids,1),RGB);
    % TODO: Vectorize this part!

    % Replace each of the pixel with the nearest centroid    
    for i = 1 : largeRows 
        for j = 1 : largeCols
            Dist = pdist2(Centroids,reshape(LargerImage(i,j,:),1,RGB),'euclidean');
            [~,WhichCentroid] = min(Dist);            
            LargerImage(i,j,:) = Centroids(WhichCentroid);

        end
    end

    % Display new image
    imshow(uint8(round(LargerImage)),ColorMap)
    imwrite(uint8(round(LargerImage)), 'D:\Hoctap\bird_kmeans.tiff');

您正在使用单个线性索引对 Centroids 进行索引。

Centroids(WhichCentroid)

这将 return 一个 单个 值(特别是那个质心的红色值)。当您将其分配给 LargerImage(i,j,:) 时,它将为所有 RGB 通道分配相同的值,从而生成灰度图像。

您可能想要获取所选质心的 所有列 以提供要分配给 LargerImage(i,j,:) 的红色、绿色和蓝色值数组。您可以使用冒号 : 来指定属于 WhichCentroid.

指示的行的 Centroids 的所有列
LargerImage(i,j,:) = Centroids(WhichCentroid,:);