opencv中的Kmeans使用示例
kmeans是非常经典的聚类算法,至今也还保留着较强的生命力,图像处理中经常用到kmeans算法或者其改进算法进行图像分割操作,在数据挖掘中kmeans经常用来做数据预处理。opencv中提供了完整的kmeans算法,其函数原型为:
double kmeans( InputArray data, int K, InputOutputArray bestLabels, TermCriteria criteria, int attempts, int flags, OutputArray centers = noArray() );
其中data表示用于聚类的数据,是N维的数组类型(Mat型),必须浮点型;
K表示需要聚类的类别数;
bestLabels聚类后的标签数组,Mat型;
criteria迭代收敛准则(MAX_ITER最大迭代次数,EPS最高精度);
attemps表示尝试的次数,防止陷入局部最优;
flags 表示聚类中心的选取方式(KMEANS_RANDOM_CENTERS 随机选取,KMEANS_PP_CENTERS使用Arthur提供的算法,KMEANS_USE_INITIAL_LABELS使用初始标签);
centers 表示聚类后的类别中心。
关于kmeans的理论可以参考:基本Kmeans算法介绍及其实现
下面给出一个关于图像聚类的示例:
#include <opencv.hpp>
using namespace cv;
Scalar colorTab[] = //10个颜色
{
Scalar(0, 0, 255),
Scalar(0, 255, 0),
Scalar(255, 100, 100),
Scalar(255, 0, 255),
Scalar(0, 255, 255),
Scalar(255, 0, 0),
Scalar(255, 255, 0),
Scalar(255, 0, 100),
Scalar(100, 100, 100),
Scalar(50, 125, 125)
};
class ClusterPixels
{
private:
Mat image; //待聚类图像
Mat labels; //聚类后的标签
int clusterCounts; //分类数,不得大于10,只是颜色定义只有10类,并不是算法限制
public:
ClusterPixels() :clusterCounts(0){}
ClusterPixels(const Mat& src, int clusters = 5) :clusterCounts(clusters){ image = src.clone(); }
void setImage(const Mat& src){ image = src.clone(); };
void setClusters(int clusters){ clusterCounts = clusters; }
Mat getLabels() {return labels; }; //返回聚类后的标签
Mat clusterGrayImageByKmeans()
{
//转换成灰度图
if (image.channels() != 1)
cvtColor(image, image, COLOR_BGR2GRAY);
int rows = image.rows;
int cols = image.cols;
//保存聚类后的图片
Mat clusteredMat(rows, cols, CV_8UC3);
clusteredMat.setTo(Scalar::all(0));
Mat pixels(rows*cols, 1, CV_32FC1); //pixels用于保存所有的灰度像素
for (int i = 0; i < rows;++i)
{
const uchar *idata = image.ptr<uchar>(i);
float *pdata = pixels.ptr<float>(0);
for (int j = 0; j < cols;++j)
{
pdata[i*cols + j] = idata[j];
}
}
kmeans(pixels, clusterCounts, labels, TermCriteria(TermCriteria::EPS + TermCriteria::MAX_ITER, 10, 0), 5, KMEANS_PP_CENTERS);
for (int i = 0; i < rows;++i)
{
for (int j = 0; j < cols;++j)
{
circle(clusteredMat, Point(j,i), 1, colorTab[labels.at<int>(i*cols + j)]); //标记像素点的类别,颜色区分
}
}
return clusteredMat;
}
Mat clusterColorImageByKmeans()
{
assert(image.channels() != 1);
int rows = image.rows;
int cols = image.cols;
int channels = image.channels();
//保存聚类后的图片
Mat clusteredMat(rows, cols, CV_8UC3);
clusteredMat.setTo(Scalar::all(0));
Mat pixels(rows*cols, 1, CV_32FC3); //pixels用于保存所有的灰度像素
pixels.setTo(Scalar::all(0));
for (int i = 0; i < rows; ++i)
{
const uchar *idata = image.ptr<uchar>(i);
float *pdata = pixels.ptr<float>(0);
for (int j = 0; j < cols*channels; ++j)
{
pdata[i*cols*channels + j] = saturate_cast<float>(idata[j]);
}
}
kmeans(pixels, clusterCounts, labels, TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 10, 0), 5, KMEANS_PP_CENTERS);
for (int i = 0; i < rows; ++i)
{
for (int j = 0; j < cols*channels; j += channels)
{
circle(clusteredMat, Point(j/channels,i), 1, colorTab[labels.at<int>(i*cols + (j/channels))]); //标记像素点的类别,颜色区分
}
}
return clusteredMat;
}
};
主函数:
#include "clusterImagePixels.hpp"
int main()
{
Mat testImage = imread("E:\testImage\board.jpg");
if (testImage.empty())
{
return -1;
}
ClusterPixels clusterPix(testImage,3);
Mat colorResults = clusterPix.clusterColorImageByKmeans();
Mat grayResult = clusterPix.clusterGrayImageByKmeans();
if (!colorResults.empty())
{
hconcat(testImage, colorResults, colorResults);
imshow("clusterImage", colorResults);
}
if (!grayResult.empty())
{
hconcat(testImage, grayResult, grayResult);
imshow("grayCluster", grayResult);
}
if (waitKey() == 27)
return 0;
}效果图:
采用灰度聚类的结果:
采用RGB颜色聚类得到的效果图:
声明:该文观点仅代表作者本人,入门客AI创业平台信息发布平台仅提供信息存储空间服务,如有疑问请联系rumenke@qq.com。
- 上一篇: C语言操作大于2G的文件
- 下一篇:没有了
