#include<opencv2/opencv.hpp>
#include<iostream>
#include<stdio.h>
#include <cstdio>
#include<string>
#include<math.h>
#include<stdlib.h>
#include<vector>
#include<string.h>
#include<ctime>
using namespace std;
using namespace cv;
int main()
{
srand(time(0));
// 颜色
Scalar ColorTab[] =
{
Scalar(0, 0, 255),
Scalar(0, 255, 0),
Scalar(255, 0, 0),
Scalar(0, 255, 255),
Scalar(255, 0, 255),
Scalar(255, 255, 0)
};
// 记录总的随机点个数以及位置
vector<Point2f> sum_points;
// 质心的位置 设置k为4 可以更改
int K = 3;
vector<Point2f> points;
// 产生图中的随机点 500个点做聚类
Mat write = Mat::zeros(500, 500, CV_8UC1);
bitwise_not(write, write);
int temp_K = K;
for (int i = 0; i < 500; i++)
{
int w = rand() % (write.cols);
int h = rand() % (write.rows);
if (w - 1 > 0 && w + 1 < write.cols&&h - 1 > 0 && h + 1 < write.rows)
{
write.at<uchar>(h, w) = 0;
Point2f temppoint = Point2f(w, h);
sum_points.push_back(temppoint);
if (temp_K > 0)
{
points.push_back(temppoint);
temp_K--;
}
}
}
imshow("随机生成点", write);
// 初始质心点坐标
cout << "首次质心的位置坐标:" << endl;
for (int i = 0; i < points.size(); i++)
{
cout << i << "=" << points[i] << endl;
}
// 记录label值
vector<int> label(sum_points.size(), 0);
// 每次更新迭代的质心点坐标
vector<Point2f> new_points(points.size());
// 记录迭代多少次
int index = 0;
do
{
if (index != 0)
{
points = new_points;
}
// 欧式距离判断并更新质心点位置
// 1、欧式距离计算分类
for (int j = 0; j < sum_points.size(); j++)
{
float min_distance = float(INT_MAX);
for (int i = 0; i < points.size(); i++)
{
float distance = sqrt(pow((sum_points[j].x - points[i].x), 2) + pow((sum_points[j].y - points[i].y), 2));
if (distance < min_distance)
{
min_distance = distance;
label[j] = i;
}
}
}
// 2、更新质心的坐标点(通过label值)
// 定义k类分别的点值变量
vector<int> k(points.size(), 0);
vector<float> x(points.size(), 0.0);
vector<float> y(points.size(), 0.0);
for (int i = 0; i < label.size(); i++)
{
for (int j = 0; j < points.size(); j++)
{
// 找到对应的类别进行后续的质心坐标运算
if (j == label[i])
{
k[j]++;
x[j] += sum_points[i].x;
y[j] += sum_points[i].y;
break;
}
}
}
// 更新坐标
for (int i = 0; i < points.size(); i++)
{
x[i] /= k[i];
y[i] /= k[i];
}
// 质心坐标值填补
for (int i = 0; i < points.size(); i++)
{
new_points[i] = Point2f(x[i], y[i]);
}
index++;
cout << "第" << index << "次迭代..." << endl;
// 显示每次的迭代过程
Mat result = Mat::zeros(write.size(), CV_8UC3);
bitwise_not(result, result);
// 迭代完成的质心点坐标
for (int i = 0; i < new_points.size(); i++)
{
cout << i << "=" << points[i] << endl;
circle(result, Point(int(new_points[i].x), int(new_points[i].y)), 5, Scalar(0, 0, 255), -1, 8);
}
putText(result, format("%d 次", index), Point(20, 20), FONT_HERSHEY_SCRIPT_SIMPLEX, FONT_HERSHEY_PLAIN, Scalar(0, 0, 255), 1, 8);
for (int i = 0; i < sum_points.size(); i++)
{
circle(result, Point(int(sum_points[i].x), int(sum_points[i].y)), 2, ColorTab[label[i]], -1, 8);
}
imshow("result", result);
waitKey(0);
} while (points != new_points);
// 显示聚类结果
Mat result = Mat::zeros(write.size(), CV_8UC3);
bitwise_not(result, result);
// 迭代完成的质心点坐标
cout << "最后一次迭代质心坐标:" << endl;
for (int i = 0; i < new_points.size(); i++)
{
cout << i << "=" << points[i] << endl;
circle(result, Point(int(new_points[i].x), int(new_points[i].y)), 5, Scalar(0, 0, 255), -1, 8);
}
cout << "总共迭代了" << index << "次" << endl;
putText(result, format("%d 次", index), Point(20, 20), FONT_HERSHEY_SCRIPT_SIMPLEX, FONT_HERSHEY_PLAIN, Scalar(0, 0, 255), 1, 8);
for (int i = 0; i < sum_points.size(); i++)
{
circle(result, Point(int(sum_points[i].x), int(sum_points[i].y)), 2, ColorTab[label[i]], -1, 8);
}
imshow("result", result);
waitKey(0);
return 0;
}
opencv库教程很多。
小菜鸡代码,欢迎讨论。