在图像分割中,使用 kmeans 算法可以实现图像区域基本分割。如果一幅图像被分为两类,kmeans 分割效果与  ostu 算法基本一致,具体如下图:

  

kmeans 将图像灰度聚类为 k 类,ostu 将图像灰度分割为 2 类,当 k = 2 时,两种算法最终目的基本趋于一致。

kmeans 算法基本思路如下:

1)随机选取第一个聚类中心点,之后的聚类中心点选取有两种方法;

a. 随机选取其他 k - 1 个聚类中心点;

b. 根据已经选取的聚类中心点,计算所有点到已经选取的聚类中心点的距离,选择到所有已经选取的聚类中心点的最远点作为下一个聚类中心点;

2)根据点到已经选取的聚类中心点的距离对其进行分类;

3)重新求各个分类的聚类中心点,然后回到 2);

4)当不再满足迭代条件时给出最终聚类结果,迭代条件包括:

a. 聚类中心点在迭代过程中的偏移量;

b. 迭代次数;

对于聚类中心点的选择,一般情况下,方法 b 会得到更好的聚类,且迭代速度较快。

opencv 提供的 kmean 函数为:

double kmeans( InputArray data, int K, InputOutputArray bestLabels, TermCriteria criteria, int attempts,

int flags, OutputArray centers=noArray() );

参数如下:

data: 待分类点矩阵,其类型必须为 CV_32F;

K,bestLabels: 聚类数与待分类点所属分类;

criteria:停止条件;

attempts:使用不同的随机聚类中心点尝试聚类次数;

flags:聚类中心点选择方案,包括完全随机选择,kmeans++选择方案(b),用户输入;

centers:最终聚类中心点;

以下给出 kmeans 算法使用代码:

 1 void UseKmeans(cv::Mat& src, cv::Mat& rst)
2 {
3 int width = src.cols;
4 int height = src.rows;
5 int dims = src.channels();
6 int sampleCount = width * height;
7
8 int clusterCount = 2;
9 Mat points(sampleCount, dims, CV_32F, Scalar(10));
10 cv::Mat pos(sampleCount, 2, CV_16S, Scalar(0, 0));
11 Mat labels;
12 Mat centers(clusterCount, 1, points.type());
13
14 // invert to data points
15 int index = 0;
16 for (int row = 0; row < height; row++) {
17 for (int col = 0; col < width; col++) {
18 points.at<float>(index, 0) = static_cast<int>(src.ptr<uchar>(row)[col]);
19 pos.at<short>(index, 0) = static_cast<short>(row);
20 pos.at<short>(index, 1) = static_cast<int>(col);
21 ++index;
22 }
23 }
24
25 // k-mean algorithm
26 TermCriteria criteria = TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 100, 1.0);
27 kmeans(points, clusterCount, labels, criteria, 3, KMEANS_PP_CENTERS, centers);
28
29 int bright_val = -1;
30 for (int i = 0; i < centers.rows; ++i)
31 {
32 int val = centers.at<float>(i, 0);
33 if (val > bright_val)
34 bright_val = val;
35 }
36
37 int bright_label = -1;
38 for (int idx = 0; idx < sampleCount; ++idx)
39 {
40 float *datapoint = points.ptr<float>(idx);
41 int *datalabel = labels.ptr<int>(idx);
42 if (datapoint[0] >= bright_val)
43 {
44 bright_label = datalabel[0];
45 break;
46 }
47 }
48
49 // save result
50 rst.create(src.size(), CV_8UC1);
51 rst.rowRange(0, rst.rows) = 0;
52 for (int idx = 0; idx < sampleCount; ++idx)
53 {
54 int *datalabel = labels.ptr<int>(idx);
55 if (datalabel[0] == bright_label)
56 {
57 int row = pos.at<short>(idx, 0);
58 int col = pos.at<short>(idx, 1);
59 rst.ptr<uchar>(row)[col] = 255;
60 }
61 }
62 }

opencv笔记--Kmeans的更多相关文章

  1. OpenCV笔记大集锦(转载)

    整理了我所了解的有关OpenCV的学习笔记.原理分析.使用例程等相关的博文.排序不分先后,随机整理的.如果有好的资源,也欢迎介绍和分享. 1:OpenCV学习笔记 作者:CSDN数量:55篇博文网址: ...

  2. opencv笔记6:角点检测

    time:2015年10月09日 星期五 23时11分58秒 # opencv笔记6:角点检测 update:从角点检测,学习图像的特征,这是后续图像跟踪.图像匹配的基础. 角点检测是什么鬼?前面一篇 ...

  3. opencv笔记5:频域和空域的一点理解

    time:2015年10月06日 星期二 12时14分51秒 # opencv笔记5:频域和空域的一点理解 空间域和频率域 傅立叶变换是f(t)乘以正弦项的展开,正弦项的频率由u(其实是miu)的值决 ...

  4. opencv笔记4:模板运算和常见滤波操作

    time:2015年10月04日 星期日 00时00分27秒 # opencv笔记4:模板运算和常见滤波操作 这一篇主要是学习模板运算,了解各种模板运算的运算过程和分类,理论方面主要参考<图像工 ...

  5. opencv笔记3:trackbar简单使用

    time:2015年 10月 03日 星期六 13:54:17 CST # opencv笔记3:trackbar简单使用 当需要测试某变量的一系列取值取值会产生什么结果时,适合用trackbar.看起 ...

  6. opencv笔记2:图像ROI

    time:2015年 10月 03日 星期六 12:03:45 CST # opencv笔记2:图像ROI ROI ROI意思是Region Of Interests,感兴趣区域,是一个图中的一个子区 ...

  7. opencv笔记1:opencv的基本模块,以及环境搭建

    opencv笔记1:opencv的基本模块,以及环境搭建 安装系统 使用fedora22-workstation-x86_64 安装opencv sudo dnf install opencv-dev ...

  8. OpenCV: Kmeans的使用一维和二维点集

    OpenCVKmeans算法默认使用了Kmeans++选取种子点 参考:OpenCv中Kmeans算法实现和使用 //效果:根据半径聚类,并不一定能得到好的结果. float CBlotGlint:: ...

  9. OpenCV基本架构[OpenCV 笔记0]

    最近正在系统学习OpenCV,将不定期发布笔记,主要按照毛星云的<OpenCV3编程入门>的顺序学习,会参考官方教程和文档.学习工具是Xcode+CMake,会对书中一部分内容更正,并加入 ...

随机推荐

  1. vim 安装使用 pathogen

    目录 pathogen 是什么? 如何安装? pathogen 是什么? pathogen 一般作为 vim 新手的第一个插件,用来统一管理 vim 插件包. (官方解释)非常容易地管理你的 'run ...

  2. 实验 6 :OpenDaylight 实验——OpenDaylight 及 Postman实现流表下发

    实验 6 :OpenDaylight 实验--OpenDaylight 及 Postman实现流表下发 一.实验目的 熟悉 Postman 的使用:熟悉如何使用 OpenDaylight 通过 Pos ...

  3. 一文搞懂Flink Window机制

    Windows是处理无线数据流的核心,它将流分割成有限大小的桶(buckets),并在其上执行各种计算. 窗口化的Flink程序的结构通常如下,有分组流(keyed streams)和无分组流(non ...

  4. 基于Dapper的分布式链路追踪入门——Opencensus+Zipkin+Jaeger

    微信搜索公众号 「程序员白泽」,进入白泽的编程知识分享星球 最近做了一些分布式链路追踪有关的东西,写篇文章来梳理一下思路,或许可以帮到想入门的同学.下面我将从原理到demo为大家一一进行讲解,欢迎评论 ...

  5. 一键AI着色,黑白老照片画面瞬间鲜活

    很多老照片或者电影受时代技术所限制,只能以黑白形式保存:经过编辑后的黑白视频和图片早已丢失彩色原图,这对于保存者来说都十分遗憾.如何能将单一乏味.陈旧斑驳的黑白照片变成鲜活亮丽的彩色照片,从照片中重新 ...

  6. python中的sort方法和sorted方法

    一.sort()函数 描述 sort() 函数用于对原列表进行排序,如果指定参数,则使用比较函数指定的比较函数. 语法 sort()方法语法: 1 list.sort(cmp=None, key=No ...

  7. Web开发之Cookie and Session

    会话 什么是会话? 简单说:用户开一个浏览器,点击多个超链接,访问服务器的多个web资源,然后关闭浏览器,整个过程就称之为一个会话. 会话过程要解决什么问题 每个用户在使用浏览器与服务器进行会话的过程 ...

  8. Android官方文档翻译 十五 3.3Supporting Different Platform Versions

    Supporting Different Platform Versions 支持不同的平台版本 This lesson teaches you to 这节课教给你 Specify Minimum a ...

  9. [学习分享] 在Windows操作系统下如何安装RMySQL包

    最近在做股票的高频交易数据分析,需要用到数据库,而我只对MySQL比较熟悉,于是就安装了MySQL.当我安装好了MySQL后,正兴冲冲地准备安装RMySQL包时,问题来了:RMySQL包不支持wind ...

  10. Android官方文档翻译 九 2.2Adding Action Buttons

    Adding Action Buttons 增加动作按钮 This lesson teaches you to 这节课教给你 Specify the Actions in XML 在XML中指定动作 ...