基於K-means聚類的圖像分割


K-means算法用於聚類分析,廣泛用於機器學習領域。

下面借用百度百科的解釋,個人覺得講的還算清楚:

k-means 算法接受參數 k ;然后將事先輸入的n個數據對象划分為 k個聚類以便使得所獲得的聚類滿足:同一聚類中的對象相似度較高;而不同聚類中的對象相似度較小。聚類相似度是利用各聚類中對象的均值所獲得一個“中心對象”(引力中心)來進行計算的。
K-means算法是最為經典的基於划分的聚類方法,是十大經典數據挖掘算法之一。K-means算法的基本思想是:以空間中k個點為中心進行聚類,對最靠近他們的對象歸類。通過迭代的方法,逐次更新各聚類中心的值,直至得到最好的聚類結果。
假設要把樣本集分為c個類別,算法描述如下:
(1)適當選擇c個類的初始中心;
(2)在第k次迭代中,對任意一個樣本,求其到c各中心的距離,將該樣本歸到距離最短的中心所在的類;
(3)利用均值等方法更新該類的中心值;
(4)對於所有的c個聚類中心,如果利用(2)(3)的迭代法更新后,值保持不變,則迭代結束,否則繼續迭代。
該算法的最大優勢在於簡潔和快速。算法的關鍵在於初始中心的選擇和距離公式。

算法流程

首先從n個數據對象任意選擇 k 個對象作為初始聚類中心;而對於所剩下其它對象,則根據它們與這些聚類中心的相似度(距離),分別將它們分配給與其最相似的(聚類中心所代表的)聚類;然后再計算每個所獲新聚類的聚類中心(該聚類中所有對象的均值);不斷重復這一過程直到標准測度函數開始收斂為止。一般都采用均方差作為標准測度函數. k個聚類具有以下特點:各聚類本身盡可能的緊湊,而各聚類之間盡可能的分開。

具體流程

輸入:k, data[n];
(1) 選擇k個初始中心點,例如c[0]=data[0],…c[k-1]=data[k-1];
(2) 對於data[0]….data[n], 分別與c[0]…c[k-1]比較,假定與c[i]差值最少,就標記為i;
(3) 對於所有標記為i點,重新計算c[i]={ 所有標記為i的data[j]之和}/標記為i的個數;
(4) 重復(2)(3),直到所有c[i]值的變化小於給定閾值。

如何處理空的聚類

果所有的點在指派步驟都未分配到某個簇,就會得到空簇。如果這種情況發生,則需要某種策略來選擇一個替補質心,否則的話,平方誤差將會偏大。一種方法是選擇一個距離當前任何質心最遠的點。這將消除當前對總平方誤差影響最大的點。另一種方法是從具有最大誤差平方和的簇中選擇一個替補的質心。這將分裂簇並降低聚類的總誤差平方和。如果有多個空簇,則該過程重復多次。

用於圖像分割

輸入參數為像素的橫、縱坐標以及R、G、B三色值共5個參數,參數歸一化后計算各個像素點與各個初始聚類像素點(假設有三個)之間五維向量的歐式距離;然后將其歸類到與其距離最小的那個初始聚類中,一遍處理完之后所有點都被歸類到三個集合里,如果本次歸類完成后與上次相比歸類情況發生變化的情況小於預設值,算法就收斂了,否則重新計算三個集合中各個集合的重心,三個中心作為聚類像素點,進行下一次歸類。
借用孫興華老師的代碼展示下,代碼如下:
double Distance_of_location_and_color(CImagePoint pixel_1, RGB_TRIPLE color_1,
	CImagePoint pixel_2, RGB_TRIPLE color_2,
	long image_height, long image_width)
{
	double first_1 = double(pixel_1.m_row) / double(image_height);
	double second_1 = double(pixel_1.m_column) / double(image_width);
	double third_1 = double(color_1.m_Red) / 255.0;
	double fourth_1 = double(color_1.m_Green) / 255.0;
	double fifth_1 = double(color_1.m_Blue) / 255.0;

	double first_2 = double(pixel_2.m_row) / double(image_height);
	double second_2 = double(pixel_2.m_column) / double(image_width);
	double third_2 = double(color_2.m_Red) / 255.0;
	double fourth_2 = double(color_2.m_Green) / 255.0;
	double fifth_2 = double(color_2.m_Blue) / 255.0;

	return sqrt((first_1 - first_2) * (first_1 - first_2)
		+ (second_1 - second_2) * (second_1 - second_2)
		+ (third_1 - third_2) * (third_1 - third_2)
		+ (fourth_1 - fourth_2) * (fourth_1 - fourth_2)
		+ (fifth_1 - fifth_2) * (fifth_1 - fifth_2));
}

int Update_index_into_clusters(CImagePoint current_pixel, RGB_TRIPLE current_color,
	CTArray< CImagePoint> centers_of_pixel, CTArray< RGB_TRIPLE > centers_of_color,
	long image_height, long image_width)
{
	long dimension = centers_of_pixel.GetDimension();

	CTArray< double > array_of_distances(dimension);

	double current_distance;
	int current_index;

	for (int index = 0; index < dimension; index++)
	{
		array_of_distances[index] = Distance_of_location_and_color(current_pixel, current_color,
			centers_of_pixel[index], centers_of_color[index],
			image_height, image_width);
		if (index == 0)
		{
			current_distance = array_of_distances[index];
			current_index = index;
		}
		else
		{
			if (array_of_distances[index] < current_distance)
			{
				current_distance = array_of_distances[index];
				current_index = index;
			}
		}
	}

	return current_index;
}

void Update_centers_of_clusters(const CTMatrix< RGB_TRIPLE >& color_image, const CTMatrix< int >& cluster_result,
	int number_of_clusters,
	CTArray< CImagePoint >& centers_of_pixel, CTArray< RGB_TRIPLE >& centers_of_color)
{
	long image_height = color_image.Get_height();
	long image_width = color_image.Get_width();

	CTArray< int > scale_of_clusters(number_of_clusters);
	CTMatrix< double > sum_of_clusters(number_of_clusters, 5);

	for (int index = 0; index < number_of_clusters; index++)
	{
		scale_of_clusters[index] = 0;

		for (int sub_index = 0; sub_index < 5; sub_index++)
		{
			sum_of_clusters[index][sub_index] = 0;
		}
	}

	for (int row = 0; row < image_height; row++)
		for (int column = 0; column < image_width; column++)
		{
		int current_index = cluster_result[row][column];

		scale_of_clusters[current_index] ++;
		sum_of_clusters[current_index][0] += row;
		sum_of_clusters[current_index][1] += column;
		sum_of_clusters[current_index][2] += color_image[row][column].m_Red;
		sum_of_clusters[current_index][3] += color_image[row][column].m_Green;
		sum_of_clusters[current_index][4] += color_image[row][column].m_Blue;
		}

	for (int index = 0; index < number_of_clusters; index++)
		if (scale_of_clusters[index] != 0)
		{
		centers_of_pixel[index].m_row = long(sum_of_clusters[index][0] / scale_of_clusters[index]);
		centers_of_pixel[index].m_column = long(sum_of_clusters[index][1] / scale_of_clusters[index]);
		centers_of_color[index].m_Red = BYTE(sum_of_clusters[index][2] / scale_of_clusters[index]);
		centers_of_color[index].m_Green = BYTE(sum_of_clusters[index][3] / scale_of_clusters[index]);
		centers_of_color[index].m_Blue = BYTE(sum_of_clusters[index][4] / scale_of_clusters[index]);
		}

	return;
}

bool Are_centers_same(const CTArray< CImagePoint>& centers_of_pixel, const CTArray< RGB_TRIPLE >& centers_of_color,
	const CTArray< CImagePoint>& copies_of_pixel, const CTArray< RGB_TRIPLE >& copies_of_color)
{
	bool is_same = true;

	long dimension = centers_of_pixel.GetDimension();

	for (int index = 0; index < dimension; index++)
	{
		if (centers_of_pixel[index] != copies_of_pixel[index]
			|| centers_of_color[index].m_Red != copies_of_color[index].m_Red
			|| centers_of_color[index].m_Green != copies_of_color[index].m_Green
			|| centers_of_color[index].m_Blue != copies_of_color[index].m_Blue)
		{
			is_same = false;
			break;
		}
	}

	return is_same;
}

// [ ********** ] ........................................................
// [ K 均值聚類 ] ........................................................
// [ ********** ] ........................................................
CTMatrix< int > CImageColorProcess::K_means_clustering(const CTMatrix< RGB_TRIPLE >& color_image, int number_of_clusters)
{
	long image_height = color_image.Get_height();
	long image_width = color_image.Get_width();

	CTMatrix< int > cluster_result(image_height, image_width);

	CTArray< CImagePoint> centers_of_pixel(number_of_clusters);
	CTArray< RGB_TRIPLE > centers_of_color(number_of_clusters);

	for (int index = 0; index < number_of_clusters; index++)
	{
		int row = image_height * (index + 1) / (number_of_clusters + 1);
		int column = image_width * (index + 1) / (number_of_clusters + 1);

		centers_of_pixel[index] = CImagePoint(row, column);
		centers_of_color[index] = color_image[row][column];
	}

	CTArray< CImagePoint> copies_of_pixel;
	CTArray< RGB_TRIPLE > copies_of_color;

	long iteration = 0;

	do
	{
		iteration++;

		copies_of_pixel = centers_of_pixel;
		copies_of_color = centers_of_color;

		for (int row = 0; row < image_height; row++)
			for (int column = 0; column < image_width; column++)
			{
			cluster_result[row][column] = Update_index_into_clusters(CImagePoint(row, column), color_image[row][column],
				centers_of_pixel, centers_of_color, image_height, image_width);
			}

		Update_centers_of_clusters(color_image, cluster_result, number_of_clusters, centers_of_pixel, centers_of_color);

	} while (!Are_centers_same(centers_of_pixel, centers_of_color, copies_of_pixel, copies_of_color) && iteration < 1000);

	return cluster_result;
}
調用方法
long number_of_clusters = 4;

	CTArray< RGB_TRIPLE > template_of_display(number_of_clusters);
	template_of_display[0] = RGB_TRIPLE(255, 255, 0);
	template_of_display[1] = RGB_TRIPLE(0, 175, 175);
	template_of_display[2] = RGB_TRIPLE(100, 0, 100);
	template_of_display[3] = RGB_TRIPLE(0, 0, 0);

	int nW(0), nH(0), nCount(0);
	m_SrcView.GetImgInfo(0, nW, nH, nCount);

	//申請原始的圖像數據內存
	int nSrcLine = LINEWIDTH(nW*nCount);
	LPBYTE lpSrcBit = new BYTE[nSrcLine*nH];
	m_SrcView.GetImgData(0, nW, nH, lpSrcBit);

	//申請目標圖像數據內存
	int nDstCount = 24;
	int nDstLine = LINEWIDTH(nW*nCount);
	int nLineBytes = LINEWIDTH(nW*nCount);
	LPBYTE lpDstBit = new BYTE[nLineBytes*nH];
	CTMatrix<RGB_TRIPLE> myimage(nH,nW);
	for (int i = 0; i < nH; i++)
	{
		for (int j = 0; j < nW; j++)
		{
			myimage[i][j].m_Red = lpSrcBit[i*nSrcLine + 3 * j];
			myimage[i][j].m_Green = lpSrcBit[i*nSrcLine + 3 * j+1];
			myimage[i][j].m_Blue = lpSrcBit[i*nSrcLine + 3 * j+2];
		}
	}
	//調用處理函數
	CTMatrix< int > cluster_results = CImageColorProcess::K_means_clustering(myimage, number_of_clusters);

	int image_height = nH;
	int image_width = nW;

	CTMatrix< RGB_TRIPLE > display_image(image_height, image_width);

	for (int row = 0; row < image_height; row++)
	{
		for (int column = 0; column < image_width; column++)
		{
			display_image[row][column] = template_of_display[cluster_results[row][column]];
			lpDstBit[row*nDstLine + column * 3] = display_image[row][column].m_Red;
			lpDstBit[row*nDstLine + column * 3+1] = display_image[row][column].m_Green;
			lpDstBit[row*nDstLine + column * 3+2] = display_image[row][column].m_Blue;
		}
	}

	//顯示圖像數據
	m_DstView.SetImgData(lpDstBit, nW, nH, nDstCount);
	m_DstView.Invalidate();
	delete[] lpSrcBit;
	delete[] lpDstBit;


效果圖發幾張

                    

原圖                                                                                       三個聚類點                                                                      四個聚類點

               



版權聲明:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM