利用k-means算法对灰度图像分割

本文主要利用k-means来对灰度图像进行分割。首先对k-means进行简单的介绍,然后直接上代码。那么什么是k-means算法?K-means算法是硬聚类算法,是典型的基于原型的目标函数聚类方法的代表,它是数据点到原型的某种距离作为优化的目标函数,利用函数求极值的方法得到迭代运算的调整规则。K-means算法以欧式距离作为相似度测度,它是求对应某一初始聚类中心向量V最优分类,使得评价指标J最小。算法采用误差平方和准则函数作为聚类准则函数。这是百度百科的介绍,说了这么多,其实作者也不知道百度百科在说啥,那就来看看基本的算法步骤吧。基本的算法步骤如下:
1. 从N个样本随机选取K个文本作为质心;
2. 对剩余每个样本测量其到每个质心的距离,并把它归到最近的质心类
3. 重新计算已经得到的各个类的质心;
4. 迭代2、3步骤直至新的质心与原质心相等或小于指定的阈值,算法结束。
这下算法就比较清晰,下面直接贴代码,我的代码主要定义了point.h头文件、kmeans.h头文件和kmeans.cpp源文件。下面是point.h文件的代码。

#ifndef POINT_H
#define POINT_H
//point结构主要用来存储图像中节点的横坐标,纵坐标以及灰度值
struct point
{int row;int col;double pixVal;point(int row, int col, double pixVal) :row(row),col(col),pixVal(pixVal) {}
};
#endif

接下来,是keams.h头文件:

#ifndef KMEANS_H
#define KMEANS_H#include<opencv2\opencv.hpp>
#include<random>
#include<time.h>
#include<stdio.h>
#include<stdlib.h>
#include<list>
#include<iostream>
#include<math.h>
#include"point.h"using namespace cv;
using namespace std;class Kmeans{
private://存储所有点vector<point> points;//存储簇的中心点vector<point> centers;//存储每个点到相应的簇vector<point>* clusters;//向量的维数int dimension;//簇的个数int k;
public://构造函数Kmeans(vector<point> points, vector<point> centers, int k, int dimension){this->points = points;this->centers = centers;this->dimension = dimension;this->k = k;clusters = new vector<point>[k];}//析构函数~Kmeans(){delete clusters;}//获取簇vector<point>* getClusters(){return this->clusters;}//计算两个向量之间的欧式距离double getDistanceBetweenTwoPoints(const point& point1, const point& point2){double sum = 0;//double tmp;//for (int i = 0; i < dimension; i++)//{//tmp = pow(point1.pixVal - point2.pixVal,2);//sum += tmp;//}sum = pow(point1.pixVal - point2.pixVal, 2);return sqrt(sum);}//计算每个点到离它最近的簇中心点,结果保存到vector中vector<int> getClosetClusterCenterLabel(){double min;int label;vector<int> labels;for (int i = 0; i < points.size(); i++){label = 0;min = getDistanceBetweenTwoPoints(points[i], centers[0]);for (int j = 1; j < centers.size(); j++){double tmp = getDistanceBetweenTwoPoints(points[i], centers[j]);if (tmp < min){min = tmp;label = j;}}labels.push_back(label);}return labels;}//将每个点放入它离的最近的中心点对应的簇中void computeClusters(const vector<int>& labels){for (int i = 0; i < k; i++){clusters[i].clear();}for (int i = 0; i < labels.size(); i++){int label = labels[i];clusters[label].push_back(points[i]);}}//重新计算所有簇的中心点的灰度值void computeCenters(){centers.clear();for (int i = 0; i < k; i++){double sum = 0;for (int j = 0; j < clusters[i].size(); j++){sum += clusters[i][j].pixVal;}double meanVal = sum / clusters[i].size();point cp(-1, -1, meanVal);centers.push_back(cp);}}//确定新的中心点后重新计算一次costdouble computeCost(){double sum = 0;for (int i = 0; i < k; i++){vector<point> tmpVec=clusters[i];for (int j = 0; j < tmpVec.size(); j++){sum += getDistanceBetweenTwoPoints(tmpVec[j], centers[i]);}}return sum / points.size();}//迭代执行k-means算法的步骤void kmeans(){double oldCost, newCost;vector<int> labels=getClosetClusterCenterLabel();computeClusters(labels);newCost = computeCost();computeCenters();labels = getClosetClusterCenterLabel();computeClusters(labels);oldCost = newCost;newCost = computeCost();while (oldCost != newCost){oldCost = newCost;computeCenters();labels = getClosetClusterCenterLabel();computeClusters(labels);newCost = computeCost();}cout <<"Final Cost: "<< newCost << endl;}
};
#endif

接下来,是测试的kmeans.cpp文件:

#include "kmeans.h"
//图片的存放位置
const String imageFolder = "F:\\";
//簇的个数(即k的大小,根据自己需要调整)
const int numOfCluster =4;
//最大像素值
const int MAX_PIX_VALUE = 255;
//存放所有点
vector<point> points;
//存放所有簇中心
vector<point> centers;
//存放所有点颜色特征(i,j)->i*rows+j
vector<double> pixVec;//读取图像
Mat readImage(String imageName)
{String imageLoc = imageFolder + imageName;Mat image=imread(imageLoc);return image;
}//初始化k-means聚类中心
void initializeCenters(const Mat& img)
{srand((unsigned)time(NULL));for (int i = 0; i < numOfCluster; i++){int randomX = rand() % img.rows;int randomY = rand() % img.cols;uchar pixVal = img.at<uchar>(randomX, randomY);point cp(randomX, randomY, (double)pixVal);centers.push_back(cp);}
}//将图像中的所有点装入points中
void initializePoints(const Mat& img)
{for (int i = 0; i < img.rows; i++){const uchar* data = img.ptr<uchar>(i);for (int j = 0; j < img.cols; j++){uchar pixVal = data[j];point p(i,j, (double)pixVal);points.push_back(p);}}
}int main()
{String imageName = "lena.jpg";Mat img = readImage(imageName);cvtColor(img, img, CV_RGB2GRAY);//转化为灰度图像namedWindow(imageName,WINDOW_NORMAL);imshow(imageName, img);waitKey(0);int rows = img.rows;int cols = img.cols;initializeCenters(img);initializePoints(img);Kmeans* km=new Kmeans(points, centers, numOfCluster, 1);cout << "---------------k-means start-------------" << endl;km->kmeans();cout << "---------------k-means end---------------" <<endl;vector<point>* clusters = km->getClusters();Mat res(img.rows,img.cols,img.type());double div = MAX_PIX_VALUE / numOfCluster;for (int i = 0; i < numOfCluster; i++){vector<point> tmpVec = clusters[i];for (int j = 0; j < tmpVec.size(); j++){res.at<uchar>(tmpVec[j].row, tmpVec[j].col) = i*div;}}namedWindow("kmeansResult",WINDOW_NORMAL);imshow("kmeansResult", res);waitKey(0);imwrite("./segment_lena.jpg", res);system("pause");
}

下面是测试结果:

  • 原图

  • 结果

    上面的代码改一下,还可以利用k-means做对彩色图像的分割,通过把图像的单灰度值改为彩色像素点的三通道向量表示。目前,我还没有尝试,有兴趣的朋友可以去做做,和我分享!

利用k-means算法对灰度图像分割相关推荐

  1. kmeans改进 matlab,基于距离函数的改进k―means 算法

    摘要:聚类算法在自然科学和和社会科学中都有很普遍的应用,而K-means算法是聚类算法中经典的划分方法之一.但如果数据集内相邻的簇之间离散度相差较大,或者是属性分布区间相差较大,则算法的聚类效果十分有 ...

  2. k means算法C语言伪代码,K均值算法(K-Means)

    1. K-Means算法步骤 算法步骤 收敛性定义,畸变函数(distortion function): 伪代码: 1) 创建k个点作为K个簇的起始质心(经常随机选择) 2) 当任意一个点的蔟分配结果 ...

  3. k均值聚类算法(K Means)及其实战案例

    算法说明 K均值聚类算法其实就是根据距离来看属性,近朱者赤近墨者黑.其中K表示要聚类的数量,就是说样本要被划分成几个类别.而均值则是因为需要求得每个类别的中心点,比如一维样本的中心点一般就是求这些样本 ...

  4. 机器学习第七章之K近邻算法

    K近邻算法(了解) 7.1 K近邻算法 7.1.1 K近邻算法的原理介绍 7.1.2 K近邻算法的计算步骤及代码实现 7.2 数据预处理之数据归一化 7.2.1 min-max标准化 7.2.2 Z- ...

  5. 机器学习:k近邻算法(KNN)介绍

    k近邻算法是一种最简单最经典的机器学习算法之一.该算法的原理为:当对测试样本进行分类时,首先通过扫描训练样本集,找到与该测试样本最相似的k个训练样本,根据这个样本的类别进行投票确定测试样本的类别.也可 ...

  6. 机器学习算法系列之K近邻算法

    本系列机器学习的文章打算从机器学习算法的一些理论知识.python实现该算法和调一些该算法的相应包来实现. 目录 K近邻算法 一.K近邻算法原理 k近邻算法 通俗解释 近邻距离的度量 k值的选择 KN ...

  7. K means 图片压缩

    k-means的基本原理较为清晰,这里不多赘述,本次博客主要通过基础的k means算法进行图像的压缩处理. 原理分析 在彩色图像中,每个像素的大小为3字节(RGB),可以表示的颜色总数为256 * ...

  8. 机器学习:K近邻算法

    一.K-近邻算法简介 1 什么是K-近邻算法 根据你的"邻居"来推断出你的类别 1.1 K-近邻算法(KNN)概念 K Nearest Neighbor算法又叫KNN算法,这个算法 ...

  9. 机器学习算法——系统性的学会使用 K近邻算法(KNN)

    目录 1.K-近邻算法简介 1.1 什么是K-近邻算法 1.2 K-近邻算法(KNN)概念 (1)定义: (2)距离公式: 1.3 电影类型分析 1.4 KNN算法流程总结 2.k近邻算法api初步使 ...

最新文章

  1. 日常开发中常用到哪些设计模式
  2. (2006, 'MySQL server has gone away') 错误解决 - dba007的空间 - 51CTO技术博客
  3. Atlas study:使用Accordion实现页面多个块状区域的显隐
  4. 云调用,小程序鉴权正确姿势
  5. Android怎么导入Moudle
  6. [资料整理]记一下英特尔atom处理器
  7. php 钉钉 免登,免登的正确使用方式
  8. python import py文件权限_python 常见问题:导入py文件易忽略问题
  9. 简单解决网课或教育平台在线学习视频鼠标检测问题
  10. pdf论文中查看使用的字体
  11. Corel VideoStudio X7 (64bit)安装
  12. html drag 例子,html5 drag事件用法
  13. ArcMap制作TPK文件
  14. 20172302 《Java软件结构与数据结构》第五周学习总结
  15. Nginx Proxy Cache原理和最佳实践
  16. Amlogic连续三年居中国OTT芯片市占率第一
  17. php 获取到当前ip,获取当前IP地址,跳转到对应城市网站。
  18. [DonkeyCar][树莓派]基础01 - 首次配置 - WIFI
  19. verilog中一文搞懂有限状态机(FSM)Mealy和Moore状态机(及一段式,二段式,三段式)
  20. python hadoop wordcount_在Hadoop上用Python实现WordCount

热门文章

  1. 学java 安卓还是ios开发_非计算机科班出身,有JAVA基础,问学安卓开发还是IOS开发好些?...
  2. 小试Python中的pack()方法
  3. HDOJnbsp;4278nbsp;nbsp;Faultynbsp;Odometer
  4. Java学习笔记 算法 Algorithms Fourth Edition
  5. “文件创建错误-参数错误”解决办法
  6. vue脚手架图片懒加载模块和样式穿透
  7. 【渝粤题库】陕西师范大学202511商法学 作业(高起本)
  8. python 中list+=[1]与list =list+[1]
  9. VMware Workstation 虚拟机安装
  10. linux sftp创建多用户,Linux 下创建 sftp 用户并限定目录