您的位置:首页 > 其它

图像基本变换---KMeans聚类算法

2016-05-13 08:53 447 查看
本文将详细介绍K-Means均值聚类的算法及实现。
聚类是一个将数据集中在某些方面相似的数据成员进行分类组织的过程。K均值聚类是最著名的划分聚类算法,由于简洁和效率使得他成为所有聚类算法中最广泛使用的。给定一个数据点集合和需要的聚类数目k,k由用户指定,k均值算法根据某个距离函数反复把数据分入k个聚类中。
算法过程:
1,初始化聚类数目K,并任意选择K个初始化均值ui。
2,迭代图像中每个像素f(x,y),判断其距离哪一个聚类均值最近,即|f(x,y)-ui|最小,则将该像素划分归属为对应的聚类i。
3,完成一次迭代后,计算每一个聚类的新的均值ui,均值公式不在重复。
4,重复步骤2-3,直到相邻两次迭代中每一个聚类的ui不在发生变化,则迭代结束。
5,得到最后的分类结果。
注:本文代码中采用的是对灰度图像进行KMeans聚类,然后还原彩色信息。
下面 我们给出一份Win8 C#代码,另附一份Winform C#代码DEMO,在文章末尾链接 中。

///
/// KMeans Cluster process.
///
/// The source image.
/// Cluster threshould, from 2 to 255.
///
public static WriteableBitmap KMeansCluster(WriteableBitmap src,int k)////KMeansCluster
{
if (src != null)
{
int w = src.PixelWidth;
int h = src.PixelHeight;
WriteableBitmap dstImage = new WriteableBitmap(w, h);
byte[] temp = src.PixelBuffer.ToArray();
byte[] tempMask = (byte[])temp.Clone();
int b = 0, g = 0, r = 0;
//定义灰度图像信息存储变量
byte[] imageData = new byte[w * h];
//定义聚类均值存储变量(存储每一个聚类的均值)
double[] meanCluster = new double[k];
//定义聚类标记变量(标记当前像素属于哪一类)
int[] markCluster = new int[w * h];
//定义聚类像素和存储变量(存储每一类像素值之和)
double[] sumCluster = new double[k];
//定义聚类像素统计变量(存储每一类像素的数目)
int []countCluster = new int[k];
//定义聚类RGB分量存储变量(存储每一类的RGB三分量大小)
int[] sumR = new int[k];
int[] sumG = new int[k];
int[] sumB = new int[k];
//临时变量
int sum = 0;
//循环控制变量
bool s = true;
double[] mJduge = new double[k];
double tempV = 0;
int cou = 0;
//获取灰度图像信息
for (int j = 0; j < h; j++)
{
for (int i = 0; i < w; i++)
{
b = tempMask[i * 4 + j * w * 4];
g = tempMask[i * 4 + 1 + j * w * 4];
r = tempMask[i * 4 + 2 + j * w * 4];
imageData[i + j * w] = (byte)(b * 0.114 + g * 0.587 + r * 0.299);
}
}
while (s)
{
sum = 0;
//初始化聚类均值
for (int i = 0; i < k; i++)
{
meanCluster[i] = i * 255.0 / (k - 1);
}
//计算聚类归属
for (int i = 0; i < imageData.Length; i++)
{
tempV = Math.Abs((double)imageData[i] - meanCluster[0]);
cou = 0;
for (int j = 1; j < k; j++)
{
double t = Math.Abs((double)imageData[i] - meanCluster[j]);
if (tempV > t)
{
tempV = t;
cou = j;
}
}
countCluster[cou]++;
sumCluster[cou] += (double)imageData[i];
markCluster[i] = cou;
}
//更新聚类均值
for (int i = 0; i < k; i++)
{
meanCluster[i] = sumCluster[i] / (double)countCluster[i];
sum += (int)(meanCluster[i] - mJduge[i]);
mJduge[i] = meanCluster[i];
}
if (sum == 0)
{
s = false;
}
}
//计算聚类RGB分量
for (int j = 0; j < h; j++)
{
for (int i = 0; i < w; i++)
{
sumB[markCluster[i + j * w]] += tempMask[i * 4 + j * w * 4];
sumG[markCluster[i + j * w]] += tempMask[i * 4 + 1 + j * w * 4];
sumR[markCluster[i + j * w]] += tempMask[i * 4 + 2 + j * w * 4];
}
}
for (int j = 0; j < h; j++)
{
for (int i = 0; i < w; i++)
{
temp[i * 4 + j * 4 * w] = (byte)(sumB[markCluster[i + j * w]] / countCluster[markCluster[i + j * w]]);
temp[i * 4 + 1 + j * 4 * w] = (byte)(sumG[markCluster[i + j * w]] / countCluster[markCluster[i + j * w]]);
temp[i * 4 + 2 + j * 4 * w] = (byte)(sumR[markCluster[i + j * w]] / countCluster[markCluster[i + j * w]]);
}
}
Stream sTemp = dstImage.PixelBuffer.AsStream();
sTemp.Seek(0, SeekOrigin.Begin);
sTemp.Write(temp, 0, w * 4 * h);
return dstImage;
}
else
{
return null;
}
}



demo下载: http://www.zealfilter.com/forum.php?mod=viewthread&tid=29&extra=page%3D1
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: