k-means (метод k-средних) — метод кластеризации, стремящийся минимизировать суммарное квадратичное отклонение точек кластеров от центров этих кластеров.
Кластеризация — задача машинного обучения, состоящая в разбиении заданной выборки объектов (данных) на непересекающиеся подмножества/группы (кластеры) на основе близости их признаков/значений. Т.о., каждый кластер состоит из схожих объектов.
Кластеризация позволяет:
* лучше понять данные (выявив структурные группы),
* компактное хранение данных,
* выявление новых объектов.
В OpenCV, алгоритм k-means реализован в cxcore, т.к. он был реализован задолго до появления библиотеки ML.
K-means пытается найти кластеры в наборе данных.
Это реализуется функцией cvKMeans2().
Алгоритм работы k-means: 1. Принимает входные данные и желаемое число кластеров 2. Случайным образом выбирает центры кластеров 3. Ассоциирует каждую точку данных с ближайшим центром кластера 4. Перемещает центр кластера в центроид его точек данных. 5. Возвращается на шаг 3 пока не достигнута сходимость (центр кластера не двигается)
Проблемы алгоритма k-means: 1. не гарантирует определения лучшего из возможных расположений центров кластеров (достижение глобального минимума суммарного квадратичного отклонения). Однако, гарантирует сходимость к какому-либо решению, т.е. итерации не зациклятся в бесконечном цикле. 2. не определяет сколько кластеров стоит использовать (т.е. число кластеров надо знать заранее) 3. результат зависит от выбора исходных центров кластеров 4. K-means предполагает, что пространственная ковариационная составляющая, либо не имеет значения, либо уже была отнормирована.
CVAPI(int) cvKMeans2( const CvArr* samples, int cluster_count, CvArr* labels,
CvTermCriteria termcrit, int attempts CV_DEFAULT(1),
CvRNG* rng CV_DEFAULT(0), int flags CV_DEFAULT(0),
CvArr* _centers CV_DEFAULT(0), double* compactness CV_DEFAULT(0) );
— разделение векторов на заданное число кластеров
samples — матрица примеров (float) — одна строчка — один вектор
cluster_count — число кластеров
labels — возвращаемый вектор (int), хранящий индекс кластера каждого вектора
termcrit — критерий завершения итераций
attempts — число попыток достижения лучшей компактности
rng — внешний ГСЧ
flags — флаг — 0 или:
#define CV_KMEANS_USE_INITIAL_LABELS 1 // для первой попытки будет использовать предуставновленное значение вектора labels (далее - будет использоваться ГСЧ)
_centers — возвращаемый массив центров кластеров
compactness — компактность — возвращаемый параметр, который высчитывается по формуле:
Summ( || samples(i) - centers(labels(i)) ||^2 )
— высчитывается после каждой попытки и лучшее (минимальное) значение выбирается и соответствующие labels возвращаются
//
// Несколько модифицированный пример Example 13-1.
// Использование K-means
//
// из книги:
// Learning OpenCV: Computer Vision with the OpenCV Library
// by Gary Bradski and Adrian Kaehler
// Published by O'Reilly Media, October 3, 2008
#include "cxcore.h"
#include "highgui.h"
#define MAX_CLUSTERS 5
int main( int argc, char* argv[] )
{
// изображение для показа точек
IplImage* img = cvCreateImage( cvSize( 500, 500 ), 8, 3 );
// таблица цветов кластеров
CvScalar color_tab[MAX_CLUSTERS];
color_tab[0] = CV_RGB(255,0,0);
color_tab[1] = CV_RGB(0,255,0);
color_tab[2] = CV_RGB(100,100,255);
color_tab[3] = CV_RGB(255,0,255);
color_tab[4] = CV_RGB(255,255,0);
// инициализация состояния ГПСЧ
CvRNG rng = cvRNG(0xffffffff);
cvNamedWindow( "clusters", 1 );
for(;;){
int k, cluster_count = cvRandInt(&rng)%MAX_CLUSTERS + 1;
int i, sample_count = cvRandInt(&rng)%1000 + 1;
CvMat* points = cvCreateMat( sample_count, 1, CV_32FC2 );
CvMat* clusters = cvCreateMat( sample_count, 1, CV_32SC1 );
// генерация случайного гауссового распределения точек
for( k = 0; k < cluster_count; k++ ){
CvPoint center;
CvMat point_chunk;
center.x = cvRandInt(&rng)%img->width;
center.y = cvRandInt(&rng)%img->height;
cvGetRows( points, &point_chunk,
k*sample_count/cluster_count,
k == cluster_count - 1 ? sample_count :
(k+1)*sample_count/cluster_count );
cvRandArr( &rng, &point_chunk, CV_RAND_NORMAL,
cvScalar(center.x,center.y,0,0),
cvScalar(img->width/6, img->height/6,0,0) );
}
// точки перемешиваются
for( i = 0; i < sample_count/2; i++ ){
CvPoint2D32f* pt1 = (CvPoint2D32f*)points->data.fl +
cvRandInt(&rng)%sample_count;
CvPoint2D32f* pt2 = (CvPoint2D32f*)points->data.fl +
cvRandInt(&rng)%sample_count;
CvPoint2D32f temp;
CV_SWAP( *pt1, *pt2, temp );
}
// определение кластеров
cvKMeans2( points, cluster_count, clusters,
cvTermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER,
10, 1.0 ));
cvZero( img );
// показываем точки
for( i = 0; i < sample_count; i++ ){
CvPoint2D32f pt = ((CvPoint2D32f*)points->data.fl)[i];
// индекс кластера
int cluster_idx = clusters->data.i[i];
cvCircle( img, cvPointFrom32f(pt), 2, color_tab[cluster_idx], CV_FILLED );
}
cvReleaseMat( &points );
cvReleaseMat( &clusters );
// показываем
cvShowImage( "clusters", img );
int key = cvWaitKey(330);
if( key == 27 ){ // 'ESC'
break;
}
}
// освобождаем ресурсы
cvReleaseImage(&img);
// удаляем окна
cvDestroyAllWindows();
return 0;
}
CVAPI(CvMat*) cvGetRows( const CvArr* arr, CvMat* submat,
int start_row, int end_row,
int delta_row CV_DEFAULT(1));
CV_INLINE CvMat* cvGetRow( const CvArr* arr, CvMat* submat, int row )
{
return cvGetRows( arr, submat, row, row + 1, 1 );
}
— возвращает массив строк
arr — исходный массив
submat — указатель возвращаемый заголовок массива
start_row — индекс (от 0) начальной строки
end_row — индекс последней строки (не включая)
delta_row — индекс шага (т.е. выбирается каждая delta_row-ая строка между [start_row:end_row) )
CVAPI(CvMat*) cvGetCols( const CvArr* arr, CvMat* submat,
int start_col, int end_col );
CV_INLINE CvMat* cvGetCol( const CvArr* arr, CvMat* submat, int col )
{
return cvGetCols( arr, submat, col, col + 1 );
}
— возвращает массив столбцов
arr — исходный массив
submat — указатель возвращаемый заголовок массива
start_col — индекс (от 0) начального столбца
end_col — индекс последнего столбца (не включая)
Комментарии (0)
RSS свернуть / развернутьТолько зарегистрированные и авторизованные пользователи могут оставлять комментарии.