1 // This file is part of OpenMVG, an Open Multiple View Geometry C++ library. 2 3 // Copyright (c) 2017 Romuald Perrot. 4 5 // This Source Code Form is subject to the terms of the Mozilla Public 6 // License, v. 2.0. If a copy of the MPL was not distributed with this 7 // file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 9 #ifndef _OPENMVG_KMEANS_TRAIT_HPP_ 10 #define _OPENMVG_KMEANS_TRAIT_HPP_ 11 12 #include "openMVG/numeric/eigen_alias_definition.hpp" 13 14 #include <algorithm> 15 #include <array> 16 #include <limits> 17 #include <random> 18 #include <vector> 19 20 namespace openMVG 21 { 22 namespace clustering 23 { 24 25 /** 26 * @brief Class used to detail parts of a vector in a generic way 27 * @note this is only tested with floating point type 28 */ 29 template< typename VectorType > 30 class KMeansVectorDataTrait 31 { 32 public: 33 /// base type 34 using type = VectorType; 35 36 /// Type of a scalar element 37 using scalar_type = VectorType; 38 39 /** 40 * @brief number of element in the vector 41 * @param aVector a Vector 42 * @return number of scalar element in the vector 43 */ 44 static size_t size( const type & aVector ); 45 46 /** 47 * @brief Square euclidean distance between two vectors 48 * @param aVec1 first vector 49 * @param aVec2 second vector 50 * @return square euclidean distance 51 */ 52 static scalar_type L2( const type & aVec1, const type & aVec2 ); 53 54 /** 55 * @brief Draw a random vector in a range 56 * @param min minimum bound of the sampling range 57 * @param max maximum bound of the sampling range 58 * @param rng A c++11 random generator 59 * @return a Random vector in the given range 60 */ 61 template < typename RngType > 62 static type random( const type & min, const type & max, RngType & rng ); 63 64 /** 65 * @brief Compute minimum and maximum value of a set of points 66 * @params elts list of points 67 * @param[out] min minimum (component-wise) of the points 68 * @param[out] max maximum (component-wise) of the points 69 */ 70 static void minMax( const std::vector<type> & elts, type & min, type & max ); 71 72 /** 73 * @brief get a zero valued vector data 74 * @param dummy a dummy vector 75 * @return a null vector 76 */ 77 static type null( const type & dummy ); 78 79 /** 80 * @brief Accumulate value inside a vector 81 * @param self vector used for accumulation 82 * @param data vector to add to the self vector 83 * @note this perform self += data (component-wise) 84 */ 85 static void accumulate( type & self, const type & data ); 86 87 /** 88 * @brief Scalar division 89 * @param self Vector to divide 90 * @param val scalar divisor 91 * @note this perform self /= data (component-wise) 92 */ 93 static void divide( type & self, const size_t val ); 94 }; 95 96 /** 97 * @brief overloading for std::array 98 */ 99 template< typename T, size_t N > 100 class KMeansVectorDataTrait<std::array<T, N>> 101 { 102 public: 103 using scalar_type = T; 104 using type = std::array<T, N>; 105 // Define alias for memory mapping 106 using VecType = Eigen::Matrix<scalar_type, 1, Eigen::Dynamic>; 107 using VecTypeMapConst = Eigen::Map<const VecType>; 108 using VecTypeMap = Eigen::Map<VecType>; 109 110 /** 111 * @brief number of element in the vector 112 * @param aVector a Vector 113 * @return number of scalar element in the vector 114 */ size(const type & aVector)115 static size_t size( const type & aVector ) 116 { 117 return N; 118 } 119 120 /** 121 * @brief Square euclidean distance between two vectors 122 * @param aVec1 first vector 123 * @param aVec2 second vector 124 * @return square euclidean distance 125 */ L2(const type & aVec1,const type & aVec2)126 static scalar_type L2( const type & aVec1, const type & aVec2 ) 127 { 128 VecTypeMapConst map_aVec1(aVec1.data(), aVec1.size()); 129 VecTypeMapConst map_aVec2(aVec2.data(), aVec2.size()); 130 return ( map_aVec1 - map_aVec2 ).squaredNorm(); 131 } 132 133 /** 134 * @brief Draw a random vector in a range 135 * @param min minimum bound of the sampling range 136 * @param max maximum bound of the sampling range 137 * @param rng A c++11 random generator 138 * @return a Random vector in the given range 139 */ 140 template < typename RngType > random(const type & min,const type & max,RngType & rng)141 static type random( const type & min, const type & max, RngType & rng ) 142 { 143 type res; 144 for( size_t id_dim = 0; id_dim < N; ++id_dim ) 145 { 146 std::uniform_real_distribution<scalar_type> distrib( min[id_dim], max[id_dim] ); 147 res[ id_dim ] = distrib( rng ); 148 } 149 return res; 150 } 151 152 /** 153 * @brief Compute minimum and maximum value of a set of points 154 * @params elts list of points 155 * @param[out] min minimum (component-wise) of the points 156 * @param[out] max maximum (component-wise) of the points 157 */ minMax(const std::vector<type> & elts,type & min,type & max)158 static void minMax( const std::vector<type> & elts, type & min, type & max ) 159 { 160 if( elts.size() == 0 ) 161 { 162 return; 163 } 164 165 // Init 166 std::fill( min.begin(), min.end(), std::numeric_limits<scalar_type>::max() ); 167 std::fill( max.begin(), max.end(), std::numeric_limits<scalar_type>::lowest() ); 168 169 // min/max search 170 for( size_t id_pt = 0; id_pt < elts.size(); ++id_pt ) 171 { 172 const type & cur_elt = elts[ id_pt ]; 173 for( size_t id_dim = 0; id_dim < cur_elt.size(); ++id_dim ) 174 { 175 // Get min_max for ith dim 176 min[ id_dim ] = std::min( min[id_dim], cur_elt[ id_dim ] ); 177 max[ id_dim ] = std::max( max[id_dim], cur_elt[ id_dim ] ); 178 } 179 } 180 } 181 182 /** 183 * @brief get a zero valued vector data 184 * @param dummy a dummy vector 185 * @return a null vector 186 */ null(const type & dummy)187 static type null( const type & dummy ) 188 { 189 type res; 190 res.fill( scalar_type( 0 ) ); 191 return res; 192 } 193 194 /** 195 * @brief Accumulate value inside a vector 196 * @param self vector used for accumulation 197 * @param data vector to add to the self vector 198 * @note this perform self += data (component-wise) 199 */ accumulate(type & self,const type & data)200 static void accumulate( type & self, const type & data ) 201 { 202 VecTypeMap map_self(self.data(), self.size()); 203 VecTypeMapConst map_data(data.data(), data.size()); 204 map_self += map_data; 205 } 206 207 /** 208 * @brief Scalar division 209 * @param self Vector to divide 210 * @param val scalar divisor 211 * @note this perform self /= data (component-wise) 212 */ divide(type & self,const size_t val)213 static void divide( type & self, const size_t val ) 214 { 215 VecTypeMap map_self(self.data(), self.size()); 216 map_self /= static_cast<scalar_type>( val ); 217 } 218 219 }; 220 221 /** 222 * @brief Overloading for std::vector 223 */ 224 template< typename T> 225 class KMeansVectorDataTrait<std::vector<T>> 226 { 227 public: 228 using scalar_type = T; 229 using type = std::vector<T>; 230 // Define alias for memory mapping 231 using VecType = Eigen::Matrix<scalar_type, 1, Eigen::Dynamic>; 232 using VecTypeMapConst = Eigen::Map<const VecType>; 233 using VecTypeMap = Eigen::Map<VecType>; 234 235 /** 236 * @brief number of element in the vector 237 * @param aVector a Vector 238 * @return number of scalar element in the vector 239 */ size(const type & aVector)240 static size_t size( const type & aVector ) 241 { 242 return aVector.size(); 243 } 244 245 /** 246 * @brief Square euclidean distance between two vectors 247 * @param aVec1 first vector 248 * @param aVec2 second vector 249 * @return square euclidean distance 250 */ L2(const type & aVec1,const type & aVec2)251 static scalar_type L2( const type & aVec1, const type & aVec2 ) 252 { 253 VecTypeMapConst map_aVec1(aVec1.data(), aVec1.size()); 254 VecTypeMapConst map_aVec2(aVec2.data(), aVec2.size()); 255 return ( map_aVec1 - map_aVec2 ).squaredNorm(); 256 } 257 258 /** 259 * @brief Draw a random vector in a range 260 * @param min minimum bound of the sampling range 261 * @param max maximum bound of the sampling range 262 * @param rng A c++11 random generator 263 * @return a Random vector in the given range 264 */ 265 template < typename RngType > random(const type & min,const type & max,RngType & rng)266 static type random( const type & min, const type & max, RngType & rng ) 267 { 268 type res( min ); 269 for( size_t id_dim = 0; id_dim < res.size(); ++id_dim ) 270 { 271 std::uniform_real_distribution<scalar_type> distrib( min[id_dim], max[id_dim] ); 272 res[ id_dim ] = distrib( rng ); 273 } 274 return res; 275 } 276 277 /** 278 * @brief Compute minimum and maximum value of a set of points 279 * @params elts list of points 280 * @param[out] min minimum (component-wise) of the points 281 * @param[out] max maximum (component-wise) of the points 282 */ minMax(const std::vector<type> & elts,type & min,type & max)283 static void minMax( const std::vector<type> & elts, type & min, type & max ) 284 { 285 if( elts.size() == 0 ) 286 { 287 return; 288 } 289 290 // Init 291 min.resize( elts[0].size(), std::numeric_limits<scalar_type>::max() ); 292 max.resize( elts[0].size(), std::numeric_limits<scalar_type>::lowest() ); 293 294 // min/max search 295 for( size_t id_pt = 0; id_pt < elts.size(); ++id_pt ) 296 { 297 const type & cur_elt = elts[ id_pt ]; 298 for( size_t id_dim = 0; id_dim < cur_elt.size(); ++id_dim ) 299 { 300 // Get min_max for ith dim 301 min[ id_dim ] = std::min( min[id_dim], cur_elt[ id_dim ] ); 302 max[ id_dim ] = std::max( max[id_dim], cur_elt[ id_dim ] ); 303 } 304 } 305 } 306 307 /** 308 * @brief get a zero valued vector data 309 * @param dummy a dummy vector 310 * @return a null vector 311 */ null(const type & dummy)312 static type null( const type & dummy ) 313 { 314 return type ( dummy.size(), scalar_type( 0 ) ); 315 } 316 317 /** 318 * @brief Accumulate value inside a vector 319 * @param self vector used for accumulation 320 * @param data vector to add to the self vector 321 * @note this perform self += data (component-wise) 322 */ accumulate(type & self,const type & data)323 static void accumulate( type & self, const type & data ) 324 { 325 VecTypeMap map_self(self.data(), self.size()); 326 VecTypeMapConst map_data(data.data(), data.size()); 327 map_self += map_data; 328 } 329 330 /** 331 * @brief Scalar division 332 * @param self Vector to divide 333 * @param val scalar divisor 334 * @note this perform self /= data (component-wise) 335 */ divide(type & self,const size_t val)336 static void divide( type & self, const size_t val ) 337 { 338 VecTypeMap map_self(self.data(), self.size()); 339 map_self /= static_cast<scalar_type>( val ); 340 } 341 }; 342 343 /* 344 ** @brief overloading for Eigen::Matrix<scalar_type, N, 1> 345 */ 346 template< typename T, int N > 347 class KMeansVectorDataTrait<Eigen::Matrix<T, N, 1>> 348 { 349 public: 350 using scalar_type = T; 351 using type = Eigen::Matrix<scalar_type, N, 1>; 352 353 /** 354 * @brief number of element in the vector 355 * @param aVector a Vector 356 * @return number of scalar element in the vector 357 */ size(const type & aVector)358 static size_t size( const type & aVector ) 359 { 360 return N; 361 } 362 363 /** 364 * @brief Square euclidean distance between two vectors 365 * @param aVec1 first vector 366 * @param aVec2 second vector 367 * @return square euclidean distance 368 */ L2(const type & aVec1,const type & aVec2)369 static scalar_type L2( const type & aVec1, const type & aVec2 ) 370 { 371 return ( aVec1 - aVec2 ).squaredNorm(); 372 } 373 374 /** 375 * @brief Draw a random vector in a range 376 * @param min minimum bound of the sampling range 377 * @param max maximum bound of the sampling range 378 * @param rng A c++11 random generator 379 * @return a Random vector in the given range 380 */ 381 template < typename RngType > random(const type & min,const type & max,RngType & rng)382 static type random( const type & min, const type & max, RngType & rng ) 383 { 384 type res; 385 for( size_t id_dim = 0; id_dim < N; ++id_dim ) 386 { 387 std::uniform_real_distribution<scalar_type> distrib( min[id_dim], max[id_dim] ); 388 res[ id_dim ] = distrib( rng ); 389 } 390 return res; 391 } 392 393 /** 394 * @brief Compute minimum and maximum value of a set of points 395 * @params elts list of points 396 * @param[out] min minimum (component-wise) of the points 397 * @param[out] max maximum (component-wise) of the points 398 */ minMax(const std::vector<type> & elts,type & min,type & max)399 static void minMax( const std::vector<type> & elts, type & min, type & max ) 400 { 401 if( elts.empty() ) 402 { 403 return; 404 } 405 406 // Init 407 min.Constant( std::numeric_limits<scalar_type>::max() ); 408 max.Constant( std::numeric_limits<scalar_type>::lowest() ); 409 410 // min/max search 411 for( size_t id_pt = 0; id_pt < elts.size(); ++id_pt ) 412 { 413 const type & cur_elt = elts[ id_pt ]; 414 min = min.cwiseMin( cur_elt ); 415 max = max.cwiseMax( cur_elt ); 416 } 417 } 418 419 /** 420 * @brief get a zero valued vector data 421 * @param dummy a dummy vector 422 * @return a null vector 423 */ null(const type & dummy)424 static type null( const type & dummy ) 425 { 426 return type::Zero(); 427 } 428 429 /** 430 * @brief Accumulate value inside a vector 431 * @param self vector used for accumulation 432 * @param data vector to add to the self vector 433 * @note this perform self += data (component-wise) 434 */ accumulate(type & self,const type & data)435 static void accumulate( type & self, const type & data ) 436 { 437 self += data; 438 } 439 440 /** 441 * @brief Scalar division 442 * @param self Vector to divide 443 * @param val scalar divisor 444 * @note this perform self /= data (component-wise) 445 */ divide(type & self,const size_t val)446 static void divide( type & self, const size_t val ) 447 { 448 self /= static_cast<scalar_type>( val ); 449 } 450 }; 451 452 /** 453 * @brief Specialization/Overloading for Vec 454 */ 455 template<> 456 class KMeansVectorDataTrait<Vec> 457 { 458 public: 459 using scalar_type = Vec::Scalar; 460 using type = Vec; 461 462 /** 463 * @brief number of element in the vector 464 * @param aVector a Vector 465 * @return number of scalar element in the vector 466 */ size(const type & aVector)467 static size_t size( const type & aVector ) 468 { 469 return aVector.size(); 470 } 471 472 /** 473 * @brief Square euclidean distance between two vectors 474 * @param aVec1 first vector 475 * @param aVec2 second vector 476 * @return square euclidean distance 477 */ L2(const type & aVec1,const type & aVec2)478 static scalar_type L2( const type & aVec1, const type & aVec2 ) 479 { 480 return ( aVec1 - aVec2 ).squaredNorm(); 481 } 482 483 /** 484 * @brief Draw a random vector in a range 485 * @param min minimum bound of the sampling range 486 * @param max maximum bound of the sampling range 487 * @param rng A c++11 random generator 488 * @return a Random vector in the given range 489 */ 490 template < typename RngType > random(const type & min,const type & max,RngType & rng)491 static type random( const type & min, const type & max, RngType & rng ) 492 { 493 Vec res( min.size() ); 494 for( size_t id_dim = 0; id_dim < res.size(); ++id_dim ) 495 { 496 std::uniform_real_distribution<scalar_type> distrib( min[0], max[0] ); 497 res[id_dim] = distrib( rng ); 498 } 499 return res; 500 } 501 502 /** 503 * @brief Compute minimum and maximum value of a set of points 504 * @params elts list of points 505 * @param[out] min minimum (component-wise) of the points 506 * @param[out] max maximum (component-wise) of the points 507 */ minMax(const std::vector<type> & elts,type & min,type & max)508 static void minMax( const std::vector<type> & elts, type & min, type & max ) 509 { 510 if( elts.size() == 0 ) 511 { 512 return; 513 } 514 515 // Init 516 min = Vec( elts[0].size() ); 517 min.fill( std::numeric_limits<scalar_type>::max() ); 518 max = Vec( elts[0].size() ); 519 max.fill( std::numeric_limits<scalar_type>::lowest() ); 520 521 // min/max search 522 for( size_t id_pt = 0; id_pt < elts.size(); ++id_pt ) 523 { 524 const type & cur_elt = elts[ id_pt ]; 525 min = min.cwiseMin( cur_elt ); 526 max = max.cwiseMax( cur_elt ); 527 } 528 } 529 530 /** 531 * @brief get a zero valued vector data 532 * @param dummy a dummy vector 533 * @return a null vector 534 */ null(const type & dummy)535 static type null( const type & dummy ) 536 { 537 static type res( dummy.size() ); 538 res.fill( scalar_type( 0 ) ); 539 return res; 540 } 541 542 /** 543 * @brief Accumulate value inside a vector 544 * @param self vector used for accumulation 545 * @param data vector to add to the self vector 546 * @note this perform self += data (component-wise) 547 */ accumulate(type & self,const type & data)548 static void accumulate( type & self, const type & data ) 549 { 550 self += data; 551 } 552 553 /** 554 * @brief Scalar division 555 * @param self Vector to divide 556 * @param val scalar divisor 557 * @note this perform self /= data (component-wise) 558 */ divide(type & self,const size_t val)559 static void divide( type & self, const size_t val ) 560 { 561 self /= static_cast<scalar_type>( val ); 562 } 563 }; 564 565 /** 566 * @brief Specialization/Overloading for Vecf 567 */ 568 template<> 569 class KMeansVectorDataTrait<Vecf> 570 { 571 public: 572 using scalar_type = Vecf::Scalar; 573 using type = Vecf; 574 575 /** 576 * @brief number of element in the vector 577 * @param aVector a Vector 578 * @return number of scalar element in the vector 579 */ size(const type & aVector)580 static size_t size( const type & aVector ) 581 { 582 return aVector.size(); 583 } 584 585 /** 586 * @brief Square euclidean distance between two vectors 587 * @param aVec1 first vector 588 * @param aVec2 second vector 589 * @return square euclidean distance 590 */ L2(const type & aVec1,const type & aVec2)591 static scalar_type L2( const type & aVec1, const type & aVec2 ) 592 { 593 return ( aVec1 - aVec2 ).squaredNorm(); 594 } 595 596 /** 597 * @brief Draw a random vector in a range 598 * @param min minimum bound of the sampling range 599 * @param max maximum bound of the sampling range 600 * @param rng A c++11 random generator 601 * @return a Random vector in the given range 602 */ 603 template < typename RngType > random(const type & min,const type & max,RngType & rng)604 static type random( const type & min, const type & max, RngType & rng ) 605 { 606 Vecf res( min.size() ); 607 for( size_t id_dim = 0; id_dim < res.size(); ++id_dim ) 608 { 609 std::uniform_real_distribution<scalar_type> distrib( min[0], max[0] ); 610 res[id_dim] = distrib( rng ); 611 } 612 return res; 613 } 614 615 /** 616 * @brief Compute minimum and maximum value of a set of points 617 * @params elts list of points 618 * @param[out] min minimum (component-wise) of the points 619 * @param[out] max maximum (component-wise) of the points 620 */ minMax(const std::vector<type> & elts,type & min,type & max)621 static void minMax( const std::vector<type> & elts, type & min, type & max ) 622 { 623 if( elts.size() == 0 ) 624 { 625 return; 626 } 627 628 // Init 629 min = Vecf( elts[0].size() ); 630 min.fill( std::numeric_limits<scalar_type>::max() ); 631 max = Vecf( elts[0].size() ); 632 max.fill( std::numeric_limits<scalar_type>::lowest() ); 633 634 // min/max search 635 for( size_t id_pt = 0; id_pt < elts.size(); ++id_pt ) 636 { 637 const type & cur_elt = elts[ id_pt ]; 638 min = min.cwiseMin( cur_elt ); 639 max = max.cwiseMax( cur_elt ); 640 } 641 } 642 643 /** 644 * @brief get a zero valued vector data 645 * @param dummy a dummy vector 646 * @return a null vector 647 */ null(const type & dummy)648 static type null( const type & dummy ) 649 { 650 static type res( dummy.size() ); 651 res.fill( scalar_type( 0 ) ); 652 return res; 653 } 654 655 /** 656 * @brief Accumulate value inside a vector 657 * @param self vector used for accumulation 658 * @param data vector to add to the self vector 659 * @note this perform self += data (component-wise) 660 */ accumulate(type & self,const type & data)661 static void accumulate( type & self, const type & data ) 662 { 663 self += data; 664 } 665 666 /** 667 * @brief Scalar division 668 * @param self Vector to divide 669 * @param val scalar divisor 670 * @note this perform self /= data (component-wise) 671 */ divide(type & self,const size_t val)672 static void divide( type & self, const size_t val ) 673 { 674 self /= static_cast<scalar_type>( val ); 675 } 676 }; 677 678 } // namespace clustering 679 } // namespace openMVG 680 681 #endif 682