K-Means的一些想法以及實現

做爲測試,我使用的是二維平面座標進行的。咱們隨機選取圖片,使用OpenCV的Mat類對象讀取圖像文件中的數據,而後使用rand函數隨機產生k(這裏k值取決於輸入)個二維座標值。遍歷整個圖像像素位置,計算每一個座標相對於任意一個核心點之間的距離L^2(歐氏距離的平方,由於這樣計算量會小一些),根據距離值對像素進行分類。當整個圖像遍歷一遍以後,咱們有了一個初步的聚類,然而這個聚類是很差的,主要緣由在於聚類的核心點是任意產生的(其緣由是因爲這個聚類方法是非監督的,咱們對數據集和數據點是未知的)。咱們須要對每個數據集進行數據的修整。ios

 

                         1聚類前圖像                                                                       2 初步聚類後算法

 

                            3最終聚類後圖像 (647*580分辨率)函數

          

           4 隨機點的分佈                                                     測試

這3個圖,大概能說明K-Means聚類方法的一些緣由和問題了。this

在看這3個圖的時候,請忽略圖像的大小變化,關注圖像內部的比例變化更好一些(根據距離進行聚類,所以能夠忽略不計)。對象

我在作K-Means 的時候,爲了展示效果,將不一樣的數據集採用不一樣色彩進行標註,每個色區中有一個點,標定核心點的位置。blog

咱們能夠看出,圖2的聚類不規則,3圖做爲最終聚類的形式,有較大的改觀,從4圖能夠發現,一開始的隨機點分佈並不如3圖當中如此排列有序,可是通過修正後,基本上比較規則,可是仍然不是徹底四等分,其中主要緣由之一,就是隨機點的獲取影響的聚類的效果,在咱們採起的聚類對象中,可能會好一點,可是在別的距類對象中(數據分佈及其不均勻,這樣的數據量很大)可能比較糟糕。排序

#include<iostream>
#include<vector>
#include<string>
#include<cv.hpp>
using cv::Mat;
using cv::imread;
using cv::imshow;
using cv::imwrite;
using cv::waitKey;
using cv::cvtColor;
//using cv::Point2i;
using std::vector;
using std::string;
using std::cin;
using std::cout;
using std::endl;

//typedef Point2i Point;

struct Point
{
	int x;
	int y;
	unsigned int gray;
	unsigned int distance;
	double weight;
	Point()
	{
		x = 0;
		y = 0;
		gray = 0;
		distance = 0;
		weight = 0;
	}
	Point(int _x, int _y,unsigned int _gray=0,unsigned int _distance=0,int _weight=0) { x = _x; y = _y; gray =_gray; distance =_distance; weight = _weight; }
	Point(const Point&_point) { this->x = _point.x; this->y = _point.y; this->gray = _point.gray; this->distance = _point.distance; this->weight = _point.weight; }
	Point& operator=(const Point&_point) { this->x = _point.x; this->y = _point.y; this->gray = _point.gray; this->distance = _point.distance; this->weight = _point.weight; return *this; }

};



void dSort(vector<Point>*vec)
{
	vector<Point>::iterator fIt = vec->begin();
	
	for (; fIt != vec->end(); ++fIt)
	{
		for (vector<Point>::iterator sIt = fIt+1; sIt != vec->end(); ++sIt)
		{
			if (sIt->distance < fIt->distance)
			{
				
				Point tmp(*sIt);
				*sIt=*fIt;
				*fIt = tmp;
			}
		}

	}
	vector<Point>::iterator it = vec->begin();
	}

void Weight(vector<Point>*vec,double alpha,double beta,double theta)
{
	if (vec->empty())
	{
		cout << "container is empty" << endl;
		return;
	}
	cout << "start sort" << endl;
	dSort(vec);
	cout << "end sort" << endl;
	double cscore = 0.0;
	double dscore = 0.0;
	vector<Point>::iterator it = vec->begin();
	for (; it != vec->end(); ++it)
	{
		dscore = (1 / (sqrt(2 * 3.14159)*beta))*(exp((it - vec->begin())*(it - vec->begin()) / (2 * beta*beta)));
		//cout << dscore << endl;
		dscore *= it->distance;
		cscore = (1 / (sqrt(2 * 3.14159)*theta))*(exp((it - vec->begin())*(it - vec->begin()) / (2 * theta*theta)));
		cscore *= it->gray;
		it->weight = double(alpha*it->distance) + double((1 - alpha)*it->gray);
	//	cout << "weight=" << it->weight << endl;
	}
	cout << "after weight" << endl;

}
 int squareDistance(const Point& p1, const Point &p2)
{
	//cout <<"s"<<p1.x << "," << p1.y <<"   "<<p2.x<<","<<p2.y<<endl;

	return ((p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y));
}
 int colorGap(Mat mat,const Point&p1, const Point&p2)
{
//	cout << "c" << p1.x << "," << p1.y << "   " << p2.x << "," << p2.y<<endl;
	//cout<<"gap="<< abs(mat.at<uchar>(p1.x, p1.y) - mat.at<uchar>(p2.x, p2.y));
 
	return abs(mat.at<uchar>(p1.x, p1.y) - mat.at<uchar>(p2.x, p2.y));
}

const Point & findCentre( vector<Point>&vec)
{
	cout << "start centre" << endl;
	vector<Point>::iterator it = vec.begin();
	int	xall = 0;
	int yall = 0;
	int weight = 0;
	for (; it != vec.end(); ++it)
	{
		xall+= it->x;
		yall += it->y;
	}
	weight=vec.size();
//	cout << xall << '\t' << yall << '\t' << weight <<'\t'<<xall/weight<<endl;
	cout << "end centre" << endl;
	Point t(xall / weight, yall / weight);
	cout << t.x <<'\t'<< t.y << endl;
	vec.clear();
	//cout << "xall=" << xall << "yall=" << yall << "weight=" << weight <<"xall/weight="<<xall/weight<<"yall/weight="<<yall/weight<< endl;
	return t;
}

bool stopCondition(int num, Point*pt, vector<Point>*vec)
{
	bool flag = 1;
	for (int i = 0; i != num; ++i)
	{
		if (pt[i].x == vec[i].begin()->x&&pt[i].y == vec[i].begin()->y)
			flag = flag & 1;
		else
			flag = flag & 0;
	}
	return flag;
}

void getPoint(Mat mat, vector<Point> *vec, int num = 5)
{
	unsigned int Min = mat.rows*mat.rows + mat.cols*mat.cols;
	int pos = 0;
	for (int i = 0; i != mat.rows; ++i)
	{
		for (int j = 0; j != mat.cols; ++j)
		{
			Min = mat.rows*mat.rows + mat.cols*mat.cols;
			pos = 0;
			for (int k = 0; k != num; ++k)
			{
				Point tmp = *vec[k].begin();
				if ((Min > squareDistance(Point(i, j), tmp)))//&&squareDistance(Point(i, j), tmp)<=l_gap)
				{

					Min = squareDistance(Point(i, j), tmp);
					pos = k;
				}
			}
			Point tmp(i, j, colorGap(mat, Point(i, j), vec[pos].front()), Min, 0);
			vec[pos].push_back(tmp);
		}
	}
}

void K_Means(Mat&mat,vector<Point> *vec, int num = 5, double alpha = 0.5,int amp=10,int l_gap=20,int c_gap=30,double threshold=0.5 )
{
	
	int amplitude = 15;
	if (mat.empty())
	{
		cout << "please input the Mat" << endl;
		return;
	}
	Point*start = new Point[num];
	for (int i = 0; i != num; ++i)
    start[i] = Point(0, 0);

    for (int i = 0; i != num; ++i)
    {
        vec[i].push_back(Point(rand() % mat.rows, rand() % mat.cols));
		cout << vec[i].front().x << "," << vec[i].front().y << endl;
	}
	
	
	while (!stopCondition(num, start, vec))
	{
		

		cout << "________________________" << endl;
		for (int i = 0; i != num; ++i)
		{
			cout << "start" << start[i].x << '\t' << start[i].y << endl;
			cout << "vec" << vec[i].begin()->x << '\t' << vec[i].begin()->y << endl;
		}
		cout << "_____________________________" << endl;

		for (int i = 0; i != num; ++i)
		{
			start[i] = vec[i].front();
		}
		amplitude = 0;
		getPoint(mat, vec, num);
		cout << "get the weight and centre" << endl;
		for (int x = 0; x != num; ++x)
		{
			cout << "num=" << x << endl;
			//	Weight(&vec[x], 0.5, 0.4, 0.4);
			Point t(findCentre(vec[x]));
			//*vec[x].begin() = t;
			vec[x].push_back(t);
			cout << vec[x].begin()->x << vec[x].begin()->y << endl;
		}
	}
	            getPoint(mat, vec, num);
				cout << "paint" << endl;
				/*
				for (int i = 0; i != num; ++i)
				{
					double allweight = 0.0;
					vector<Point>::iterator it = vec[i].begin();
					for (; it != vec[i].end(); ++it)
						allweight += it->weight;
					it = vec[i].begin();
					double aveweight = allweight / (vec[i].size());
					*/
					/*
					for (int i = 0; i != mat.rows; ++i)
						for (int j = 0; j != mat.cols; ++j)
							mat.at<uchar>(i, j) = 255;
							*/


				for (int i = 0; i != num;++i)
				{
					vector<Point>::iterator it = vec[i].begin();
					for (; it != vec[i].end(); ++it)
					{
							mat.at<uchar>(it->x, it->y) = 50 + i * 30;
					}
					mat.at<uchar>(vec[i].front().x, vec[i].front().y) = 0;
					
				}

}

int main()
{
	int number = 0;
	vector<Point> *vec;
	cin >> number;
	vec = new vector<Point>[number];
//	for (int i = 0; i != numbe)
	Mat mat =imread("2.jpg");
	cvtColor(mat, mat, CV_BGR2GRAY);
	K_Means(mat, vec,number);
	imshow("1", mat);
	//imwrite(string("2.jpg"), mat);
	waitKey(0);
}

  代碼格式雜亂無章,做爲本身的筆記,先這麼湊合吧,等把這個K-Means聯合color因子的算法徹底寫出來,再進行調整也不晚。圖片

這些代碼中,其中Weight函數中提出了色彩+距離權重的計算,咱們使用兩個不一樣參數的高斯函數進行權重的規約(將數據按照距離進行排序,由小到大。距離越大,相對於高斯函數的中軸越遠,將這個距離帶入高斯函數中,最終權值較小)。色彩+距離這兩個因子使用一個參數進行調節,控制這兩個因子在權重中所佔比率的大小,這樣我感受效果會好一些。ci

相關文章
相關標籤/搜索