1 /*M/////////////////////////////////////////////////////////////////////////////////////// 2 // 3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 4 // 5 // By downloading, copying, installing or using the software you agree to this license. 6 // If you do not agree to this license, do not download, install, 7 // copy or use the software. 8 // 9 // 10 // License Agreement 11 // For Open Source Computer Vision Library 12 // 13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved. 14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved. 15 // Copyright (C) 2013, OpenCV Foundation, all rights reserved. 16 // Third party copyrights are property of their respective owners. 17 // 18 // Redistribution and use in source and binary forms, with or without modification, 19 // are permitted provided that the following conditions are met: 20 // 21 // * Redistribution's of source code must retain the above copyright notice, 22 // this list of conditions and the following disclaimer. 23 // 24 // * Redistribution's in binary form must reproduce the above copyright notice, 25 // this list of conditions and the following disclaimer in the documentation 26 // and/or other materials provided with the distribution. 27 // 28 // * The name of the copyright holders may not be used to endorse or promote products 29 // derived from this software without specific prior written permission. 30 // 31 // This software is provided by the copyright holders and contributors "as is" and 32 // any express or implied warranties, including, but not limited to, the implied 33 // warranties of merchantability and fitness for a particular purpose are disclaimed. 34 // In no event shall the Intel Corporation or contributors be liable for any direct, 35 // indirect, incidental, special, exemplary, or consequential damages 36 // (including, but not limited to, procurement of substitute goods or services; 37 // loss of use, data, or profits; or business interruption) however caused 38 // and on any theory of liability, whether in contract, strict liability, 39 // or tort (including negligence or otherwise) arising in any way out of 40 // the use of this software, even if advised of the possibility of such damage. 41 // 42 //M*/ 43 44 #include "precomp.hpp" 45 46 ////////////////////////////////////////// kmeans //////////////////////////////////////////// 47 48 namespace cv 49 { 50 51 static void generateRandomCenter(const std::vector<Vec2f>& box, float* center, RNG& rng) 52 { 53 size_t j, dims = box.size(); 54 float margin = 1.f/dims; 55 for( j = 0; j < dims; j++ ) 56 center[j] = ((float)rng*(1.f+margin*2.f)-margin)*(box[j][1] - box[j][0]) + box[j][0]; 57 } 58 59 class KMeansPPDistanceComputer : public ParallelLoopBody 60 { 61 public: 62 KMeansPPDistanceComputer( float *_tdist2, 63 const float *_data, 64 const float *_dist, 65 int _dims, 66 size_t _step, 67 size_t _stepci ) 68 : tdist2(_tdist2), 69 data(_data), 70 dist(_dist), 71 dims(_dims), 72 step(_step), 73 stepci(_stepci) { } 74 75 void operator()( const cv::Range& range ) const 76 { 77 const int begin = range.start; 78 const int end = range.end; 79 80 for ( int i = begin; i<end; i++ ) 81 { 82 tdist2[i] = std::min(normL2Sqr(data + step*i, data + stepci, dims), dist[i]); 83 } 84 } 85 86 private: 87 KMeansPPDistanceComputer& operator=(const KMeansPPDistanceComputer&); // to quiet MSVC 88 89 float *tdist2; 90 const float *data; 91 const float *dist; 92 const int dims; 93 const size_t step; 94 const size_t stepci; 95 }; 96 97 /* 98 k-means center initialization using the following algorithm: 99 Arthur & Vassilvitskii (2007) k-means++: The Advantages of Careful Seeding 100 */ 101 static void generateCentersPP(const Mat& _data, Mat& _out_centers, 102 int K, RNG& rng, int trials) 103 { 104 int i, j, k, dims = _data.cols, N = _data.rows; 105 const float* data = _data.ptr<float>(0); 106 size_t step = _data.step/sizeof(data[0]); 107 std::vector<int> _centers(K); 108 int* centers = &_centers[0]; 109 std::vector<float> _dist(N*3); 110 float* dist = &_dist[0], *tdist = dist + N, *tdist2 = tdist + N; 111 double sum0 = 0; 112 113 centers[0] = (unsigned)rng % N; 114 115 for( i = 0; i < N; i++ ) 116 { 117 dist[i] = normL2Sqr(data + step*i, data + step*centers[0], dims); 118 sum0 += dist[i]; 119 } 120 121 for( k = 1; k < K; k++ ) 122 { 123 double bestSum = DBL_MAX; 124 int bestCenter = -1; 125 126 for( j = 0; j < trials; j++ ) 127 { 128 double p = (double)rng*sum0, s = 0; 129 for( i = 0; i < N-1; i++ ) 130 if( (p -= dist[i]) <= 0 ) 131 break; 132 int ci = i; 133 134 parallel_for_(Range(0, N), 135 KMeansPPDistanceComputer(tdist2, data, dist, dims, step, step*ci)); 136 for( i = 0; i < N; i++ ) 137 { 138 s += tdist2[i]; 139 } 140 141 if( s < bestSum ) 142 { 143 bestSum = s; 144 bestCenter = ci; 145 std::swap(tdist, tdist2); 146 } 147 } 148 centers[k] = bestCenter; 149 sum0 = bestSum; 150 std::swap(dist, tdist); 151 } 152 153 for( k = 0; k < K; k++ ) 154 { 155 const float* src = data + step*centers[k]; 156 float* dst = _out_centers.ptr<float>(k); 157 for( j = 0; j < dims; j++ ) 158 dst[j] = src[j]; 159 } 160 } 161 162 class KMeansDistanceComputer : public ParallelLoopBody 163 { 164 public: 165 KMeansDistanceComputer( double *_distances, 166 int *_labels, 167 const Mat& _data, 168 const Mat& _centers ) 169 : distances(_distances), 170 labels(_labels), 171 data(_data), 172 centers(_centers) 173 { 174 } 175 176 void operator()( const Range& range ) const 177 { 178 const int begin = range.start; 179 const int end = range.end; 180 const int K = centers.rows; 181 const int dims = centers.cols; 182 183 for( int i = begin; i<end; ++i) 184 { 185 const float *sample = data.ptr<float>(i); 186 int k_best = 0; 187 double min_dist = DBL_MAX; 188 189 for( int k = 0; k < K; k++ ) 190 { 191 const float* center = centers.ptr<float>(k); 192 const double dist = normL2Sqr(sample, center, dims); 193 194 if( min_dist > dist ) 195 { 196 min_dist = dist; 197 k_best = k; 198 } 199 } 200 201 distances[i] = min_dist; 202 labels[i] = k_best; 203 } 204 } 205 206 private: 207 KMeansDistanceComputer& operator=(const KMeansDistanceComputer&); // to quiet MSVC 208 209 double *distances; 210 int *labels; 211 const Mat& data; 212 const Mat& centers; 213 }; 214 215 } 216 217 double cv::kmeans( InputArray _data, int K, 218 InputOutputArray _bestLabels, 219 TermCriteria criteria, int attempts, 220 int flags, OutputArray _centers ) 221 { 222 const int SPP_TRIALS = 3; 223 Mat data0 = _data.getMat(); 224 bool isrow = data0.rows == 1 && data0.channels() > 1; 225 int N = !isrow ? data0.rows : data0.cols; 226 int dims = (!isrow ? data0.cols : 1)*data0.channels(); 227 int type = data0.depth(); 228 229 attempts = std::max(attempts, 1); 230 CV_Assert( data0.dims <= 2 && type == CV_32F && K > 0 ); 231 CV_Assert( N >= K ); 232 233 Mat data(N, dims, CV_32F, data0.ptr(), isrow ? dims * sizeof(float) : static_cast<size_t>(data0.step)); 234 235 _bestLabels.create(N, 1, CV_32S, -1, true); 236 237 Mat _labels, best_labels = _bestLabels.getMat(); 238 if( flags & CV_KMEANS_USE_INITIAL_LABELS ) 239 { 240 CV_Assert( (best_labels.cols == 1 || best_labels.rows == 1) && 241 best_labels.cols*best_labels.rows == N && 242 best_labels.type() == CV_32S && 243 best_labels.isContinuous()); 244 best_labels.copyTo(_labels); 245 } 246 else 247 { 248 if( !((best_labels.cols == 1 || best_labels.rows == 1) && 249 best_labels.cols*best_labels.rows == N && 250 best_labels.type() == CV_32S && 251 best_labels.isContinuous())) 252 best_labels.create(N, 1, CV_32S); 253 _labels.create(best_labels.size(), best_labels.type()); 254 } 255 int* labels = _labels.ptr<int>(); 256 257 Mat centers(K, dims, type), old_centers(K, dims, type), temp(1, dims, type); 258 std::vector<int> counters(K); 259 std::vector<Vec2f> _box(dims); 260 Vec2f* box = &_box[0]; 261 double best_compactness = DBL_MAX, compactness = 0; 262 RNG& rng = theRNG(); 263 int a, iter, i, j, k; 264 265 if( criteria.type & TermCriteria::EPS ) 266 criteria.epsilon = std::max(criteria.epsilon, 0.); 267 else 268 criteria.epsilon = FLT_EPSILON; 269 criteria.epsilon *= criteria.epsilon; 270 271 if( criteria.type & TermCriteria::COUNT ) 272 criteria.maxCount = std::min(std::max(criteria.maxCount, 2), 100); 273 else 274 criteria.maxCount = 100; 275 276 if( K == 1 ) 277 { 278 attempts = 1; 279 criteria.maxCount = 2; 280 } 281 282 const float* sample = data.ptr<float>(0); 283 for( j = 0; j < dims; j++ ) 284 box[j] = Vec2f(sample[j], sample[j]); 285 286 for( i = 1; i < N; i++ ) 287 { 288 sample = data.ptr<float>(i); 289 for( j = 0; j < dims; j++ ) 290 { 291 float v = sample[j]; 292 box[j][0] = std::min(box[j][0], v); 293 box[j][1] = std::max(box[j][1], v); 294 } 295 } 296 297 for( a = 0; a < attempts; a++ ) 298 { 299 double max_center_shift = DBL_MAX; 300 for( iter = 0;; ) 301 { 302 swap(centers, old_centers); 303 304 if( iter == 0 && (a > 0 || !(flags & KMEANS_USE_INITIAL_LABELS)) ) 305 { 306 if( flags & KMEANS_PP_CENTERS ) 307 generateCentersPP(data, centers, K, rng, SPP_TRIALS); 308 else 309 { 310 for( k = 0; k < K; k++ ) 311 generateRandomCenter(_box, centers.ptr<float>(k), rng); 312 } 313 } 314 else 315 { 316 if( iter == 0 && a == 0 && (flags & KMEANS_USE_INITIAL_LABELS) ) 317 { 318 for( i = 0; i < N; i++ ) 319 CV_Assert( (unsigned)labels[i] < (unsigned)K ); 320 } 321 322 // compute centers 323 centers = Scalar(0); 324 for( k = 0; k < K; k++ ) 325 counters[k] = 0; 326 327 for( i = 0; i < N; i++ ) 328 { 329 sample = data.ptr<float>(i); 330 k = labels[i]; 331 float* center = centers.ptr<float>(k); 332 j=0; 333 #if CV_ENABLE_UNROLLED 334 for(; j <= dims - 4; j += 4 ) 335 { 336 float t0 = center[j] + sample[j]; 337 float t1 = center[j+1] + sample[j+1]; 338 339 center[j] = t0; 340 center[j+1] = t1; 341 342 t0 = center[j+2] + sample[j+2]; 343 t1 = center[j+3] + sample[j+3]; 344 345 center[j+2] = t0; 346 center[j+3] = t1; 347 } 348 #endif 349 for( ; j < dims; j++ ) 350 center[j] += sample[j]; 351 counters[k]++; 352 } 353 354 if( iter > 0 ) 355 max_center_shift = 0; 356 357 for( k = 0; k < K; k++ ) 358 { 359 if( counters[k] != 0 ) 360 continue; 361 362 // if some cluster appeared to be empty then: 363 // 1. find the biggest cluster 364 // 2. find the farthest from the center point in the biggest cluster 365 // 3. exclude the farthest point from the biggest cluster and form a new 1-point cluster. 366 int max_k = 0; 367 for( int k1 = 1; k1 < K; k1++ ) 368 { 369 if( counters[max_k] < counters[k1] ) 370 max_k = k1; 371 } 372 373 double max_dist = 0; 374 int farthest_i = -1; 375 float* new_center = centers.ptr<float>(k); 376 float* old_center = centers.ptr<float>(max_k); 377 float* _old_center = temp.ptr<float>(); // normalized 378 float scale = 1.f/counters[max_k]; 379 for( j = 0; j < dims; j++ ) 380 _old_center[j] = old_center[j]*scale; 381 382 for( i = 0; i < N; i++ ) 383 { 384 if( labels[i] != max_k ) 385 continue; 386 sample = data.ptr<float>(i); 387 double dist = normL2Sqr(sample, _old_center, dims); 388 389 if( max_dist <= dist ) 390 { 391 max_dist = dist; 392 farthest_i = i; 393 } 394 } 395 396 counters[max_k]--; 397 counters[k]++; 398 labels[farthest_i] = k; 399 sample = data.ptr<float>(farthest_i); 400 401 for( j = 0; j < dims; j++ ) 402 { 403 old_center[j] -= sample[j]; 404 new_center[j] += sample[j]; 405 } 406 } 407 408 for( k = 0; k < K; k++ ) 409 { 410 float* center = centers.ptr<float>(k); 411 CV_Assert( counters[k] != 0 ); 412 413 float scale = 1.f/counters[k]; 414 for( j = 0; j < dims; j++ ) 415 center[j] *= scale; 416 417 if( iter > 0 ) 418 { 419 double dist = 0; 420 const float* old_center = old_centers.ptr<float>(k); 421 for( j = 0; j < dims; j++ ) 422 { 423 double t = center[j] - old_center[j]; 424 dist += t*t; 425 } 426 max_center_shift = std::max(max_center_shift, dist); 427 } 428 } 429 } 430 431 if( ++iter == MAX(criteria.maxCount, 2) || max_center_shift <= criteria.epsilon ) 432 break; 433 434 // assign labels 435 Mat dists(1, N, CV_64F); 436 double* dist = dists.ptr<double>(0); 437 parallel_for_(Range(0, N), 438 KMeansDistanceComputer(dist, labels, data, centers)); 439 compactness = 0; 440 for( i = 0; i < N; i++ ) 441 { 442 compactness += dist[i]; 443 } 444 } 445 446 if( compactness < best_compactness ) 447 { 448 best_compactness = compactness; 449 if( _centers.needed() ) 450 centers.copyTo(_centers); 451 _labels.copyTo(best_labels); 452 } 453 } 454 455 return best_compactness; 456 } 457