基于KMeans的图像分割

Posted by 周宝航 on April 18, 2018

图像分割

基友上的人工智能课上,老师留了基于聚类算法的图像分割作业。正好图像处理课的老师也在讲这部分,所以自己拿来尝试一哈。

问题描述:针对下面这副图片,将其分为两部分:山与河流。

Alt text

Kmeans

事先确定常数k,常数k意味着最终的聚类类别数。将事先输入的n个数据对象划分为k个聚类以便使得所获得的聚类满足:同一聚类中的对象相似度较高;而不同聚类中的对象相似度较小。聚类相似度是利用各聚类中对象的均值所获得一个“中心对象”(引力中心)来进行计算的。

算法描述

假设要把样本集分为c个类别,算法描述如下:

(1)适当选择c个类的初始中心;

(2)在第k次迭代中,对任意一个样本,求其到c个中心的距离,将该样本归到距离最短的中心所在的类;

(3)利用均值等方法更新该类的中心值;

(4)对于所有的c个聚类中心,如果利用(2)(3)的迭代法更新后,值保持不变,则迭代结束,否则继续迭代。

该算法的最大优势在于简洁和快速。算法的关键在于初始中心的选择和距离公式。

自己动手实现KMeans

function [ans] = KMeans(k, data)
    ans = zeros(size(data,1),1);
    initialPoint = randint(k,1,size(data,1));
    centerData = []
    for i=1:k
       centerData = [centerData;data(initialPoint(i,1),:)];
    end
    while 1
        t1 = zeros(size(data,1),1);
        t2 = zeros(k,1);
        t3 = zeros(k,2);
        for i=1:size(t1,1)
            for j=1:k
                t2(j,1) = CalDistance(data(i,1),centerData(j));
            end
            [val index] = min(t2);
            t1(i,1) = index;
            t3(index,1) = t3(index,1) + val;
            t3(index,2) = t3(index,2) + 1;
        end
        for i=1:k
           t3(i,1) = t3(i,1) / t3(i,2);
        end
        centerData = t3(:,1);
        ans = t1;
        if isequal(t1,ans)
            break
        end
    end
end

实验结果 Alt text

讨论

实验过程中确实发现了一些问题。比如:有时处理的过程很快,可是右下角的森林部分与河流混在了一起;而有时,分割的效果就很好,较好地区分出山体与河流。上网翻了一些博客、论文,找到了KMeans算法的一些优缺点分析。

缺点:

(1)K值需要初始化,不同的K值得到的处理结果不一样;

(2)对于初始中心点是敏感的,这也就解释了我们处理结果的不唯一性。

(3)特殊值对处理结果有很大的影响

针对上述问题,还有更好的Kmeans ++算法,有时间研究一哈。还有,老师今天讲到了Mean Shift算法,能够自动确定聚类中心点,处理效果很不错。之后有机会尝试一哈。