图像处理之K-Means算法演示

简介: 图像处理之K-Means算法演示

一:数学原理


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点集合。


二:算法基本流程

1366451358_1138.png




三:算法关键代码解析


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

Random random = new Random();
for (int i = 0; i < numOfCluster; i++)
{
    int randomNumber1 = random.nextInt(width);
    int randomNumber2 = random.nextInt(height);
    index = randomNumber2 * width + randomNumber1;
    ClusterCenter cc = new ClusterCenter(randomNumber1, randomNumber2, inPixels[index]);
    cc.setcIndex(i);
    clusterCenterList.add(cc); 
}

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

// create all cluster point
for (int row = 0; row < height; ++row)
{
    for (int col = 0; col < width; ++col)
    {
      index = row * width + col;
      int color = inPixels[index];
      pointList.add(new ClusterPoint(row, col, color));
 
    }
}

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

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

重新计算Cluster中心点RGB值的代码如下:

private double[] reCalculateClusterCenters() {
  
  // clear the points now
  for(int i=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;
}

四:运行效果

1366451587_7079.png
五:K-Means算法源代码

package com.gloomyfish.segmentation.kmeans;
 
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
 
import com.gloomyfish.filter.study.AbstractBufferedImageOp;
import com.gloomyfish.segmentation.fuzzycmeans.ClusterPoint;
 
public class KMeansProcessor extends AbstractBufferedImageOp {
  private List<ClusterCenter> clusterCenterList;
  private List<ClusterPoint> pointList;
  
  private int numOfCluster;
  
  public KMeansProcessor(int clusters)
  {
    this.numOfCluster = clusters;
    pointList = new ArrayList<ClusterPoint>();
    this.clusterCenterList = new ArrayList<ClusterCenter>();
  }
 
  @Override
  public BufferedImage filter(BufferedImage src, BufferedImage dest) {
    // initialization the pixel data
        int width = src.getWidth();
        int height = src.getHeight();
        int[] inPixels = new int[width*height];
        src.getRGB( 0, 0, width, height, inPixels, 0, width );
        int index = 0;
        
        //Create random points to use a the cluster center
    Random random = new Random();
    for (int i = 0; i < numOfCluster; i++)
    {
        int randomNumber1 = random.nextInt(width);
        int randomNumber2 = random.nextInt(height);
        index = randomNumber2 * width + randomNumber1;
        ClusterCenter cc = new ClusterCenter(randomNumber1, randomNumber2, inPixels[index]);
        cc.setcIndex(i);
        clusterCenterList.add(cc); 
    }
        
        // create all cluster point
        for (int row = 0; row < height; ++row)
        {
            for (int col = 0; col < width; ++col)
            {
              index = row * width + col;
              int color = inPixels[index];
              pointList.add(new ClusterPoint(row, col, color));
 
            }
        }
        
        // initialize the clusters for each point
        double[] clusterDisValues = new double[clusterCenterList.size()];
        for(int i=0; i<pointList.size(); i++)
        {
          for(int j=0; j<clusterCenterList.size(); j++)
          {
            clusterDisValues[j] = calculateEuclideanDistance(pointList.get(i), clusterCenterList.get(j));
          }
          pointList.get(i).setClusterIndex(getCloserCluster(clusterDisValues));
        }
        
        // calculate the old summary
        // assign the points to cluster center
        // calculate the new cluster center
        // computation the delta value
        // stop condition--
        double[] oldClusterCenterColors = reCalculateClusterCenters();
        while(true)
        {
          stepClusters();
          double[] newClusterCenterColors = reCalculateClusterCenters();
          if(isStop(oldClusterCenterColors, newClusterCenterColors))
          {           
            break;
          } 
          else
          {
            oldClusterCenterColors = newClusterCenterColors;
          }
        }
        
        //update the result image
        dest = createCompatibleDestImage(src, null );
        index = 0;
        int[] outPixels = new int[width*height];       
        for (int j = 0; j < pointList.size(); j++)
        {
            for (int i = 0; i < clusterCenterList.size(); i++)
            {
                ClusterPoint p = this.pointList.get(j);
                if (clusterCenterList.get(i).getcIndex() == p.getClusterIndex())
                {
                  int row = (int)p.getX(); // row
                  int col = (int)p.getY(); // column
                  index = row * width + col;
                  outPixels[index] = clusterCenterList.get(i).getPixelColor();
                }
            }
        }
        
        // fill the pixel data
        setRGB( dest, 0, 0, width, height, outPixels );
    return dest;
  }
  
  private boolean isStop(double[] oldClusterCenterColors, double[] newClusterCenterColors) {
    for(int i=0; i<oldClusterCenterColors.length; i++)
    {
      System.out.println("cluster " + i + " old : " + oldClusterCenterColors[i] + ", new : " + newClusterCenterColors[i]);
      if(oldClusterCenterColors[i]  != newClusterCenterColors[i]) 
      {
        return false;
      }
    }
    System.out.println();
    return true;
  }
 
  /**
   * update the cluster index by distance value
   */
  private void stepClusters() 
  {
        // initialize the clusters for each point
        double[] clusterDisValues = new double[clusterCenterList.size()];
        for(int i=0; i<pointList.size(); i++)
        {
          for(int j=0; j<clusterCenterList.size(); j++)
          {
            clusterDisValues[j] = calculateEuclideanDistance(pointList.get(i), clusterCenterList.get(j));
          }
          pointList.get(i).setClusterIndex(getCloserCluster(clusterDisValues));
        }
    
  }
 
  /**
   * using cluster color of each point to update cluster center color
   * 
   * @return
   */
  private double[] reCalculateClusterCenters() {
    
    // clear the points now
    for(int i=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;
  }
  
  
 
  /**
   * 
   * @param clusterDisValues
   * @return
   */
  private double getCloserCluster(double[] clusterDisValues)
  {
    double min = clusterDisValues[0];
    int clusterIndex = 0;
    for(int i=0; i<clusterDisValues.length; i++)
    {
      if(min > clusterDisValues[i])
      {
        min = clusterDisValues[i];
        clusterIndex = i;
      }
    }
    return clusterIndex;
  }
 
  /**
   * 
   * @param point
   * @param cluster
   * @return distance value
   */
  private double calculateEuclideanDistance(ClusterPoint p, ClusterCenter c) 
  {
    // int pa = (p.getPixelColor() >> 24) & 0xff;
      int pr = (p.getPixelColor() >> 16) & 0xff;
      int pg = (p.getPixelColor() >> 8) & 0xff;
      int pb = p.getPixelColor() & 0xff;
      // int ca = (c.getPixelColor() >> 24) & 0xff;
      int cr = (c.getPixelColor() >> 16) & 0xff;
      int cg = (c.getPixelColor() >> 8) & 0xff;
      int cb = c.getPixelColor() & 0xff;
      
      return Math.sqrt(Math.pow((pr - cr), 2.0) + Math.pow((pg - cg), 2.0) + Math.pow((pb - cb), 2.0));
  }
 
}

转载请注明出自gloomyfish博客

相关文章
|
22天前
|
算法 计算机视觉
图像处理之积分图应用四(基于局部均值的图像二值化算法)
图像处理之积分图应用四(基于局部均值的图像二值化算法)
91 0
|
22天前
|
监控 算法 图计算
图像处理之积分图应用三(基于NCC快速相似度匹配算法)
图像处理之积分图应用三(基于NCC快速相似度匹配算法)
20 0
|
22天前
|
文字识别 算法 计算机视觉
图像处理之Zhang Suen细化算法
图像处理之Zhang Suen细化算法
16 0
|
15天前
|
机器学习/深度学习 算法 数据可视化
算法金 | 再见!!!K-means
**k-means 算法的简要总结:** - **k-means** 是一种非监督学习的聚类算法,用于将数据分为 k 个类别。 - **工作流程** 包括初始化 k 个中心点,分配数据点到最近的中心,更新中心点,然后迭代直到中心点稳定或达到最大迭代次数。 - **优点** 包括简单易懂、计算效率高,适合大规模数据,结果直观。 - **缺点** 包括需要预设 k 值,对初始中心点敏感,假设簇是凸形,受异常值影响大。
16 2
算法金 | 再见!!!K-means
|
4天前
|
机器学习/深度学习 人工智能 自然语言处理
机器学习算法入门:从K-means到神经网络
【6月更文挑战第26天】机器学习入门:从K-means到神经网络。文章涵盖了K-means聚类、逻辑回归、决策树和神经网络的基础原理及应用场景。K-means用于数据分组,逻辑回归适用于二分类,决策树通过特征划分做决策,神经网络则在复杂任务如图像和语言处理中大显身手。是初学者的算法导览。
|
22天前
|
算法 Java 计算机视觉
图像处理之积分图算法
图像处理之积分图算法
14 2
|
22天前
|
资源调度 算法 计算机视觉
图像处理之积分图应用二(快速边缘保留滤波算法)
图像处理之积分图应用二(快速边缘保留滤波算法)
12 0
|
22天前
|
算法 BI 计算机视觉
图像处理之积分图应用一(半径无关的快速模糊算法)
图像处理之积分图应用一(半径无关的快速模糊算法)
14 0
|
4天前
|
机器学习/深度学习 自然语言处理 算法
m基于深度学习的OFDM+QPSK链路信道估计和均衡算法误码率matlab仿真,对比LS,MMSE及LMMSE传统算法
**摘要:** 升级版MATLAB仿真对比了深度学习与LS、MMSE、LMMSE的OFDM信道估计算法,新增自动样本生成、复杂度分析及抗频偏性能评估。深度学习在无线通信中,尤其在OFDM的信道估计问题上展现潜力,解决了传统方法的局限。程序涉及信道估计器设计,深度学习模型通过学习导频信息估计信道响应,适应频域变化。核心代码展示了信号处理流程,包括编码、调制、信道模拟、降噪、信道估计和解调。
26 8
|
6天前
|
算法
基于GA遗传优化的混合发电系统优化配置算法matlab仿真
**摘要:** 该研究利用遗传算法(GA)对混合发电系统进行优化配置,旨在最小化风能、太阳能及电池储能的成本并提升系统性能。MATLAB 2022a用于实现这一算法。仿真结果展示了一系列图表,包括总成本随代数变化、最佳适应度随代数变化,以及不同数据的分布情况,如负荷、风速、太阳辐射、弃电、缺电和电池状态等。此外,代码示例展示了如何运用GA求解,并绘制了发电单元的功率输出和年变化。该系统原理基于GA的自然选择和遗传原理,通过染色体编码、初始种群生成、适应度函数、选择、交叉和变异操作来寻找最优容量配置,以平衡成本、效率和可靠性。