opencv KMeans 图像分割实例

文章目录

        • 一、原理
        • 二、函数原型
        • 三、代码实例
        • 四、运行结果

一、原理

(1)随机选择两个中心点;
(2)计算每个点到这两个中心点的距离,最近的分成一类(连接起来);
(3)重新计算中心点(平均值计算),计算新的中心点到久的中心点的差值如果小于输入的值,就说明中心的位置发生了变化,,那么到(2)步重新计算中心点到每个点的距离,开始下一次循环;
(4)执行多个迭代之后,满足收敛时,得到最终的分类。

如下图:
opencv KMeans 图像分割实例_第1张图片

二、函数原型

double cv::kmeans( InputArray data, int K, InputOutputArray bestLabels
    TermCriteria citeria, int attempts, int flags, OutputArray)

(1)data: 需要自动聚类的数据,一般是一个Mat。浮点型的矩阵,每行为一个样本。
(2)k: 取成几类,比较关键的一个参数。
(3)bestLabels: 返回的类别标记,整型数字。
(4)criteria: 算法结束的标准,获取期望精度的迭代最大次数
(5)attempts: 判断某个样本为某个类的最少聚类次数,比如值为3时,则某个样本聚类3次都为同一个类,则确定下来。
(6)flags: 确定簇心的计算方式。有三个值可选:KMEANS_RANDOM_CENTERS 表示随机初始化簇心。KMEANS_PP_CENTERS 表示用kmeans++算法来初始化簇心(没用过),KMEANS_USE_INITIAL_LABELS 表示第一次聚类时用用户给定的值初始化聚类,后面几次的聚类,则自动确定簇心。
(7)centers: 用来初始化簇心的。与前一个flags参数的选择有关。如果选择KMEANS_RANDOM_CENTERS随机初始化簇心,则这个参数可省略。

三、代码实例

#include 
#include 
using namespace cv;
using namespace std;

int main()
{
	Mat src = imread("D:/source/image/dlrb.png");
	if (src.empty())
	{
		printf("read image error\n");
		system("pause");
		return -1;
	}

	imshow("src", src);

	Scalar colorTab[] = {
		Scalar(0, 0, 255),
		Scalar(0, 255, 0),
		Scalar(255, 0, 0),
		Scalar(0, 255, 255),
		Scalar(255, 0, 255)
	};

	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, clusterCount, labels, criteria, 3, KMEANS_PP_CENTERS, centers);

	// 显示图像分割后的结果,一维转多维
	Mat result = Mat::zeros(src.size(), src.type());
	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);
		circle(result, Point(x, y), 10, Scalar(255,255,255), 1, LINE_AA);
	}

	imshow("result", result);

	waitKey(0);
	return(0);
}

四、运行结果

opencv KMeans 图像分割实例_第2张图片

你可能感兴趣的:(机器视觉,【OpenCV】整理记录)