图像处理------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点集合。
二:算法基本流程
三:算法关键代码解析
初始化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));
; i<clusterCenterList.size(); i++)
四:运行效果
五: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));
- }
- }
图像处理------K-Means算法演示的更多相关文章
- KNN 与 K - Means 算法比较
KNN K-Means 1.分类算法 聚类算法 2.监督学习 非监督学习 3.数据类型:喂给它的数据集是带label的数据,已经是完全正确的数据 喂给它的数据集是无label的数据,是杂乱无章的,经过 ...
- K-means算法
K-means算法很简单,它属于无监督学习算法中的聚类算法中的一种方法吧,利用欧式距离进行聚合啦. 解决的问题如图所示哈:有一堆没有标签的训练样本,并且它们可以潜在地分为K类,我们怎么把它们划分呢? ...
- JS写的排序算法演示
看到网上有老外写的,就拿起自已之前完成的jmgraph画图组件也写了一个.想了解jmgraph的请移步:https://github.com/jiamao/jmgraph 当前演示请查看:http:/ ...
- 用Python从零开始实现K近邻算法
KNN算法的定义: KNN通过测量不同样本的特征值之间的距离进行分类.它的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别.K通 ...
- 02-18 scikit-learn库之k近邻算法
目录 scikit-learn库之k近邻算法 一.KNeighborsClassifier 1.1 使用场景 1.2 代码 1.3 参数详解 1.4 方法 1.4.1 kneighbors([X, n ...
- 使用K均值算法进行图片压缩
K均值算法 上一期介绍了机器学习中的监督式学习,并用了离散回归与神经网络模型算法来解决手写数字的识别问题.今天我们介绍一种机器学习中的非监督式学习算法--K均值算法. 所谓非监督式学习,是一种 ...
- AlgorithmMan,一套免费的算法演示神器
概述 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/971 访问. 文章末尾附带GitHub开源下载地址. 0.概述 ...
- K近邻算法:机器学习萌新必学算法
摘要:K近邻(k-NearestNeighbor,K-NN)算法是一个有监督的机器学习算法,也被称为K-NN算法,由Cover和Hart于1968年提出,可以用于解决分类问题和回归问题. 1. 为什么 ...
- K 均值算法-如何让数据自动分组
公号:码农充电站pro 主页:https://codeshellme.github.io 之前介绍到的一些机器学习算法都是监督学习算法.所谓监督学习,就是既有特征数据,又有目标数据. 而本篇文章要介绍 ...
- 机器学习算法之K近邻算法
0x00 概述 K近邻算法是机器学习中非常重要的分类算法.可利用K近邻基于不同的特征提取方式来检测异常操作,比如使用K近邻检测Rootkit,使用K近邻检测webshell等. 0x01 原理 ...
随机推荐
- 我是如何让minio client上传速度提高几十倍的
minio java client 使用okhttp作为底层的http实现,在产品包里面局域网上传文件的速度一直只有400~800KB/s,经过一天排查发现是-Djava.compile=none禁用 ...
- wpf datagrid row height 行高自动计算使每行行高自适应文本
wpf 的datagrid的行高 要么是Auto,要么是定值:但会带来麻烦就是每行行高都一样. 当需要按内容(主要是wrap 换行的textbox或textblock)来动态调整行高的时候,需要用到d ...
- appium+python环境搭建
一.环境 1.安装python. 2.安装appium. 3.安装pip 4.安装selenium 5.安装Appium-Python-Client #cmd->cd setupto ...
- jdk环境变量配置及配置原因
windows下: 一.设置环境变量 变量名:JAVA_HOME 变量值:D:\Program Files\Java\jdk1.6.0 (即jdk安装的位置) 变量名:Path (这个变量名已在系 ...
- BZOJ 1192: [HNOI2006]鬼谷子的钱袋 [娱乐]
题意: n个数分组,使得小于n的每个数都能表示出来,最少几组 就是“最优集合”的超级弱化版.....每次+=now+1 然后一个貌似科学的方法是n二进制拆分 #include <iostream ...
- HDU 3032 Nim or not Nim? [Multi-SG]
传送门 题意: nim游戏,多了一种操作:将一堆分成两堆 Multi-SG游戏规定,在符合拓扑原则的前提下,一个单一游戏的后继可以为多个单一游戏. 仍然可以使用$SG$函数,分成多个游戏的后继$SG$ ...
- ES6的Symbol
let s = Symbol(); alert(typeof(s)); // Symbol函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者转为字符串时,比 ...
- python如何讲一个文件中的图片分到两个
最近在做一个图像分类的比赛,作为初次接触深度学习的菜鸟,上手了keras.说实话,除了keras教程,中文博客的技术支持太差了.正在头大的学习中...废话不多说,记录一下学习中的一些小细节.在遇到ge ...
- JAVAEE——BOS物流项目05:OCUpload、POI、pinyin4J、重构分页代码、分区添加、combobox
1 学习计划 1.实现区域导入功能 n OCUpload一键上传插件使用 n 将文件上传到Action n POI简介 n 使用POI解析Excel文件 n 完成数据库操作 n 使用pinyin4J生 ...
- 读书共享 Primer Plus C-part 9
第十二章 存储类.链接和内存管理 针对代码块中的static变量做如下范本 #include ...