c++opencv图像处理|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图像处理|C++OpenCV系统学习(14)——图像分割与抠图(1)_KMeans
文章图片

1.2基本流程 【c++opencv图像处理|C++OpenCV系统学习(14)——图像分割与抠图(1)_KMeans】c++opencv图像处理|C++OpenCV系统学习(14)——图像分割与抠图(1)_KMeans
文章图片

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图像处理|C++OpenCV系统学习(14)——图像分割与抠图(1)_KMeans
文章图片

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

    推荐阅读