基于KMeans(K均值)的图像分割matlab程序

KMeans图像分割算法是一种典型的分割算法。其主要思想就是首先随机(起始值其实很重要)选取K个特征值作为聚类中心,然后对于每个像素点计算其到各聚类中心的距离,将其划归到距离最近的类中(也可以进行软分类,即给出其属于各类的概率),然后计算各类中元素的(加权)均值作为新的聚类中心。重复上述操作直到收敛或者达到设定迭代次数。下面给出本人编写的一个matlab示例程序及处理结果。

代码:

function [sg,normMuDiff]=KMeansSeg(img,k,Mu,eps)
normMuDiff=[];
m=size(img,1);
n=size(img,2);
img=double(img);
M=reshape(img,m*n,size(img,3));
% index=randperm(m*n);
% Mu=M(index(1:k),:);
flag=1;
Cov=repmat(eye(size(img,3)),1,1,k); %k个聚类的协方差
Label=zeros(m*n,1);

iter=1;
figure;
while flag
    old_Mu=Mu;
    Num=zeros(1,k);
    ClassedPixs=zeros(m*n,size(img,3),k); %分到k个类中的像素值
    w=zeros(m*n,k); %各像素点对于聚类的权重矩阵
    C=zeros(size(img,3),size(img,3),k);
    for j=1:k
        invCov=inv(Cov(:,:,j));
        C(:,:,j)=invCov/norm(invCov);%使用Mahalanobis距离(即马氏距离)度量
    end
    for i=1:m*n
        dis=zeros(k,1);
        for j=1:k
            dis(j)=(M(i,:)-Mu(j,:))*C(:,:,j)*(M(i,:)-Mu(j,:))'; 
        end
        maxIdx=find(dis==min(dis));
        label=maxIdx(1);
        Label(i)=label;
        Num(label)=Num(label)+1;
        ClassedPixs(Num(label),:,label)=M(i,:);
        w(Num(label),label)=1/(sqrt(min(dis))+1); %避免被0除的情况
    end
    w=w./repmat(sum(w),m*n,1); %权重归一化
    % 更新协方差Cov
    for j=1:k
        PixsThisClass=ClassedPixs(1:Num(j),:,j);
        if Num(j)~=0      
            Cov(:,:,j)=cov(PixsThisClass)+0.01*rand(size(img,3)); %加随机量以防止矩阵奇异
            Mu(j,:)=sum(repmat(w(1:Num(j),j),1,size(img,3)).*PixsThisClass);
        end
    end
    normDiff=norm(old_Mu-Mu);
    if  normDiff

脚本:

clear all;close all;clc;
img=imread('onion.png');
% 初始值是在图中黄、绿、红、白、紫部分随机取一点得到的RGB值
Mu=[255 220 50;...
    115 124 31;...
    216 50 39;...
    247 215 185;...
    75 45 75];
[sg,normMuDiff]=KMeansSeg(img,5,Mu,10^-2);
figure,imshow(mat2gray(sg));
figure,plot(1:length(normMuDiff),normMuDiff,'g-');

原图:

基于KMeans(K均值)的图像分割matlab程序_第1张图片 标题

运行结果:

基于KMeans(K均值)的图像分割matlab程序_第2张图片

基于KMeans(K均值)的图像分割matlab程序_第3张图片

可以看出,误差值随迭代总体呈下降趋势,但也可能出现回弹,所以推荐使用固定迭代次数以结束循环。

你可能感兴趣的:(信号与图像处理)