Home | History | Annotate | Download | only in core
      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 // Copyright (C) 2015, Itseez Inc., all rights reserved.
     17 // Third party copyrights are property of their respective owners.
     18 //
     19 // Redistribution and use in source and binary forms, with or without modification,
     20 // are permitted provided that the following conditions are met:
     21 //
     22 //   * Redistribution's of source code must retain the above copyright notice,
     23 //     this list of conditions and the following disclaimer.
     24 //
     25 //   * Redistribution's in binary form must reproduce the above copyright notice,
     26 //     this list of conditions and the following disclaimer in the documentation
     27 //     and/or other materials provided with the distribution.
     28 //
     29 //   * The name of the copyright holders may not be used to endorse or promote products
     30 //     derived from this software without specific prior written permission.
     31 //
     32 // This software is provided by the copyright holders and contributors "as is" and
     33 // any express or implied warranties, including, but not limited to, the implied
     34 // warranties of merchantability and fitness for a particular purpose are disclaimed.
     35 // In no event shall the Intel Corporation or contributors be liable for any direct,
     36 // indirect, incidental, special, exemplary, or consequential damages
     37 // (including, but not limited to, procurement of substitute goods or services;
     38 // loss of use, data, or profits; or business interruption) however caused
     39 // and on any theory of liability, whether in contract, strict liability,
     40 // or tort (including negligence or otherwise) arising in any way out of
     41 // the use of this software, even if advised of the possibility of such damage.
     42 //
     43 //M*/
     44 
     45 #ifndef __OPENCV_CORE_OPERATIONS_HPP__
     46 #define __OPENCV_CORE_OPERATIONS_HPP__
     47 
     48 #ifndef __cplusplus
     49 #  error operations.hpp header must be compiled as C++
     50 #endif
     51 
     52 #include <cstdio>
     53 
     54 //! @cond IGNORED
     55 
     56 namespace cv
     57 {
     58 
     59 ////////////////////////////// Matx methods depending on core API /////////////////////////////
     60 
     61 namespace internal
     62 {
     63 
     64 template<typename _Tp, int m> struct Matx_FastInvOp
     65 {
     66     bool operator()(const Matx<_Tp, m, m>& a, Matx<_Tp, m, m>& b, int method) const
     67     {
     68         Matx<_Tp, m, m> temp = a;
     69 
     70         // assume that b is all 0's on input => make it a unity matrix
     71         for( int i = 0; i < m; i++ )
     72             b(i, i) = (_Tp)1;
     73 
     74         if( method == DECOMP_CHOLESKY )
     75             return Cholesky(temp.val, m*sizeof(_Tp), m, b.val, m*sizeof(_Tp), m);
     76 
     77         return LU(temp.val, m*sizeof(_Tp), m, b.val, m*sizeof(_Tp), m) != 0;
     78     }
     79 };
     80 
     81 template<typename _Tp> struct Matx_FastInvOp<_Tp, 2>
     82 {
     83     bool operator()(const Matx<_Tp, 2, 2>& a, Matx<_Tp, 2, 2>& b, int) const
     84     {
     85         _Tp d = determinant(a);
     86         if( d == 0 )
     87             return false;
     88         d = 1/d;
     89         b(1,1) = a(0,0)*d;
     90         b(0,0) = a(1,1)*d;
     91         b(0,1) = -a(0,1)*d;
     92         b(1,0) = -a(1,0)*d;
     93         return true;
     94     }
     95 };
     96 
     97 template<typename _Tp> struct Matx_FastInvOp<_Tp, 3>
     98 {
     99     bool operator()(const Matx<_Tp, 3, 3>& a, Matx<_Tp, 3, 3>& b, int) const
    100     {
    101         _Tp d = (_Tp)determinant(a);
    102         if( d == 0 )
    103             return false;
    104         d = 1/d;
    105         b(0,0) = (a(1,1) * a(2,2) - a(1,2) * a(2,1)) * d;
    106         b(0,1) = (a(0,2) * a(2,1) - a(0,1) * a(2,2)) * d;
    107         b(0,2) = (a(0,1) * a(1,2) - a(0,2) * a(1,1)) * d;
    108 
    109         b(1,0) = (a(1,2) * a(2,0) - a(1,0) * a(2,2)) * d;
    110         b(1,1) = (a(0,0) * a(2,2) - a(0,2) * a(2,0)) * d;
    111         b(1,2) = (a(0,2) * a(1,0) - a(0,0) * a(1,2)) * d;
    112 
    113         b(2,0) = (a(1,0) * a(2,1) - a(1,1) * a(2,0)) * d;
    114         b(2,1) = (a(0,1) * a(2,0) - a(0,0) * a(2,1)) * d;
    115         b(2,2) = (a(0,0) * a(1,1) - a(0,1) * a(1,0)) * d;
    116         return true;
    117     }
    118 };
    119 
    120 
    121 template<typename _Tp, int m, int n> struct Matx_FastSolveOp
    122 {
    123     bool operator()(const Matx<_Tp, m, m>& a, const Matx<_Tp, m, n>& b,
    124                     Matx<_Tp, m, n>& x, int method) const
    125     {
    126         Matx<_Tp, m, m> temp = a;
    127         x = b;
    128         if( method == DECOMP_CHOLESKY )
    129             return Cholesky(temp.val, m*sizeof(_Tp), m, x.val, n*sizeof(_Tp), n);
    130 
    131         return LU(temp.val, m*sizeof(_Tp), m, x.val, n*sizeof(_Tp), n) != 0;
    132     }
    133 };
    134 
    135 template<typename _Tp> struct Matx_FastSolveOp<_Tp, 2, 1>
    136 {
    137     bool operator()(const Matx<_Tp, 2, 2>& a, const Matx<_Tp, 2, 1>& b,
    138                     Matx<_Tp, 2, 1>& x, int) const
    139     {
    140         _Tp d = determinant(a);
    141         if( d == 0 )
    142             return false;
    143         d = 1/d;
    144         x(0) = (b(0)*a(1,1) - b(1)*a(0,1))*d;
    145         x(1) = (b(1)*a(0,0) - b(0)*a(1,0))*d;
    146         return true;
    147     }
    148 };
    149 
    150 template<typename _Tp> struct Matx_FastSolveOp<_Tp, 3, 1>
    151 {
    152     bool operator()(const Matx<_Tp, 3, 3>& a, const Matx<_Tp, 3, 1>& b,
    153                     Matx<_Tp, 3, 1>& x, int) const
    154     {
    155         _Tp d = (_Tp)determinant(a);
    156         if( d == 0 )
    157             return false;
    158         d = 1/d;
    159         x(0) = d*(b(0)*(a(1,1)*a(2,2) - a(1,2)*a(2,1)) -
    160                 a(0,1)*(b(1)*a(2,2) - a(1,2)*b(2)) +
    161                 a(0,2)*(b(1)*a(2,1) - a(1,1)*b(2)));
    162 
    163         x(1) = d*(a(0,0)*(b(1)*a(2,2) - a(1,2)*b(2)) -
    164                 b(0)*(a(1,0)*a(2,2) - a(1,2)*a(2,0)) +
    165                 a(0,2)*(a(1,0)*b(2) - b(1)*a(2,0)));
    166 
    167         x(2) = d*(a(0,0)*(a(1,1)*b(2) - b(1)*a(2,1)) -
    168                 a(0,1)*(a(1,0)*b(2) - b(1)*a(2,0)) +
    169                 b(0)*(a(1,0)*a(2,1) - a(1,1)*a(2,0)));
    170         return true;
    171     }
    172 };
    173 
    174 } // internal
    175 
    176 template<typename _Tp, int m, int n> inline
    177 Matx<_Tp,m,n> Matx<_Tp,m,n>::randu(_Tp a, _Tp b)
    178 {
    179     Matx<_Tp,m,n> M;
    180     cv::randu(M, Scalar(a), Scalar(b));
    181     return M;
    182 }
    183 
    184 template<typename _Tp, int m, int n> inline
    185 Matx<_Tp,m,n> Matx<_Tp,m,n>::randn(_Tp a, _Tp b)
    186 {
    187     Matx<_Tp,m,n> M;
    188     cv::randn(M, Scalar(a), Scalar(b));
    189     return M;
    190 }
    191 
    192 template<typename _Tp, int m, int n> inline
    193 Matx<_Tp, n, m> Matx<_Tp, m, n>::inv(int method, bool *p_is_ok /*= NULL*/) const
    194 {
    195     Matx<_Tp, n, m> b;
    196     bool ok;
    197     if( method == DECOMP_LU || method == DECOMP_CHOLESKY )
    198         ok = cv::internal::Matx_FastInvOp<_Tp, m>()(*this, b, method);
    199     else
    200     {
    201         Mat A(*this, false), B(b, false);
    202         ok = (invert(A, B, method) != 0);
    203     }
    204     if( NULL != p_is_ok ) { *p_is_ok = ok; }
    205     return ok ? b : Matx<_Tp, n, m>::zeros();
    206 }
    207 
    208 template<typename _Tp, int m, int n> template<int l> inline
    209 Matx<_Tp, n, l> Matx<_Tp, m, n>::solve(const Matx<_Tp, m, l>& rhs, int method) const
    210 {
    211     Matx<_Tp, n, l> x;
    212     bool ok;
    213     if( method == DECOMP_LU || method == DECOMP_CHOLESKY )
    214         ok = cv::internal::Matx_FastSolveOp<_Tp, m, l>()(*this, rhs, x, method);
    215     else
    216     {
    217         Mat A(*this, false), B(rhs, false), X(x, false);
    218         ok = cv::solve(A, B, X, method);
    219     }
    220 
    221     return ok ? x : Matx<_Tp, n, l>::zeros();
    222 }
    223 
    224 
    225 
    226 ////////////////////////// Augmenting algebraic & logical operations //////////////////////////
    227 
    228 #define CV_MAT_AUG_OPERATOR1(op, cvop, A, B) \
    229     static inline A& operator op (A& a, const B& b) { cvop; return a; }
    230 
    231 #define CV_MAT_AUG_OPERATOR(op, cvop, A, B)   \
    232     CV_MAT_AUG_OPERATOR1(op, cvop, A, B)      \
    233     CV_MAT_AUG_OPERATOR1(op, cvop, const A, B)
    234 
    235 #define CV_MAT_AUG_OPERATOR_T(op, cvop, A, B)                   \
    236     template<typename _Tp> CV_MAT_AUG_OPERATOR1(op, cvop, A, B) \
    237     template<typename _Tp> CV_MAT_AUG_OPERATOR1(op, cvop, const A, B)
    238 
    239 CV_MAT_AUG_OPERATOR  (+=, cv::add(a,b,a), Mat, Mat)
    240 CV_MAT_AUG_OPERATOR  (+=, cv::add(a,b,a), Mat, Scalar)
    241 CV_MAT_AUG_OPERATOR_T(+=, cv::add(a,b,a), Mat_<_Tp>, Mat)
    242 CV_MAT_AUG_OPERATOR_T(+=, cv::add(a,b,a), Mat_<_Tp>, Scalar)
    243 CV_MAT_AUG_OPERATOR_T(+=, cv::add(a,b,a), Mat_<_Tp>, Mat_<_Tp>)
    244 
    245 CV_MAT_AUG_OPERATOR  (-=, cv::subtract(a,b,a), Mat, Mat)
    246 CV_MAT_AUG_OPERATOR  (-=, cv::subtract(a,b,a), Mat, Scalar)
    247 CV_MAT_AUG_OPERATOR_T(-=, cv::subtract(a,b,a), Mat_<_Tp>, Mat)
    248 CV_MAT_AUG_OPERATOR_T(-=, cv::subtract(a,b,a), Mat_<_Tp>, Scalar)
    249 CV_MAT_AUG_OPERATOR_T(-=, cv::subtract(a,b,a), Mat_<_Tp>, Mat_<_Tp>)
    250 
    251 CV_MAT_AUG_OPERATOR  (*=, cv::gemm(a, b, 1, Mat(), 0, a, 0), Mat, Mat)
    252 CV_MAT_AUG_OPERATOR_T(*=, cv::gemm(a, b, 1, Mat(), 0, a, 0), Mat_<_Tp>, Mat)
    253 CV_MAT_AUG_OPERATOR_T(*=, cv::gemm(a, b, 1, Mat(), 0, a, 0), Mat_<_Tp>, Mat_<_Tp>)
    254 CV_MAT_AUG_OPERATOR  (*=, a.convertTo(a, -1, b), Mat, double)
    255 CV_MAT_AUG_OPERATOR_T(*=, a.convertTo(a, -1, b), Mat_<_Tp>, double)
    256 
    257 CV_MAT_AUG_OPERATOR  (/=, cv::divide(a,b,a), Mat, Mat)
    258 CV_MAT_AUG_OPERATOR_T(/=, cv::divide(a,b,a), Mat_<_Tp>, Mat)
    259 CV_MAT_AUG_OPERATOR_T(/=, cv::divide(a,b,a), Mat_<_Tp>, Mat_<_Tp>)
    260 CV_MAT_AUG_OPERATOR  (/=, a.convertTo((Mat&)a, -1, 1./b), Mat, double)
    261 CV_MAT_AUG_OPERATOR_T(/=, a.convertTo((Mat&)a, -1, 1./b), Mat_<_Tp>, double)
    262 
    263 CV_MAT_AUG_OPERATOR  (&=, cv::bitwise_and(a,b,a), Mat, Mat)
    264 CV_MAT_AUG_OPERATOR  (&=, cv::bitwise_and(a,b,a), Mat, Scalar)
    265 CV_MAT_AUG_OPERATOR_T(&=, cv::bitwise_and(a,b,a), Mat_<_Tp>, Mat)
    266 CV_MAT_AUG_OPERATOR_T(&=, cv::bitwise_and(a,b,a), Mat_<_Tp>, Scalar)
    267 CV_MAT_AUG_OPERATOR_T(&=, cv::bitwise_and(a,b,a), Mat_<_Tp>, Mat_<_Tp>)
    268 
    269 CV_MAT_AUG_OPERATOR  (|=, cv::bitwise_or(a,b,a), Mat, Mat)
    270 CV_MAT_AUG_OPERATOR  (|=, cv::bitwise_or(a,b,a), Mat, Scalar)
    271 CV_MAT_AUG_OPERATOR_T(|=, cv::bitwise_or(a,b,a), Mat_<_Tp>, Mat)
    272 CV_MAT_AUG_OPERATOR_T(|=, cv::bitwise_or(a,b,a), Mat_<_Tp>, Scalar)
    273 CV_MAT_AUG_OPERATOR_T(|=, cv::bitwise_or(a,b,a), Mat_<_Tp>, Mat_<_Tp>)
    274 
    275 CV_MAT_AUG_OPERATOR  (^=, cv::bitwise_xor(a,b,a), Mat, Mat)
    276 CV_MAT_AUG_OPERATOR  (^=, cv::bitwise_xor(a,b,a), Mat, Scalar)
    277 CV_MAT_AUG_OPERATOR_T(^=, cv::bitwise_xor(a,b,a), Mat_<_Tp>, Mat)
    278 CV_MAT_AUG_OPERATOR_T(^=, cv::bitwise_xor(a,b,a), Mat_<_Tp>, Scalar)
    279 CV_MAT_AUG_OPERATOR_T(^=, cv::bitwise_xor(a,b,a), Mat_<_Tp>, Mat_<_Tp>)
    280 
    281 #undef CV_MAT_AUG_OPERATOR_T
    282 #undef CV_MAT_AUG_OPERATOR
    283 #undef CV_MAT_AUG_OPERATOR1
    284 
    285 
    286 
    287 ///////////////////////////////////////////// SVD /////////////////////////////////////////////
    288 
    289 inline SVD::SVD() {}
    290 inline SVD::SVD( InputArray m, int flags ) { operator ()(m, flags); }
    291 inline void SVD::solveZ( InputArray m, OutputArray _dst )
    292 {
    293     Mat mtx = m.getMat();
    294     SVD svd(mtx, (mtx.rows >= mtx.cols ? 0 : SVD::FULL_UV));
    295     _dst.create(svd.vt.cols, 1, svd.vt.type());
    296     Mat dst = _dst.getMat();
    297     svd.vt.row(svd.vt.rows-1).reshape(1,svd.vt.cols).copyTo(dst);
    298 }
    299 
    300 template<typename _Tp, int m, int n, int nm> inline void
    301     SVD::compute( const Matx<_Tp, m, n>& a, Matx<_Tp, nm, 1>& w, Matx<_Tp, m, nm>& u, Matx<_Tp, n, nm>& vt )
    302 {
    303     CV_StaticAssert( nm == MIN(m, n), "Invalid size of output vector.");
    304     Mat _a(a, false), _u(u, false), _w(w, false), _vt(vt, false);
    305     SVD::compute(_a, _w, _u, _vt);
    306     CV_Assert(_w.data == (uchar*)&w.val[0] && _u.data == (uchar*)&u.val[0] && _vt.data == (uchar*)&vt.val[0]);
    307 }
    308 
    309 template<typename _Tp, int m, int n, int nm> inline void
    310 SVD::compute( const Matx<_Tp, m, n>& a, Matx<_Tp, nm, 1>& w )
    311 {
    312     CV_StaticAssert( nm == MIN(m, n), "Invalid size of output vector.");
    313     Mat _a(a, false), _w(w, false);
    314     SVD::compute(_a, _w);
    315     CV_Assert(_w.data == (uchar*)&w.val[0]);
    316 }
    317 
    318 template<typename _Tp, int m, int n, int nm, int nb> inline void
    319 SVD::backSubst( const Matx<_Tp, nm, 1>& w, const Matx<_Tp, m, nm>& u,
    320                 const Matx<_Tp, n, nm>& vt, const Matx<_Tp, m, nb>& rhs,
    321                 Matx<_Tp, n, nb>& dst )
    322 {
    323     CV_StaticAssert( nm == MIN(m, n), "Invalid size of output vector.");
    324     Mat _u(u, false), _w(w, false), _vt(vt, false), _rhs(rhs, false), _dst(dst, false);
    325     SVD::backSubst(_w, _u, _vt, _rhs, _dst);
    326     CV_Assert(_dst.data == (uchar*)&dst.val[0]);
    327 }
    328 
    329 
    330 
    331 /////////////////////////////////// Multiply-with-Carry RNG ///////////////////////////////////
    332 
    333 inline RNG::RNG()              { state = 0xffffffff; }
    334 inline RNG::RNG(uint64 _state) { state = _state ? _state : 0xffffffff; }
    335 
    336 inline RNG::operator uchar()    { return (uchar)next(); }
    337 inline RNG::operator schar()    { return (schar)next(); }
    338 inline RNG::operator ushort()   { return (ushort)next(); }
    339 inline RNG::operator short()    { return (short)next(); }
    340 inline RNG::operator int()      { return (int)next(); }
    341 inline RNG::operator unsigned() { return next(); }
    342 inline RNG::operator float()    { return next()*2.3283064365386962890625e-10f; }
    343 inline RNG::operator double()   { unsigned t = next(); return (((uint64)t << 32) | next()) * 5.4210108624275221700372640043497e-20; }
    344 
    345 inline unsigned RNG::operator ()(unsigned N) { return (unsigned)uniform(0,N); }
    346 inline unsigned RNG::operator ()()           { return next(); }
    347 
    348 inline int    RNG::uniform(int a, int b)       { return a == b ? a : (int)(next() % (b - a) + a); }
    349 inline float  RNG::uniform(float a, float b)   { return ((float)*this)*(b - a) + a; }
    350 inline double RNG::uniform(double a, double b) { return ((double)*this)*(b - a) + a; }
    351 
    352 inline unsigned RNG::next()
    353 {
    354     state = (uint64)(unsigned)state* /*CV_RNG_COEFF*/ 4164903690U + (unsigned)(state >> 32);
    355     return (unsigned)state;
    356 }
    357 
    358 //! returns the next unifomly-distributed random number of the specified type
    359 template<typename _Tp> static inline _Tp randu()
    360 {
    361   return (_Tp)theRNG();
    362 }
    363 
    364 ///////////////////////////////// Formatted string generation /////////////////////////////////
    365 
    366 CV_EXPORTS String format( const char* fmt, ... );
    367 
    368 ///////////////////////////////// Formatted output of cv::Mat /////////////////////////////////
    369 
    370 static inline
    371 Ptr<Formatted> format(InputArray mtx, int fmt)
    372 {
    373     return Formatter::get(fmt)->format(mtx.getMat());
    374 }
    375 
    376 static inline
    377 int print(Ptr<Formatted> fmtd, FILE* stream = stdout)
    378 {
    379     int written = 0;
    380     fmtd->reset();
    381     for(const char* str = fmtd->next(); str; str = fmtd->next())
    382         written += fputs(str, stream);
    383 
    384     return written;
    385 }
    386 
    387 static inline
    388 int print(const Mat& mtx, FILE* stream = stdout)
    389 {
    390     return print(Formatter::get()->format(mtx), stream);
    391 }
    392 
    393 static inline
    394 int print(const UMat& mtx, FILE* stream = stdout)
    395 {
    396     return print(Formatter::get()->format(mtx.getMat(ACCESS_READ)), stream);
    397 }
    398 
    399 template<typename _Tp> static inline
    400 int print(const std::vector<Point_<_Tp> >& vec, FILE* stream = stdout)
    401 {
    402     return print(Formatter::get()->format(Mat(vec)), stream);
    403 }
    404 
    405 template<typename _Tp> static inline
    406 int print(const std::vector<Point3_<_Tp> >& vec, FILE* stream = stdout)
    407 {
    408     return print(Formatter::get()->format(Mat(vec)), stream);
    409 }
    410 
    411 template<typename _Tp, int m, int n> static inline
    412 int print(const Matx<_Tp, m, n>& matx, FILE* stream = stdout)
    413 {
    414     return print(Formatter::get()->format(cv::Mat(matx)), stream);
    415 }
    416 
    417 //! @endcond
    418 
    419 /****************************************************************************************\
    420 *                                  Auxiliary algorithms                                  *
    421 \****************************************************************************************/
    422 
    423 /** @brief Splits an element set into equivalency classes.
    424 
    425 The generic function partition implements an \f$O(N^2)\f$ algorithm for splitting a set of \f$N\f$ elements
    426 into one or more equivalency classes, as described in
    427 <http://en.wikipedia.org/wiki/Disjoint-set_data_structure> . The function returns the number of
    428 equivalency classes.
    429 @param _vec Set of elements stored as a vector.
    430 @param labels Output vector of labels. It contains as many elements as vec. Each label labels[i] is
    431 a 0-based cluster index of `vec[i]`.
    432 @param predicate Equivalence predicate (pointer to a boolean function of two arguments or an
    433 instance of the class that has the method bool operator()(const _Tp& a, const _Tp& b) ). The
    434 predicate returns true when the elements are certainly in the same class, and returns false if they
    435 may or may not be in the same class.
    436 @ingroup core_cluster
    437 */
    438 template<typename _Tp, class _EqPredicate> int
    439 partition( const std::vector<_Tp>& _vec, std::vector<int>& labels,
    440           _EqPredicate predicate=_EqPredicate())
    441 {
    442     int i, j, N = (int)_vec.size();
    443     const _Tp* vec = &_vec[0];
    444 
    445     const int PARENT=0;
    446     const int RANK=1;
    447 
    448     std::vector<int> _nodes(N*2);
    449     int (*nodes)[2] = (int(*)[2])&_nodes[0];
    450 
    451     // The first O(N) pass: create N single-vertex trees
    452     for(i = 0; i < N; i++)
    453     {
    454         nodes[i][PARENT]=-1;
    455         nodes[i][RANK] = 0;
    456     }
    457 
    458     // The main O(N^2) pass: merge connected components
    459     for( i = 0; i < N; i++ )
    460     {
    461         int root = i;
    462 
    463         // find root
    464         while( nodes[root][PARENT] >= 0 )
    465             root = nodes[root][PARENT];
    466 
    467         for( j = 0; j < N; j++ )
    468         {
    469             if( i == j || !predicate(vec[i], vec[j]))
    470                 continue;
    471             int root2 = j;
    472 
    473             while( nodes[root2][PARENT] >= 0 )
    474                 root2 = nodes[root2][PARENT];
    475 
    476             if( root2 != root )
    477             {
    478                 // unite both trees
    479                 int rank = nodes[root][RANK], rank2 = nodes[root2][RANK];
    480                 if( rank > rank2 )
    481                     nodes[root2][PARENT] = root;
    482                 else
    483                 {
    484                     nodes[root][PARENT] = root2;
    485                     nodes[root2][RANK] += rank == rank2;
    486                     root = root2;
    487                 }
    488                 CV_Assert( nodes[root][PARENT] < 0 );
    489 
    490                 int k = j, parent;
    491 
    492                 // compress the path from node2 to root
    493                 while( (parent = nodes[k][PARENT]) >= 0 )
    494                 {
    495                     nodes[k][PARENT] = root;
    496                     k = parent;
    497                 }
    498 
    499                 // compress the path from node to root
    500                 k = i;
    501                 while( (parent = nodes[k][PARENT]) >= 0 )
    502                 {
    503                     nodes[k][PARENT] = root;
    504                     k = parent;
    505                 }
    506             }
    507         }
    508     }
    509 
    510     // Final O(N) pass: enumerate classes
    511     labels.resize(N);
    512     int nclasses = 0;
    513 
    514     for( i = 0; i < N; i++ )
    515     {
    516         int root = i;
    517         while( nodes[root][PARENT] >= 0 )
    518             root = nodes[root][PARENT];
    519         // re-use the rank as the class label
    520         if( nodes[root][RANK] >= 0 )
    521             nodes[root][RANK] = ~nclasses++;
    522         labels[i] = ~nodes[root][RANK];
    523     }
    524 
    525     return nclasses;
    526 }
    527 
    528 } // cv
    529 
    530 #endif
    531