这次的寒假实习选题选择了遥感影像的K均值聚类算法,在网上淘了一下发现大部分都是非遥感影像的Kmean算法,而且有的不能运行,还有的很繁杂,因此决定自己写一篇方便后来人(这是本人第一次写博客,轻喷)
算法原理
Kmean算法的原理我就不细讲了,在这里引用一篇个人觉得讲解还算不错的
https://blog.csdn.net/zengxiantao1994/article/details/73441922
然后分类后结果以及分布图可以参考这一篇(对简单的点进行分类)
https://blog.csdn.net/u011291472/article/details/103104091
算法实现
之前课间实习的时候写过K均值的算法但是只是将10个数字分成2类,而对遥感影像来说:
1、元素数目众多,这个不用多说,一张图像成千上万个像元
2、元素结构复杂,因为考虑到普适性所以直接用的是彩色影像,所以有RGB三个通道的值
了解了这些就可以开始进行编译了
OpenCV的配置
https://blog.csdn.net/u010719432/article/details/13323431
推荐使用这个,虽然过程比较麻烦但是一劳永逸
https://blog.csdn.net/xiahangli1/article/details/45038065
或者像我一样配置好一个属性表之后把它存好,每次用之前配置现有属性表就可以用了
选择初始聚类中心
一般来说直接选择最前面的若干个点作为初始聚类中心,但是可能收敛结果不理想(大家尽管尝试,最后结果肯定是对的,但是怎么说呢,还是不建议这样子写),在此我选择的是最大最小距离选心法。我就不引用了,直接简单的说一下吧:先定下第一个初始聚类中心,再在待选聚类中心中选择和第一个中心“距离”最远的点作为第二个聚类中心;再在剩下的待选点中选择与该点到两个聚类中心“距离”中的最小值最远的点作为第三个聚类中心…依次类推得到所有的初始聚类中心
int ChoseCenter(Mat graph, Point center[sort]) {
//最大最小距离选心法
int grow = graph.rows;
int gcol = graph.cols; //图像大小
center[0].x = 0;
center[0].y = 0; //第一个初始聚类中心(0,0)
for (int i = 1; i < sort; i++) {
double max_mindistance = 0;
int id = 0; //点的序号,如(2,2)点的ID就是2*col+2
for (int k = 0; k < grow*gcol; k++) {
//这样写就只用一层循环体就可以遍历整个二维矩阵
double mindistance = INFINITY;
double tep = 0;
for (int t = 0; t < i; t++) {
tep = sqrt(pow(graph.data[k * 3 + 0] - graph.data[(center[t].x*gcol + center[t].y) * 3 + 0], 2) +
pow(graph.data[k * 3 + 1] - graph.data[(center[t].x*gcol + center[t].y) * 3 + 1], 2) +
pow(graph.data[k * 3 + 2] - graph.data[(center[t].x*gcol + center[t].y) * 3 + 2], 2)); //计算RGB色差
if (tep < mindistance)
mindistance = tep; //确定点到所有已知初始聚类中心的最小色差
}
if (mindistance > max_mindistance) {
max_mindistance = mindistance; //确定所有点的最小色差的最大值
id = k; //最大值对应的点的序号
}
}
center