您的位置:首页 > 运维架构

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

2015-12-09 16:52 676 查看
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随机初始化簇心,则这个参数可省略。

示例图片:



学过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 = 5;
Vec3b colorTab[] =
{
Vec3b(0, 0, 255),
Vec3b(0, 255, 0),
Vec3b(255, 100, 100),
Vec3b(255, 0, 255),
Vec3b(0, 255, 255)
};
Mat data,labels;
Mat pic = imread("d:/woman.png");
for (int i = 0; i < pic.rows;i++)
for (int j = 0; j < pic.cols; j++)
{
Vec3b point = pic.at<Vec3b>(i, j);
Mat tmp = (Mat_<float>(1, 3) << point[0], point[1], point[2]);
data.push_back(tmp);
}

//根据浏览图片,确定k=3
kmeans(data, 3, labels, TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 1.0),
3, KMEANS_RANDOM_CENTERS);

int n = 0;
//显示聚类结果,不同的类别用不同的颜色显示
for (int i = 0; i < pic.rows; i++)
for (int j = 0; j < pic.cols; j++)
{
int clusterIdx = labels.at<int>(n);
pic.at<Vec3b>(i, j) = colorTab[clusterIdx];
n++;
}
imshow("pic", pic);
waitKey(0);

return 0;
}


结果:



效果不是十分理想,毕竟是全自动的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: