k-means提取图像主色(手写)
2017-03-18 09:53
218 查看
一、k-means算法
k-means算法是一种简单有效的聚类算法。根据制定的类别数k,将所给数据集,以一定的距离(用户自定义距离,如本文采用是RGB图像每点的欧式距离)相近程度进行类别划分,可以理解为一种求质心的聚类方式。
算法基本流程如下:
1、随机产生k个聚类中心(也可用户指定)。计算每个样本到各个聚类中心的距离。将样本归类到相应最接近的类别中。
2、计算每个样本的算数平均数,求出每一类中离平均数最近的点记为该类新的中心。
3、判断所有类别中中心点有没有发生变化,如果中心点改变,则再次以该中心点对所有数据聚类,直到所有的中心点都不改变为止,算法结束。
二、c++实现
三、程序结果
src: 原图像 lab: 划分区域 dst: 提取的颜色
k-means算法是一种简单有效的聚类算法。根据制定的类别数k,将所给数据集,以一定的距离(用户自定义距离,如本文采用是RGB图像每点的欧式距离)相近程度进行类别划分,可以理解为一种求质心的聚类方式。
算法基本流程如下:
1、随机产生k个聚类中心(也可用户指定)。计算每个样本到各个聚类中心的距离。将样本归类到相应最接近的类别中。
2、计算每个样本的算数平均数,求出每一类中离平均数最近的点记为该类新的中心。
3、判断所有类别中中心点有没有发生变化,如果中心点改变,则再次以该中心点对所有数据聚类,直到所有的中心点都不改变为止,算法结束。
二、c++实现
#define CLUST_NUM 5 struct Node { CvPoint point; CvScalar color; }; struct Clust { Node center; vector<Node> buff; }; void DCD(IplImage* src) { IplImage* src = NULL; src = cvLoadImage("test.jpg"); if(!src) { return; } int width = src->width; int height = src->height; // 产生随机种子 CvPoint point[CLUST_NUM]; CvRNG rng(cvGetTickCount()); for (int i = 0; i< CLUST_NUM; i++) { point[i].x = cvRandInt(&rng) % width; point[i].y = cvRandInt(&rng) % height; } //分类簇 Clust v[CLUST_NUM]; //初始化 for (int i = 0; i < CLUST_NUM; i++) { v[i].center.point = point[i]; v[i].center.color = cvGet2D(src, v[i].center.point.y, v[i].center.point.x); cout << point[i].x << ":" << point[i].y << endl; Node node; node.point = v[i].center.point; node.color = v[i].center.color; v[i].buff.push_back(node); } do { for (int rows = 0; rows < height; rows++) { uchar* ptr = (uchar*)src->imageData + src->widthStep*rows; for (int cols = 0; cols < width; cols++) { int b, g, r; b = ptr[cols*src->nChannels + 0]; g = ptr[cols*src->nChannels + 1]; r = ptr[cols*src->nChannels + 2]; //计算每个像素到达每个簇的中心距离 double dis[CLUST_NUM] = { 0.0 }; for (int i = 0; i < CLUST_NUM; i++) { dis[i] = (v[i].center.color.val[0] - b)*(v[i].center.color.val[0] - b) + (v[i].center.color.val[1] - g)*(v[i].center.color.val[1] - g) + (v[i].center.color.val[2] - r)*(v[i].center.color.val[2] - r); dis[i] = sqrt(dis[i]); } //获取该像素点离的最近的簇的编号 int minDisClustId = 0; int i = 0; for (i = 1; i < CLUST_NUM; i++) { if (dis[ 97b8 i] < dis[minDisClustId]) { minDisClustId = i; } } Node node; node.color.val[0] = b; node.color.val[1] = g; node.color.val[2] = r; node.point.x = cols; node.point.y = rows; v[minDisClustId].buff.push_back(node); } } for (int i = 0; i < CLUST_NUM; i++) { double avgR = 0.0; double avgG = 0.0; double avgB = 0.0; //计算每一簇的平均RGB vector<Node>::iterator it = v[i].buff.begin(); while (it != v[i].buff.end()) { avgB += it->color.val[0]; avgG += it->color.val[1]; avgR += it->color.val[2]; it++; } avgB /= v[i].buff.size(); avgG /= v[i].buff.size(); avgR /= v[i].buff.size(); //获得距离平均RGB最近的点 it = v[i].buff.begin(); double curDis = 0.0; double minDis = 0.0; int curId = 0; int minId = 0; while (it != v[i].buff.end()) { if (it == v[i].buff.begin()) { minDis = (it->color.val[0] - avgB)*(it->color.val[0] - avgB) + (it->color.val[1] - avgG)*(it->color.val[1] - avgG) + (it->color.val[2] - avgR)*(it->color.val[2] - avgR); minDis = sqrt(minDis); minId = 0; it++; } else { curDis = (it->color.val[0] - avgB)*(it->color.val[0] - avgB) + (it->color.val[1] - avgG)*(it->color.val[1] - avgG) + (it->color.val[2] - avgR)*(it->color.val[2] - avgR); curDis = sqrt(curDis); if (curDis < minDis) { minDis = curDis; minId = it - v[i].buff.begin(); } it++; } } //获得新的每一簇的中心点 v[i].center.point = v[i].buff.at(minId).point; v[i].center.color = v[i].buff.at(minId).color; } //检查终止条件 是否所有的中心点都没有改变 int flg = 0; for (int i = 0; i < CLUST_NUM; i++) { for (int j = 0; j < CLUST_NUM; j++) { if (point[i].x == v[j].center.point.x && point[i].y == v[j].center.point.y) { flg++; break; } } } if (flg == CLUST_NUM) { break; } //清空每一簇的点 保留中心点 for (int i = 0; i < CLUST_NUM; i++) { cout << v[i].center.point.x << ":" << v[i].center.point.y << "size:" << v[i].buff.size() << endl; v[i].buff.clear(); //中心点进入对应的簇 Node node; node.point = v[i].center.point; node.color = v[i].center.color; v[i].buff.push_back(node); point[i] = v[i].center.point; } cout << "*" << endl; } while (1); IplImage* dst = NULL; IplImage* lab = NULL; dst = cvCreateImage(cvGetSize(src), src->depth, src->nChannels); lab = cvCreateImage(cvGetSize(src), src->depth, src->nChannels); if(!dst ||!lab) { reurn; } for (int i = 0; i < CLUST_NUM; i++) { CvScalar color; color = v[i].center.color; cvSetImageROI(dst, cvRect(i*src->width / CLUST_NUM, 0, src->width / CLUST_NUM, src->height)); cvSet(dst, color); cvResetImageROI(dst); vector<Node>::iterator it = v[i].buff.begin(); while (it != v[i].buff.end()) { cvSet2D(lab, it->point.y, it->point.x, v[i].center.color); it++; } } cvShowImage("src", src); cvShowImage("dst", dst); cvShowImage("lab", lab); cvReleaseImage(&src); cvReleaseImage(&dst); cvReleaseImage(&lab); cvWaitKey(0); return; }
三、程序结果
src: 原图像 lab: 划分区域 dst: 提取的颜色
相关文章推荐
- k-means提取图像主色(调用opencv-kmeans)
- 图像主色的提取
- opencv 提取轮廓大于某个阈值的图像
- C#数字图像处理有3种典型方法:提取像素法、内存法、指针法。
- 图像二值化、提取边缘
- 图像特征提取三大法宝:HOG特征,LBP特征,Haar特征
- 把DICOM文件中的图像部分提取到BMP文件的函数
- 图像特征提取方法
- Codrops 实验:使用 Vibrant.js 提取图像颜色
- 目标检测的图像特征提取之(一)HOG特征
- VTK修炼之道27:图像基本操作_三维图像切片交互提取(回调函数、观察者-命令模式)
- pdf和图像文字识别提取工具
- OTSU算法提取图像阈值的C语言实现
- 目标检測的图像特征提取之(一)HOG特征
- opencv数字图像基础,提取图像像素,遍历图像
- canny边缘提取之二 高斯图像滤波
- 快速扫描算法提取鱼眼图像有效区域
- 目标检测的图像特征提取之HOG特征
- 图像处理中项目代码合集,包括特征提取-图像分割-分类-匹配-降噪等等
- [置顶] 基于opencv-3.4.0的图像特征点提取及图像匹配(Java 版)