一:数学原理

K-Means算法的作者是MacQueen, 基本的数学原理很容易理解,假设有一个像素

数据集P。我们要根据值不同将它分为两个基本的数据集合Cluster1, Cluster2,使

用K-Means算法大致如下:

假设两个Cluster的RGB值分别为112,225,244和23,34,99则像素集合中的像素点

a(222,212,234), b(198,205,229), c(25,77,52),d(34,55,101)计算每个像素点与这

两个cluster中心点的欧几里德距离,则像素点a, b属于前面一个cluster, c,d属于

后面一个cluster。然后在根据(222+198)/2, (212+205)/2, (234+52)/2更新cluster

的RGB值,对后一个cluster做同样处理。然后再计算每个像素点到cluster中心点

的欧几里德距离。最终值没有变化则得到分类Cluster点集合。

二:算法基本流程

三:算法关键代码解析

初始化cluster中心点代码如下:

  1. Random random = new Random();
  2. for (int i = 0; i < numOfCluster; i++)
  3. {
  4. int randomNumber1 = random.nextInt(width);
  5. int randomNumber2 = random.nextInt(height);
  6. index = randomNumber2 * width + randomNumber1;
  7. ClusterCenter cc = new ClusterCenter(randomNumber1, randomNumber2, inPixels[index]);
  8. cc.setcIndex(i);
  9. clusterCenterList.add(cc);
  10. }

初始化所有像素点代码如下:

  1. // create all cluster point
  2. for (int row = 0; row < height; ++row)
  3. {
  4. for (int col = 0; col < width; ++col)
  5. {
  6. index = row * width + col;
  7. int color = inPixels[index];
  8. pointList.add(new ClusterPoint(row, col, color));
  9. }
  10. }

计算两个像素点之间欧几里德距离的代码如下:

  1. // int pa = (p.getPixelColor() >> 24) & 0xff;
  2. int pr = (p.getPixelColor() >> 16) & 0xff;
  3. int pg = (p.getPixelColor() >> 8) & 0xff;
  4. int pb = p.getPixelColor() & 0xff;
  5. // int ca = (c.getPixelColor() >> 24) & 0xff;
  6. int cr = (c.getPixelColor() >> 16) & 0xff;
  7. int cg = (c.getPixelColor() >> 8) & 0xff;
  8. int cb = c.getPixelColor() & 0xff;
  9. return Math.sqrt(Math.pow((pr - cr), 2.0) + Math.pow((pg - cg), 2.0) + Math.pow((pb - cb), 2.0));

; i<clusterCenterList.size(); i++)

  • {
  • clusterCenterList.get(i).setNumOfPoints(0);
  • }
  • // recalculate the sum and total of points for each cluster
  • double[] redSums = new double[3];
  • double[] greenSum = new double[3];
  • double[] blueSum = new double[3];
  • for(int i=0; i<pointList.size(); i++)
  • {
  • int cIndex = (int)pointList.get(i).getClusterIndex();
  • clusterCenterList.get(cIndex).addPoints();
  • int ta = (pointList.get(i).getPixelColor() >> 24) & 0xff;
  • int tr = (pointList.get(i).getPixelColor() >> 16) & 0xff;
  • int tg = (pointList.get(i).getPixelColor() >> 8) & 0xff;
  • int tb = pointList.get(i).getPixelColor() & 0xff;
  • ta = 255;
  • redSums[cIndex] += tr;
  • greenSum[cIndex] += tg;
  • blueSum[cIndex] += tb;
  • }
  • double[] oldClusterCentersColors = new double[clusterCenterList.size()];
  • for(int i=0; i<clusterCenterList.size(); i++)
  • {
  • double sum  = clusterCenterList.get(i).getNumOfPoints();
  • int cIndex = clusterCenterList.get(i).getcIndex();
  • int red = (int)(greenSum[cIndex]/sum);
  • int green = (int)(greenSum[cIndex]/sum);
  • int blue = (int)(blueSum[cIndex]/sum);
  • System.out.println("red = " + red + " green = " + green + " blue = " + blue);
  • int clusterColor = (255 << 24) | (red << 16) | (green << 8) | blue;
  • clusterCenterList.get(i).setPixelColor(clusterColor);
  • oldClusterCentersColors[i] = clusterColor;
  • }
  • return oldClusterCentersColors;
  • }