C++OpenCV系统学习(14)——图像分割与抠图(1)_KMeans

目录

1.概述

1.1K-means方法

 1.2基本流程

 2.K-means图像分割

2.1图像分割

 2.2K-means算法原理

2.3实验案例


1.概述

图像分割主要有四种方法:

K-means和GMM是基于聚类的方式进行图像分割,分水岭方法是基于图像的拓扑结构进行图像分割的,还有GrabCut是基于交互方式的图像分割与抠图的方法。

1.1K-means方法

K-means是无监督学习方法,对于分类问题需要输入分类数目,初始化中心位置。对于硬分类问题,以距离度量。

主要用处有两个:

  • 数据聚类
  • 图像分割

C++OpenCV系统学习(14)——图像分割与抠图(1)_KMeans_第1张图片

 1.2基本流程

C++OpenCV系统学习(14)——图像分割与抠图(1)_KMeans_第2张图片

 2.K-means图像分割

2.1图像分割

        图像分割是图像处理中的一种方法,图像分割是指将一幅图像分解成若干互不相交区域的集合,其实质可以看成是一种像素的聚类过程。通常使用到的图像分割的方法可以分为:

  • 基于边缘的技术
  • 基于区域的技术

基于聚类算法的图像分割属于基于区域的技术        

 2.2K-means算法原理

        K-Means算法是基于距离相似性的聚类算法,通过比较样本之间的相似性,将形式的样本划分到同一个类别中,K-Means算法的基本过程为:

  1. 初始化常数 ,随机初始化k个聚类中心
  2. 重复计算以下过程,直到聚类中心不再改变

       (1) 计算每个样本与每个聚类中心之间的相似度,将样本划分到最相似的类别中
        (2)计算划分到每个类别中的所有样本特征的均值,并将该均值作为每个类新的聚类中心
输出最终的聚类中心以及每个样本所属的类别
        在K-Means算法中,需要随机初始化k个聚类中心,而K-Means算法对初始聚类中心的选取较为敏感,若选择的聚类中心不好,则得到的聚类结果会非常差,因此,对K-Means算法提出了很多的改进的方法,如K-Means++算法,在K-Means++算法中,希望初始化的k个聚类中心之间的距离尽可能的大,其具体过程为:

  1. 在数据集中随机选择一个样本点作为第一个初始化的聚类中心
  2. 选择出其余的聚类中心:

        计算样本中的每一个样本点与已经初始化的聚类中心之间的距离,并选择其中最短的距离
        以概率选择距离最大的样本作为新的聚类中心,重复上述过程,直到 个聚类中心都被确定
        对k个初始化的聚类中心,利用K-Means算法计算最终的聚类中心。

2.3实验案例

Mat MyApi::k_meansCluster(Mat& image)
{
	Scalar colorTab[] = 
	{
		Scalar(0,0,255),
		Scalar(0,255,0),
		Scalar(255,0,0),
		Scalar(0,255,255),
		Scalar(255,0,255)
	};
	int width = image.cols;
	int height = image.rows;
	int dims = image.channels();

	//初始化定义
	int sampleCount = width * height;//有多少像素点就有多少sample
	int clusterCount = 2;
	Mat points(sampleCount, dims, CV_32F, Scalar(10));
	Mat labels;
	Mat centers(clusterCount,1,points.type());//有多少clusterCount就有多少centers

	//RGB数据转换到样本数据
	int index = 0; 
	for (int row = 0; row < height; row++)
	{
		for (int col = 0; col < width; col++)
		{
			index = row * width + col;
			Vec3b bgr = image.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]);
		}
	}
	//运行K-means
	TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 0.1);
	kmeans(points, clusterCount, labels, criteria, 3, KMEANS_PP_CENTERS, centers);

	//显示图像分割结果
	Mat result = Mat::zeros(image.size(), image.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];
		}
	}
	return result;
}

C++OpenCV系统学习(14)——图像分割与抠图(1)_KMeans_第3张图片

 左边为原图,右边为分为两类的图

你可能感兴趣的:(c++opencv图像处理,opencv,c++,kmeans)