利用opencv3中的kmeans实现抠图功能

时间:2022-11-12 07:58:53

kmeans算法主要用来实现自动聚类,是一种非监督的机器学习算法,使用非常广泛。在opencv3.0中提供了这样一个函数,直接调用就能实现自动聚类,非常方便。

函数原型:

C++: double kmeans(InputArray data, int K, InputOutputArray bestLabels, TermCriteria criteria, int attempts, int flags, OutputArray centers=noArray() )

有7个参数,分别表示:

data:  需要自动聚类的数据,一般是一个Mat。浮点型的矩阵,每行为一个样本。

k: 取成几类,比较关键的一个参数。

bestLabels:  返回的类别标记,整型数字。

criteria: 算法结束的标准,获取期望精度的迭代最大次数

attempts:  判断某个样本为某个类的最少聚类次数,比如值为3时,则某个样本聚类3次都为同一个类,则确定下来。

flags:  确定簇心的计算方式。有三个值可选:KMEANS_RANDOM_CENTERS 表示随机初始化簇心。KMEANS_PP_CENTERS 表示用kmeans++算法来初始化簇心(没用过),KMEANS_USE_INITIAL_LABELS 表示第一次聚类时用用户给定的值初始化聚类,后面几次的聚类,则自动确定簇心。

centers: 用来初始化簇心的。与前一个flags参数的选择有关。如果选择KMEANS_RANDOM_CENTERS随机初始化簇心,则这个参数可省略。

示例图片:

利用opencv3中的kmeans实现抠图功能

学过ps描图的都知道,头发丝在抠图中,是非常难的。这里我们就用kmeans自动聚类来进行自动抠图。

思路就是将图片的每个像素点的三通道值作为一个特征,因此会得到一个n行3列的特征矩阵data,然后用这个特征矩阵进行kmeans

代码:

#include "stdafx.h"
#include "opencv2\opencv.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
const int MAX_CLUSTERS = ;
Vec3b colorTab[] =
{
Vec3b(, , ),
Vec3b(, , ),
Vec3b(, , ),
Vec3b(, , ),
Vec3b(, , )
};
Mat data,labels;
Mat pic = imread("d:/woman.png");
for (int i = ; i < pic.rows;i++)
for (int j = ; j < pic.cols; j++)
{
Vec3b point = pic.at<Vec3b>(i, j);
Mat tmp = (Mat_<float>(, ) << point[], point[], point[]);
data.push_back(tmp);
} //根据浏览图片,确定k=3
kmeans(data, , labels, TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, , 1.0),
, KMEANS_RANDOM_CENTERS); int n = ;
//显示聚类结果,不同的类别用不同的颜色显示
for (int i = ; i < pic.rows; i++)
for (int j = ; j < pic.cols; j++)
{
int clusterIdx = labels.at<int>(n);
pic.at<Vec3b>(i, j) = colorTab[clusterIdx];
n++;
}
imshow("pic", pic);
waitKey(); return ;
}

结果:

利用opencv3中的kmeans实现抠图功能

效果不是十分理想,毕竟是全自动的。