本文共 3929 字,大约阅读时间需要 13 分钟。
k-means是一种经典的无监督学习算法,广泛应用于数据聚类任务中。本文将介绍如何利用OpenCV库实现k-means分类算法,并展示实际应用中的实现代码和运行结果。
k-means算法的目标是将数据集分成k个聚类,使得每个聚类内部的数据点与聚类中心的距离之和最小。算法通过迭代优化中心的位置,最终达到最优分组。k-means算法的核心步骤包括以下几个:
以下是用于生成随机数据进行分类的一个典型实现:
#include#include using namespace cv;using namespace std;int main1() { Mat img(500, 500, CV_8UC3); RNG rng(12345); Scalar colorTab[] = { Scalar(0,0,255), Scalar(0,255,0), Scalar(255,0,0), Scalar(0,255,255), Scalar(255,0,255) }; int numCluster = rng.uniform(2, 5); // 分类个数 cout << "分类个数:" << numCluster << endl; int sampleCount = rng.uniform(2, 1000); // 需要分类的点数 Mat points(sampleCount, 1, CV_32FC2); // 每一列两个数 Mat labels; // 存储每一个数据点的聚类编号 Mat centers; // 存储每一个聚类的中心位置 // 生成随机数 for (int k = 0; k < numCluster; k++) { Point center; center.x = rng.uniform(0, img.cols); center.y = rng.uniform(0, img.rows); Mat pointChunk = points.rowRange(k*sampleCount / numCluster, k == numCluster - 1 ? sampleCount : (k + 1)*sampleCount / numCluster); rng.fill(pointChunk, RNG::NORMAL, Scalar(center.x, center.y), Scalar(img.cols*0.05, img.rows*0.05)); } randShuffle(points, 1, &rng); // 将随机数据块打乱 // 使用kmeans kmeans(points, numCluster, labels, TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 0.1), 3, KMEANS_PP_CENTERS, centers); // 用不同颜色显示分类 img = Scalar::all(255); for (int i = 0; i < sampleCount; i++) { int index = labels.at (i); Point p = points.at (i); circle(img, p, 2, colorTab[index], -1, 8); } for (int i = 0; i < centers.rows; i++) { int x = centers.at (i, 0); int y = centers.at (i, 1); cout << "x:" << x << "y:" << y << endl; circle(img, Point(x, y), 40, colorTab[i], 1, LINE_AA); } imshow("KMean-Demo", img); waitKey(0); return 0;}
以下是用于读取图片并执行分类的实现:
#include#include using namespace std;using namespace cv;using namespace cv::ml;int main2(int argc, char **argv) { Mat src = imread("E:\\vs2015\\opencvstudy\\2kmeans.jpg", 1); if (src.empty()) { cout << "could not load the image!" << endl; return -1; } imshow("input", src); int width = src.cols; int height = src.rows; int dims = src.channels(); // 初始化定义 int sampleCount = width * height; int clusterCount = 4; Mat points(sampleCount, dims, CV_32F, Scalar(10)); Mat labels; Mat centers(clusterCount, 1, points.type()); RGB数据转换到样本数据 int index = 0; for (int row = 0; row < height; row++) { for (int col = 0; col < width; col++) { index = row * width + col; Vec3b bgr = src.at (row, col); points.at (index, 0) = static_cast (bgr[0]); points.at (index, 1) = static_cast (bgr[1]); points.at (index, 2) = static_cast (bgr[2]); } } // 运行kMeans TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 0.1); kmeans(points, sampleCount, labels, criteria, 3, KMEANS_PP_CENTERS, centers); // 显示图像分割结果 Mat result = Mat::zeros(src.size(), src.type()); Scalar colorTab[] = { Scalar(0,0,255), Scalar(0,255,0), Scalar(255,0,0), Scalar(0,255,255), Scalar(255,0,255) }; for (int row = 0; row < height; row++) { for (int col = 0; col < width; col++) { index = row * width + col; int label = labels.at (index, 0); result.at (row, col)[0] = colorTab[label][0]; result.at (row, col)[1] = colorTab[label][1]; result.at (row, col)[2] = colorTab[label][2]; } } for (int i = 0; i < centers.rows; i++) { int x = centers.at (i, 0); int y = centers.at (i, 1); cout << "第" << i << "个:c.x" << x << "c.y" << y << endl; } imshow("KMeans_Result", result); waitKey(0); return 0;}
运行上述代码后,会打开一个窗口显示分类结果。每个数据点会被标记为对应的颜色,聚类中心也会以圆圈的形式显示在图像上。
通过以上实现,可以清晰地看到k-means算法在图像分类任务中的应用。代码首先生成随机数据点,并使用k-means算法进行分类,最后通过绘制图像的方式展示分类结果。这种方法在实际应用中可以用来对图像数据进行自动分割和分类。
如果需要更高效的算法或更复杂的分类任务,可以考虑使用其他机器学习算法如SVM、随机森林等。
转载地址:http://fgsfk.baihongyu.com/