K-means (代碼)

K-means是一种用于分群集的算法,通过计算点与群集中心的距离来分配点,并不断更新群集中心,直到中心变化较小或不变。这篇博客提供了详细解释和C++代码示例,演示如何在OpenCV中对灰阶图片中的白灰点进行处理和分群集。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

簡單來說這就是一個分群集的演算法。
詳細說明可以參考:

https://jason-chen-1992.weebly.com/home/-k-means-clustering
https://edisonx.pixnet.net/blog/post/84122954
https://dotblogs.com.tw/dragon229/2013/02/04/89919

程式步驟(假設分3群集):

  1. 隨機產生3個群集中心
  2. 計算這些點離群集中心的距離,並分配這些點給較近的群集中心
  3. 重新計算群中心距離
  4. 循環2-3步驟,直至群集中心不變或者變動較小為止。

代碼如下:

#include<opencv2/opencv.hpp>
#include<iostream>
#include <cstdlib> /* 亂數相關函數 */
#include <ctime>   /* 時間相關函數 */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>

using  namespace cv;
using namespace std;
#define K_GROUP 4
Mat srcImage, grayImage;
int k_cnt = 0;
int max_x, min_x;
void K_Manes(Point *kp, int k_group);

int main()
{

	char k_first_Flag = 0;
	Point K_center[K_GROUP];

	srcImage = imread("C:\\Users\\User\\Downloads\\Image\\1cm.bmp");
	cvtColor(srcImage, grayImage, CV_RGB2GRAY);

	//get point range
	for (int x = 0; x < grayImage.rows; x++)
	{
		for (int y = 0; y < grayImage.cols; y++)
		{
			if (grayImage.ptr<uchar>(x)[y] != 0)
			{
				if (k_first_Flag == 0)
				{
					k_first_Flag = 1;
					min_x = x;
				}
				max_x = x;
				k_cnt++;//get total point
			}
		}
	}

	printf("min_x=%d\n", min_x);
	printf("max_x=%d\n", max_x);

	//get rand point
	int lx, ly;
	srand(time(NULL));
	for (int i = 0; i < K_GROUP; i++)
	{
		lx = rand() % (max_x - min_x + 1) + min_x;
		printf("lx=%d\n", lx);
		ly = (rand() % grayImage.cols) + 1;
		K_center[i].x = lx;
		K_center[i].y = ly;
		printf("ly=%d\n", ly);
	}


	//k_manes calculate
	K_Manes(K_center, K_GROUP);

	imshow("show",grayImage);
	waitKey();
	return 0;

}

void K_Manes(Point *kp, int k_group)
{
	Point p2;
	int d[K_GROUP];

	Point **data;
	unsigned long **dataD;
	unsigned long *loc_cnt;
	long loc_g = 0;
	//char rand_flag[K_GROUP];
	int lx, ly;
	int t = 100, stop_cnt = 0;
	Point last_p[K_GROUP];

	data = new Point*[K_GROUP]; 
	dataD = new unsigned long*[K_GROUP];
	loc_cnt = new unsigned long[K_GROUP];
	srand(time(NULL));

	for (int i = 0; i < K_GROUP; i++){
		data[i] = new Point[k_cnt];
		dataD[i] = new unsigned long[k_cnt];
		//rand_flag[i] = 0;
		last_p[i].x = 0;
		last_p[i].y = 0;
	}	

	for (int i = 0; i < K_GROUP; i++)
	{
		for (int j = 0; j < k_cnt; j++){
			data[i][j].x = 0;
			data[i][j].y = 0;
			dataD[i][j] = 0;
		}
	}

	//show point
	Mat show = Mat::zeros(grayImage.rows, grayImage.cols, grayImage.type());
	for (int x = 0; x < grayImage.rows; x++)
	{
		for (int y = 0; y < grayImage.cols; y++)
		{
			for (int i = 0; i < K_GROUP; i++)
				if (x == kp[i].x && y == kp[i].y){
					show.ptr<uchar>(x)[y] = 255;
					for (int j = 0; j < 10; j++){
						if (x - j > 0 && x + j < grayImage.rows && y + j < grayImage.cols && y - j>0){
							show.ptr<uchar>(x - j)[y] = 255;
							show.ptr<uchar>(x + j)[y] = 255;
							show.ptr<uchar>(x)[y - j] = 255;
							show.ptr<uchar>(x)[y + j] = 255;
						}
					}
				}

		}

	}
	imshow("show point", show);

	while (t--)
	{
		//clear loc_cnt
		for (int i = 0; i < K_GROUP; i++)
		{
			loc_cnt[i] = 0;
			for (int j = 0; j < k_cnt; j++)
			{
				data[i][j].x = 0;
				data[i][j].y = 0;
				dataD[i][j] = 0;
			}
		}

		int samll_d= 0;
		//find group
		for (int x = 0; x < grayImage.rows; x++)
		{
			for (int y = 0; y < grayImage.cols; y++)
			{
				if (grayImage.ptr<uchar>(x)[y] != 0)
				{
					p2.x = x;
					p2.y = y;
					//find distance
					loc_g = 0;
					samll_d = d[0];
					for (int i = 0; i < K_GROUP; i++)
					{
							
						d[i] = sqrt(pow(p2.x - kp[i].x, 2) + pow(p2.y - kp[i].y, 2));
						if (samll_d > d[i]){
							loc_g = i;
							samll_d = d[i];
							
						}
					}

					//save data
					data[loc_g][loc_cnt[loc_g]].x = p2.x;
					data[loc_g][loc_cnt[loc_g]].y = p2.y;
					dataD[loc_g][loc_cnt[loc_g]] = samll_d;
					
					loc_cnt[loc_g]++;
					data[loc_g][loc_cnt[loc_g]].x = 0;
					data[loc_g][loc_cnt[loc_g]].y = 0;
					dataD[loc_g][loc_cnt[loc_g]] = 0;
				}

			}
		}



		//count max point
		int s = loc_cnt[0];
		int sl = 0;
		for (int i = 0; i < K_GROUP; i++){
			if (s < loc_cnt[i]){
				s = loc_cnt[i];
				sl = i;
			}
		}

		//draw center point
		char p = 5;
		Mat show2 = Mat::zeros(show.rows, show.cols, show.type());
		for (int x = 0; x < show.rows; x++)
		{
			for (int y = 0; y < show.cols; y++)
			{
				for (int i = 0; i < K_GROUP; i++)
				{
					if (x == kp[i].x && y == kp[i].y){
						show2.ptr<uchar>(x)[y] = 255;
						i == sl ? p = 10 : p = 5;
						for (int j = 0; j < p; j++){
							if (x - j > 0 && x + j < grayImage.rows && y + j < grayImage.cols && y - j>0){
								show2.ptr<uchar>(x - j)[y] = 255;
								show2.ptr<uchar>(x + j)[y] = 255;
								show2.ptr<uchar>(x)[y - j] = 255;
								show2.ptr<uchar>(x)[y + j] = 255;
							}
						}
					}
				}

			}
		}


		//return loop 
		Mat show3 = Mat::zeros(show2.rows, show2.cols, show2.type());
		for (int i = 0; i < K_GROUP; i++)
		{
			if (stop_cnt > 3 || t == 0)
			{
				printf("t=%d\n", 100 - t);
				for (int x = 0; x < grayImage.rows; x++)
				{
					for (int y = 0; y < grayImage.cols; y++)
					{
						if (grayImage.ptr<uchar>(x)[y] != 0)
						{
							show2.ptr<uchar>(x)[y] = 255;
						}
					}
				}

				for (int x = 0; x < K_GROUP; x++){
					printf("loc_cnt[%d]=%ld\n", x, loc_cnt[x]);
					printf("kp[%d].x=%d  kp[%d].y=%d \n", x, kp[x].x, x, kp[x].y);
				}
				imshow("show2 point", show2);
				return;
			}

			if (last_p[i].x == kp[i].x && last_p[i].y == kp[i].y && loc_cnt[i]>0)
				stop_cnt++;
			else if (sqrt(pow(last_p[i].x - kp[i].x, 2) + pow(last_p[i].y - kp[i].y, 2))<5)
				stop_cnt++;

		}

		//calcuate K-group center again
		Point max_loc[K_GROUP], min_loc[K_GROUP];
		unsigned long long max_p, min_p;
		unsigned long long  new_point_X[K_GROUP];
		unsigned long long  new_point_Y[K_GROUP];
		for (int i = 0; i < K_GROUP; i++)
		{
			new_point_X[i] = 0;
			new_point_Y[i] = 0;
			max_p = dataD[i][0];
			min_p = dataD[i][0];
			max_loc[i].x = data[i][0].x;
			min_loc[i].y = data[i][0].y;

			for (int j = 0; j < loc_cnt[i]; j++)
			{
				if (data[i][j].x != 0 && data[i][j].y != 0)
				{

					if (loc_cnt[i] > 0){
						/*average point*/
						new_point_X[i] += data[i][j].x;
						new_point_Y[i] += data[i][j].y;
					}


				}
			}
		}
		//update group center
		for (int i = 0; i < K_GROUP; i++)
		{
			if (loc_cnt[i] > 0){
				/*average point*/
				new_point_X[i] /= loc_cnt[i];
				new_point_Y[i] /= loc_cnt[i];

				last_p[i].x = kp[i].x;
				last_p[i].y = kp[i].y;

				kp[i].x = new_point_X[i];
				kp[i].y = new_point_Y[i];
			}
		}

	}
}

此程式碼將圖片(灰階)載入後,取白灰點做處理並分群集。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值