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