您的位置:首页 > 编程语言 > Java开发

[置顶] java代码 kmeans算法实现 图像分割

2016-10-26 17:08 447 查看
  数据挖掘作业是使用kmeans进行图像分割,老师给的例子是matlab,在这里使用java进行实现。

      首先了解什么是kmeans,它是一种聚类算法,简单理解就是给你一堆数据,让你对他们进行分类,比如网上的例子有给你足球运动员得分等数据信息,让你判断他们在篮球场的位置(前锋、后卫等)。本次的任务是进行图像分割,由于数据是图像二维像素点,彩色图像每个像素点有rgb三个分量,灰度图像只有一个分量。因此每个数据维度是3.

    kmeans参考http://blog.csdn.net/hustlx/article/details/50849554

    算法:①首先从数据集里随机选取K个值作为初始中心;

          ②计算每个样本数据到这K个中心的欧式距离(有公式);

          ③将样本划分到距离最小的中心簇中;

          ④计算每个簇的均值,作为新的中心;

          ⑤重复②-④,直到上一次到本次簇中心差值很小时结束。
那么接下来就是按照上述算法进行实现啦

因为是编程小白,肯定有代码重复、变量名乱七八糟的缺点,希望大家能多多指导,不懂得相互交流~~~~

源代码:

import java.awt.List;

import java.util.ArrayList;

import java.util.Random;

/*

首先 就是KMeans算法类,在这里写成了通用类的形式

输入参数:k(最终聚类的数目),sourceData[][](输入的样本数据,其一维长度len_1代表样本数据的数量,二维长度len_2代表每个样本数据所包含的数据个数)

                    MAX_Its(迭代次数,迭代次数越多应该说明分类越精确吧?)。

输出参数:label[] ,其长度和sourceData相同,存储了每个样本数据的类标记,如label[2]=0,表示第三个样本数据被分配到第1类。

*/

public class KMeans {

  //由于这三个数据总是共用不变的因此在这里声明

  static int k=0;

  static int len_1=0;       //源数据数组的长度,即样本数目

  static int len_2=0;       //源数组二维长度,及每个样本包含数据的数目

  double[][] center=new double[k][len_2];//各簇初始中心

  public int[] KMeans(int k,double[][] sourceData,int MAX_Its){
 KMeans.k=k;
 KMeans.len_1= sourceData.length;        //源数据数组的长度  也就是多少个像素点
 KMeans.len_2=sourceData[0].length;     //每个数据的维度   三个像素值  3 

          int[] label=new int[len_1];                          //最终输出,存储了每个样本数据的类标记

 center=initcenter(k,sourceData); 
 for(int i=0;i<MAX_Its;i++){
 System.out.println("第   "+i+"  次分类");
 label=classify(sourceData,center,k);         //分类
 center=changecenter(sourceData,label,center,k); //改变中心值
 }
 for(int i =0;i<label.length;i++)
     System.out.println(i+"  被分到第"+label[i]+"类");
 return label;

  }

  //初始化中心值

  static public double[][] initcenter(int k,double[][] sourceData){
 int[] eachlabel_num=new int[k];
 double[][] center=new double[k][];//各簇初始中心
 Random random=new Random(System.currentTimeMillis());//生成随机数
 //初始化中心值

      for(int i=0;i<k;i++){

    int ran= random.nextInt(len_1);

    System.out.println(i+"  random is :  "+ran);

    center[i]=sourceData[ran];

      }

      int[] label=classify(sourceData,center,k);

      for (int i=0;i<len_1;i++){
 for(int j=0;j<k;j++){
if(label[i]==j){
eachlabel_num[j]++;
} else continue;
 }
 }

      int repeat=0;

      for(int j=0;j<k;j++){

     System.out.println("label "+j+"  num is  "+eachlabel_num[j]);

     if(eachlabel_num[j]==0){

     initcenter(k,sourceData);

     repeat++;

     System.out.println("初始化中心第      "+repeat+"  次");

     break;

     }else continue;

      }

      return center;

  }

  //把每个数据样本分配到距离最小的中心簇

  static public int[] classify(double[][] sourceData,double[][] center,int k){
 
 int[] label=new int[len_1];
 for(int i=0;i<len_1;i++){
 double neardist=Double.MAX_VALUE;//定义最小欧式距离,最初赋予最大值
 for(int j=0;j<k;j++){
 double dist=calEuraDist(sourceData[i], center[j],len_2); //计算欧式距离
 if(dist<neardist){
 neardist=dist;
 label[i]=j;// 记录每个元素所在分组  
 }
 }  
 }
 return label;

  }

//重新计算簇中心

  static public double[][] changecenter(double[][] sourceData,int[] label,double[][] center,int k){  
 int[] eachlabel_num=new int[k];
 for (int i=0;i<len_1;i++){
 for(int j=0;j<k;j++){
if(label[i]==j){
eachlabel_num[j]++;
} else continue;
 }
 }
 int[][] sum=new int[k][len_2];

      for(int i=0;i<label.length;i++){

     for(int j=0;j<len_2;j++){

     sum[label[i]][j]+=sourceData[i][j];

     }

      }
 for(int i=0;i<k;i++){
for(int j=0;j<len_2;j++){
center[i][j]=sum[i][j]/eachlabel_num[i];
}
 }
 return center;

  }

  //计算欧式距离

  static public double calEuraDist(double[] vector,double[] center,int len){  

      double sum=0;  

      for(int i=0;i<len;i++){  

          sum+=Math.pow(vector[i]-center[i],2);  

      }  

      sum=Math.sqrt(sum);   

      return sum;  

  }  

  

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: