在图像分割中,使用 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 }

最新文章

  1. sqlserver2008附加数据库时提示“无法为该请求检索数据。 (Microsoft.SqlServer.Management.Sdk.Sfc)”
  2. springMVC-mvc:annotation-driven
  3. linux dd命令实用详解
  4. chainOfResponsibility责任链模式
  5. 函数与关系实例,函数运算与SQL,试验与关系元组
  6. The 6th Zhejiang Provincial Collegiate Programming Contest-&gt;ProblemK:K-Nice
  7. iOS 使用fir、 蒲公英 进行内部测试
  8. 最全的ASP.NET开源CMS汇总
  9. GitHub 如何基於 Node.js 和 Chromium 開發 Atom?
  10. 应用 Valgrind 发现 Linux 程序的内存问题(转)
  11. java初级开发程序员(第六单元)
  12. Trusted Execution Technology (TXT) --- 启动控制策略(LCP)篇
  13. SAP MM &#39;独立/集中&#39;等于1的MTS物料MRP运行后合并需求触发PR
  14. centos7 tomcat8+jdk1.8
  15. POJ--3190 Stall Reservations(贪心排序)
  16. pyqt5-顶层窗口特定操作-图标和标题和不透明度
  17. 飞鱼星、H3C企业路由器配置
  18. TCP的TIME_WAIT快速回收与重用
  19. [转] 如何在 CentOS7 中使用阿里云的yum源
  20. Codeforces 714B. Filya and Homework

热门文章

  1. Three.js 实现虎年春节3D创意页面
  2. Sentry 开发者贡献指南 - Django Rest Framework(Serializers)
  3. 微服务架构 | 3.1 Netflix Eureka 注册中心
  4. springboot应用中使用CommandLineRunner
  5. Solon 开发,四、Bean 扫描的三种方式
  6. 【自写信息搜集工具】ThunderSearch开发原理解析
  7. log4j学习记录以及相关配置(精简版)
  8. jsp中获取下拉框的value问题
  9. 从故纸堆里,回顾下Web技术的发展历程
  10. 测试开发实战[提测平台]20-图表G2Plot在项目的实践实录