java代码 kmeans算法实现 图像分割

  数据挖掘作业是使用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;  
  }  
  
}

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值