K-means算法及OpenCV实现

K-means算法MacQueen在1967年提出的,是最简单与最常见数据分类方法之一并且最为一种常见数据分析技术在机器学习、数据挖掘、模式识别、图像分析等领域都用应用。从机器学习的角度看,K-means属于一种无监督的机器学习方法。无监督学习(Unsupervised Learning)简单的说就是在不给定正确答案(标签)的情况下,在数据中找到一些相似的特征用以分析(分类)数据的方法。而在K-means算法解决图像的问题中,就是在对图像的像素点进行分类,达到图像分割的目的。

K-means算法流程:

这里写图片描述

(1)K-means初始聚类中心的确定:初始的K个分类中每个分类的中心点选择,K-Means算法支持随机选择,人工指定与中心化算法三种方式。
(2)如何判断收敛:
这里写图片描述
其中i表示第i个数据点,j表示第j个聚类中心,这里写图片描述表示第i个数据点的数据,这里写图片描述表示第j个聚类中心的值。所以RSS表征的意义为:被归于一类的数据点距离与它对应的聚类中心的差值的平方和。K-means聚类算法依靠两次聚类后RSS的差值是否小于设定的阈值判断是否达到收敛。
(3)如何表征像素点(数据点)的特征:
多维数据支持,多数时候我们要分类的特征对象的描述数据不止一个数据特征,而是一个特征向量来表示,OpenCV中通过Mat对象构建实现对多维数据KMeans分类支持。

K-means的OpenCV实现:

函数定义:

CV_EXPORTS_W double kmeans( 
InputArray data, 
int K, 
CV_OUT InputOutputArray bestLabels,
TermCriteria criteria, 
int attempts,
int flags, 
OutputArray centers=noArray() );

第一个参数:表示输入的数据集合,可以一维或者多维数据,类型是Mat类型,比如Mat points(count, 2, CV_32F)表示数据集合是二维,浮点数数据集;
第二个参数:表示分类的数目,K=2时即表示二分类;
第三个参数:表示计算之后各个数据点的最终的分类索引,是一个INT类型的Mat对象;
第四个参数:表示算法终止的条件,达到最大循环数目或者指定的精度阈值算法就停止继续分类迭代计算;
第五个参数:表示为了获得最佳的分类效果,算法要不同的初始分类尝试次数;
第六个参数:表示表示选择初始中心点选择方法用哪一种方法:
KMEANSRANDOMCENTERS 表示随机选择中心点
KMEANSPPCENTERS 基于中心化算法选择
KMEANSUSEINITIAL_LABELS第一次分类中心点用输入的中心点;
第七个参数:表示输出的每个分类的中心点数据;

#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char** argv) {
	Mat SrcImage = imread("1.jpg");
	imshow("原图", SrcImage);
	int width = SrcImage.cols;
	int height = SrcImage.rows;
	int dims = SrcImage.channels();
	int sampleCount = width*height;
	int clusterCount = 2;
	Mat points(sampleCount, dims, CV_32F, Scalar(10));
	Mat labels;
	Mat centers(clusterCount, 1, points.type());
	int index = 0;
	for (int row = 0; row < height; row++) {
		for (int col = 0; col < width; col++) {
			index = row*width + col;
			Vec3b rgb = SrcImage.at<Vec3b>(row, col);
			points.at<float>(index, 0) = static_cast<int>(rgb[0]);
			points.at<float>(index, 1) = static_cast<int>(rgb[1]);
			points.at<float>(index, 2) = static_cast<int>(rgb[2]);
		}
	}
	TermCriteria criteria = TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 10, 1.0);
	kmeans(points, clusterCount, labels, criteria, 3, KMEANS_PP_CENTERS, centers);
	Mat result = Mat::zeros(SrcImage.size(), CV_8UC3);
	for (int row = 0; row < height; row++) {
		for (int col = 0; col < width; col++) {
			index = row*width + col;
			int label = labels.at<int>(index, 0);
			if (label == 1) {
				result.at<Vec3b>(row, col)[0] = 0;
				result.at<Vec3b>(row, col)[1] = 0;
				result.at<Vec3b>(row, col)[2] = 0;
			}
			else if (label == 0) {
				result.at<Vec3b>(row, col)[0] = 255;
				result.at<Vec3b>(row, col)[1] = 255;
				result.at<Vec3b>(row, col)[2] = 255;
			}
		}
	}
	imshow("聚类结果", result);
	waitKey(0);
	return 0;
}

结果:

这里写图片描述

这里写图片描述

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值