OpenCv-C++-02-KMeans-图像分割

关于KMeans上一篇文章有提到,也用了一些随机点进行数据分类,那么图像呢?图像也是一堆数据,我们只需要把1图像转变为一组数据即可进行数据分类,然后重新显示在图像上,这就是图像分割。
代码部分与上一章文章没多大区别,只需稍作改动即可:

#include<opencv2/opencv.hpp>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char** argv)
{
	Mat src = imread("F:/test/lena.jpg");
	if (!src.data)
	{
		printf("图片未找到!\n");
		return -1;
	}
	imshow("input image", src);
	int width = src.cols; //图像宽
	int height = src.rows; //图像高
	int channels = src.channels(); //通道数
	Scalar colorTab[] = {    //定义颜色数组
		Scalar(0,0,255),
		Scalar(255,0,255),
		Scalar(0,255,0),
		Scalar(255,0,0),
		Scalar(0,255,255),
	};
	//初始化定义
	int clusterCount = 4;//4分类
	int sampleCount = width * height;//样本点数量
	Mat points(sampleCount, channels, CV_32F, Scalar(10));
	Mat labels;
	Mat centers(clusterCount, 1, points.type());

	//RGB转换到样本数据
	int index = 0;
	for (int row = 0; row < src.rows; row++)
	{
		for (int col = 0; col < src.cols; col++)
		{
			index = row * width + col;
			Vec3b bgr = src.at<Vec3b>(row, col);
			//获取每个通道的值
			points.at<float>(index, 0) = static_cast<int>(bgr[0]);
			points.at<float>(index, 1) = static_cast<int>(bgr[1]);
			points.at<float>(index, 2) = static_cast<int>(bgr[2]);
		}
	}
	//运行KMeans
	TermCriteria cirteria = TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 0.1);
	kmeans(points, clusterCount, labels, cirteria, 3, KMEANS_PP_CENTERS, centers);
	
	//显示图像分割结果

	Mat result = Mat::zeros(src.size(), src.type());
	for (int row = 0; row < src.rows; row++)
	{
		for (int col = 0; col < src.cols; col++)
		{
			index = row * width + col;
			int label = labels.at<int>(index,0);

			result.at<Vec3b>(row, col)[0] = colorTab[label][0];  
			result.at<Vec3b>(row, col)[1] = colorTab[label][1];
			result.at<Vec3b>(row, col)[2]= colorTab[label][2];
		}
	}

	
	imshow("result", result);
	waitKey(0);
	return 0;
}



运行结果:
在这里插入图片描述
分割后的结果:
在这里插入图片描述

发布了88 篇原创文章 · 获赞 39 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/Daker_Huang/article/details/89320942
今日推荐