k均值聚类算法(k-means clustering algorithm)

k-means算法又名k均值聚类算法。其算法思想大致为:先从样本集中随机选取 k 个样本作为类别中心,并计算所有样本与这 k 个类别中心的距离,对于每一个样本,将其划分到与其距离最近的类别中心所在的类别中,对于新的类别计算各个类别的新的类别中心。
  根据以上描述,我们大致可以猜测到实现k-means算法的主要三点:
  (1)类别个数 k 的选择
  (2)各个样本点到类别中心的距离
  (3)根据新划分的类别,更新类别中心

代码实现
首先定义类别中心:

struct KMeansClassCenter
{
	vector <int> classcenter;//类别中心,因为是1个像元,故不采用float或double
	vector <int> pixCode;//记录该类别的像元号
};

再定义每个点的象元值的属性

struct KMeansPixData
{
	vector <int> pixs;  //像元值
	KMeansClassCenter classcenter;//类别中心
	double class_distance;//距离
	int classNum;//类别号
};

进行聚类划分

bool kmeans(KMeansPixData *pixdata, int nBandCount, int nImgSizeX, int nImgSizeY, int m_maxClassNum, int m_maxIteratNum, int * outputpafScan)
{
	KMeansClassCenter *classCenter;

	pixdata = new KMeansPixData[nImgSizeX * nImgSizeY];
	
	for (int i = 0; i < m_maxClassNum; ++i)//给类别中心赋初始值
	{
		int classnum = (i + 0.5) * nImgSizeX * nImgSizeY / m_maxClassNum;
		classCenter[i].classcenter = pixdata[classnum].pixs;
	}

	for (int IteratNum = 0; IteratNum < m_maxIteratNum; ++IteratNum)//迭代
	{
		for(int pixcount = 0; pixcount < nImgSizeX * nImgSizeY; ++pixcount)//遍历像元
		{
			for (int classnum = 0; classnum < m_maxClassNum; ++classnum)//计算与每个类别中心的距离
			{
				float perclassdistance = 0;
				for (int bandcount = 0; bandcount < nBandCount; ++bandcount)
				{
					perclassdistance += (pixdata[pixcount].pixs[bandcount] - classCenter[classnum].classcenter[bandcount])
						* (pixdata[pixcount].pixs[bandcount] - classCenter[classnum].classcenter[bandcount]);
				}
				perclassdistance = sqrt(perclassdistance);
				if (classnum == 0)
					pixdata[pixcount].class_distance = sqrt((float)nImgSizeX * nImgSizeX + nImgSizeY * nImgSizeY);
				
				if (pixdata[pixcount].class_distance > perclassdistance)
				{
					pixdata[pixcount].class_distance = perclassdistance;
					pixdata[pixcount].classNum = classnum;
				}
				classCenter[pixdata[pixcount].classNum].pixCode.push_back(pixcount);//记录每个类别包括的像元号
			}
		}

		for (int classnum = 0; classnum < m_maxClassNum; ++classnum)//计算类别中心
		{
			for(int bandcount = 0; bandcount < nBandCount; ++bandcount)
			{
				int sum = 0;
				int maxsize = classCenter[classnum].pixCode.size();
				for (int classSize = 0; classSize < maxsize; ++classSize)//该类别像元个数
					sum += pixdata[classCenter[classnum].pixCode[classSize]].pixs[bandcount];
				if (maxsize == 0) continue;
				sum /= maxsize;
				classCenter[classnum].classcenter[bandcount] = (int)sum;
			}
		}
	}

	for(int bandcount = 0; bandcount < nBandCount; ++bandcount)
	{
		for(int pixcount = 0; pixcount < nImgSizeX * nImgSizeY; ++pixcount)		
			outputpafScan[pixcount] = pixdata[pixcount].classNum;
	}

	return true;
}

原始图像:
原始图像
k-means聚类的结果:
分类结果
欢迎大家批评指正。

发布了35 篇原创文章 · 获赞 37 · 访问量 4284

猜你喜欢

转载自blog.csdn.net/L_J_Kin/article/details/102797578
今日推荐