欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Opencv之kmeans图像分割

程序员文章站 2024-03-25 08:09:34
...
int imageSeg_kmeans()
{
	string image_path = "D:/vs2019Proj/ConsoleApplication1/timg.jpg";
	Mat src_image = imread(image_path);
	if (!src_image.data)
	{
		cout << "could not load image.." << endl;
		return -1;
	}
	//颜色板
	vector<Scalar> colorTab = {
		{0,0,255},
		{0,255,0},
		{255,0,0},
		{255,255,0},
		{0,255,255},
		{255,0,255}
	};
	int width = src_image.cols;
	int height = src_image.rows;
	int chnes = src_image.channels();
	//把彩色图像中的数据点提取出来放入points里面
	//points的类型是CV_32F
	Mat points(width * height, chnes, CV_32F,Scalar(10));
	for (int row = 0; row < height; row++)
	{
		uchar* ptr = src_image.ptr<uchar>(row);
		for (int col = 0; col < width* chnes; col+= chnes)
		{
			int index = row * width + col/chnes;
			float* ptr_points = points.ptr<float>(index);
			ptr_points[0] = static_cast<int>(ptr[col]);//B
			ptr_points[1] = static_cast<int>(ptr[col+1]);//G
			ptr_points[2] = static_cast<int>(ptr[col+2]);//R
		}
	}
	//设置kmeans的参数,执行kmeans
	//clusters 表示要把图像分割为几类
	int clusters = 2;
	//attempts 表示要在图像上尝试几次kmeans计算,因为可能会存在起始点选择不太好的情况,所以要多尝试几次
	int attempts = 3;
	//flags 表示选取中心点的方法,clusters为几就要选取多少个中心点
	int flags = cv::KMEANS_PP_CENTERS;
	//centers 记录迭代完成后中心点的位置
	Mat centers(clusters, 1, points.type());
	//label 记录每一个像素点所属的类别
	Mat label;
	//critreia kmeans算法的终止条件
	//TermCriteria::EPS 迭代算法停止时要达到的精度
	//TermCriteria::COUNT 表示最大迭代次数
	TermCriteria critreia = TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 0.1);
	kmeans(points, clusters, label, critreia, attempts, flags, centers);
	//处理kmeans的结果,即处理label,并且还原为分割图像
	//label数据结构是width*height行,1列,每一行表示一个像素点的类别
	Mat result = Mat::zeros(src_image.size(), src_image.type());
	for (int row = 0; row < height; row++)
	{
		uchar* ptr = result.ptr<uchar>(row);
		for (int col = 0; col < width*3; col+=3)
		{
			int index = label.at<int>(row * width + col / 3, 0);
			ptr[col] = colorTab[index][0];
			ptr[col + 1] = colorTab[index][1];
			ptr[col + 2] = colorTab[index][2];
		}
	}
	//输出每一种分割类别的中心点
	for (int i = 0; i < centers.rows; i++)
	{
		int x = centers.at<float>(i, 0);
		int y = centers.at<float>(i, 1);
		cout << "center " << i << ":" << x << " " << y << endl;
	}
	imshow("result", result);
	imshow("srcimage", src_image);
}