converted moments function to C++
authorVadim Pisarevsky <vadim.pisarevsky@gmail.com>
Tue, 12 Feb 2013 14:07:22 +0000 (18:07 +0400)
committerVadim Pisarevsky <vadim.pisarevsky@gmail.com>
Tue, 12 Feb 2013 14:07:22 +0000 (18:07 +0400)
modules/imgproc/src/moments.cpp
modules/imgproc/test/test_moments.cpp

index 784a61b..f197e17 100644 (file)
 //M*/
 #include "precomp.hpp"
 
+namespace cv
+{
+
 // The function calculates center of gravity and the central second order moments
-static void icvCompleteMomentState( CvMoments* moments )
+static void completeMomentState( Moments* moments )
 {
     double cx = 0, cy = 0;
     double mu20, mu11, mu02;
 
     assert( moments != 0 );
-    moments->inv_sqrt_m00 = 0;
 
     if( fabs(moments->m00) > DBL_EPSILON )
     {
         double inv_m00 = 1. / moments->m00;
         cx = moments->m10 * inv_m00;
         cy = moments->m01 * inv_m00;
-        moments->inv_sqrt_m00 = std::sqrt( fabs(inv_m00) );
     }
 
     // mu20 = m20 - m10*cx
@@ -80,115 +81,111 @@ static void icvCompleteMomentState( CvMoments* moments )
 }
 
 
-static void icvContourMoments( CvSeq* contour, CvMoments* moments )
+static Moments contourMoments( const Mat& contour )
 {
-    int is_float = CV_SEQ_ELTYPE(contour) == CV_32FC2;
+    Moments m;
+    int lpt = contour.checkVector(2);
+    int is_float = contour.depth() == CV_32F;
+    const Point* ptsi = (const Point*)contour.data;
+    const Point2f* ptsf = (const Point2f*)contour.data;
 
-    if( contour->total )
-    {
-        CvSeqReader reader;
-        double a00, a10, a01, a20, a11, a02, a30, a21, a12, a03;
-        double xi, yi, xi2, yi2, xi_1, yi_1, xi_12, yi_12, dxy, xii_1, yii_1;
-        int lpt = contour->total;
+    CV_Assert( contour.depth() == CV_32S || contour.depth() == CV_32F );
 
-        a00 = a10 = a01 = a20 = a11 = a02 = a30 = a21 = a12 = a03 = 0;
+    if( lpt == 0 )
+        return m;
+
+    double a00 = 0, a10 = 0, a01 = 0, a20 = 0, a11 = 0, a02 = 0, a30 = 0, a21 = 0, a12 = 0, a03 = 0;
+    double xi, yi, xi2, yi2, xi_1, yi_1, xi_12, yi_12, dxy, xii_1, yii_1;
+
+    if( !is_float )
+    {
+        xi_1 = ptsi[lpt-1].x;
+        yi_1 = ptsi[lpt-1].y;
+    }
+    else
+    {
+        xi_1 = ptsf[lpt-1].x;
+        yi_1 = ptsf[lpt-1].y;
+    }
 
-        cvStartReadSeq( contour, &reader, 0 );
+    xi_12 = xi_1 * xi_1;
+    yi_12 = yi_1 * yi_1;
 
+    for( int i = 0; i < lpt; i++ )
+    {
         if( !is_float )
         {
-            xi_1 = ((CvPoint*)(reader.ptr))->x;
-            yi_1 = ((CvPoint*)(reader.ptr))->y;
+            xi = ptsi[i].x;
+            yi = ptsi[i].y;
         }
         else
         {
-            xi_1 = ((CvPoint2D32f*)(reader.ptr))->x;
-            yi_1 = ((CvPoint2D32f*)(reader.ptr))->y;
+            xi = ptsf[i].x;
+            yi = ptsf[i].y;
         }
-        CV_NEXT_SEQ_ELEM( contour->elem_size, reader );
 
-        xi_12 = xi_1 * xi_1;
-        yi_12 = yi_1 * yi_1;
+        xi2 = xi * xi;
+        yi2 = yi * yi;
+        dxy = xi_1 * yi - xi * yi_1;
+        xii_1 = xi_1 + xi;
+        yii_1 = yi_1 + yi;
+
+        a00 += dxy;
+        a10 += dxy * xii_1;
+        a01 += dxy * yii_1;
+        a20 += dxy * (xi_1 * xii_1 + xi2);
+        a11 += dxy * (xi_1 * (yii_1 + yi_1) + xi * (yii_1 + yi));
+        a02 += dxy * (yi_1 * yii_1 + yi2);
+        a30 += dxy * xii_1 * (xi_12 + xi2);
+        a03 += dxy * yii_1 * (yi_12 + yi2);
+        a21 += dxy * (xi_12 * (3 * yi_1 + yi) + 2 * xi * xi_1 * yii_1 +
+                   xi2 * (yi_1 + 3 * yi));
+        a12 += dxy * (yi_12 * (3 * xi_1 + xi) + 2 * yi * yi_1 * xii_1 +
+                   yi2 * (xi_1 + 3 * xi));
+        xi_1 = xi;
+        yi_1 = yi;
+        xi_12 = xi2;
+        yi_12 = yi2;
+    }
 
-        while( lpt-- > 0 )
+    if( fabs(a00) > FLT_EPSILON )
+    {
+        double db1_2, db1_6, db1_12, db1_24, db1_20, db1_60;
+        
+        if( a00 > 0 )
         {
-            if( !is_float )
-            {
-                xi = ((CvPoint*)(reader.ptr))->x;
-                yi = ((CvPoint*)(reader.ptr))->y;
-            }
-            else
-            {
-                xi = ((CvPoint2D32f*)(reader.ptr))->x;
-                yi = ((CvPoint2D32f*)(reader.ptr))->y;
-            }
-            CV_NEXT_SEQ_ELEM( contour->elem_size, reader );
-
-            xi2 = xi * xi;
-            yi2 = yi * yi;
-            dxy = xi_1 * yi - xi * yi_1;
-            xii_1 = xi_1 + xi;
-            yii_1 = yi_1 + yi;
-
-            a00 += dxy;
-            a10 += dxy * xii_1;
-            a01 += dxy * yii_1;
-            a20 += dxy * (xi_1 * xii_1 + xi2);
-            a11 += dxy * (xi_1 * (yii_1 + yi_1) + xi * (yii_1 + yi));
-            a02 += dxy * (yi_1 * yii_1 + yi2);
-            a30 += dxy * xii_1 * (xi_12 + xi2);
-            a03 += dxy * yii_1 * (yi_12 + yi2);
-            a21 +=
-                dxy * (xi_12 * (3 * yi_1 + yi) + 2 * xi * xi_1 * yii_1 +
-                       xi2 * (yi_1 + 3 * yi));
-            a12 +=
-                dxy * (yi_12 * (3 * xi_1 + xi) + 2 * yi * yi_1 * xii_1 +
-                       yi2 * (xi_1 + 3 * xi));
-
-            xi_1 = xi;
-            yi_1 = yi;
-            xi_12 = xi2;
-            yi_12 = yi2;
+            db1_2 = 0.5;
+            db1_6 = 0.16666666666666666666666666666667;
+            db1_12 = 0.083333333333333333333333333333333;
+            db1_24 = 0.041666666666666666666666666666667;
+            db1_20 = 0.05;
+            db1_60 = 0.016666666666666666666666666666667;
         }
-
-        double db1_2, db1_6, db1_12, db1_24, db1_20, db1_60;
-
-        if( fabs(a00) > FLT_EPSILON )
+        else
         {
-            if( a00 > 0 )
-            {
-                db1_2 = 0.5;
-                db1_6 = 0.16666666666666666666666666666667;
-                db1_12 = 0.083333333333333333333333333333333;
-                db1_24 = 0.041666666666666666666666666666667;
-                db1_20 = 0.05;
-                db1_60 = 0.016666666666666666666666666666667;
-            }
-            else
-            {
-                db1_2 = -0.5;
-                db1_6 = -0.16666666666666666666666666666667;
-                db1_12 = -0.083333333333333333333333333333333;
-                db1_24 = -0.041666666666666666666666666666667;
-                db1_20 = -0.05;
-                db1_60 = -0.016666666666666666666666666666667;
-            }
-
-            // spatial moments
-            moments->m00 = a00 * db1_2;
-            moments->m10 = a10 * db1_6;
-            moments->m01 = a01 * db1_6;
-            moments->m20 = a20 * db1_12;
-            moments->m11 = a11 * db1_24;
-            moments->m02 = a02 * db1_12;
-            moments->m30 = a30 * db1_20;
-            moments->m21 = a21 * db1_60;
-            moments->m12 = a12 * db1_60;
-            moments->m03 = a03 * db1_20;
-
-            icvCompleteMomentState( moments );
+            db1_2 = -0.5;
+            db1_6 = -0.16666666666666666666666666666667;
+            db1_12 = -0.083333333333333333333333333333333;
+            db1_24 = -0.041666666666666666666666666666667;
+            db1_20 = -0.05;
+            db1_60 = -0.016666666666666666666666666666667;
         }
+
+        // spatial moments
+        m.m00 = a00 * db1_2;
+        m.m10 = a10 * db1_6;
+        m.m01 = a01 * db1_6;
+        m.m20 = a20 * db1_12;
+        m.m11 = a11 * db1_24;
+        m.m02 = a02 * db1_12;
+        m.m30 = a30 * db1_20;
+        m.m21 = a21 * db1_60;
+        m.m12 = a12 * db1_60;
+        m.m03 = a03 * db1_20;
+
+        completeMomentState( &m );
     }
+    return m;
 }
 
 
@@ -197,9 +194,9 @@ static void icvContourMoments( CvSeq* contour, CvMoments* moments )
 \****************************************************************************************/
 
 template<typename T, typename WT, typename MT>
-static void momentsInTile( const cv::Mat& img, double* moments )
+static void momentsInTile( const Mat& img, double* moments )
 {
-    cv::Size size = img.size();
+    Size size = img.size();
     int x, y;
     MT mom[10] = {0,0,0,0,0,0,0,0,0,0};
 
@@ -247,10 +244,10 @@ template<> void momentsInTile<uchar, int, int>( const cv::Mat& img, double* mome
     typedef uchar T;
     typedef int WT;
     typedef int MT;
-    cv::Size size = img.size();
+    Size size = img.size();
     int y;
     MT mom[10] = {0,0,0,0,0,0,0,0,0,0};
-    bool useSIMD = cv::checkHardwareSupport(CV_CPU_SSE2);
+    bool useSIMD = checkHardwareSupport(CV_CPU_SSE2);
 
     for( y = 0; y < size.height; y++ )
     {
@@ -318,62 +315,89 @@ template<> void momentsInTile<uchar, int, int>( const cv::Mat& img, double* mome
 
 #endif
 
-typedef void (*CvMomentsInTileFunc)(const cv::Mat& img, double* moments);
+typedef void (*MomentsInTileFunc)(const Mat& img, double* moments);
 
-CV_IMPL void cvMoments( const void* array, CvMoments* moments, int binary )
+Moments::Moments()
 {
-    const int TILE_SIZE = 32;
-    int type, depth, cn, coi = 0;
-    CvMat stub, *mat = (CvMat*)array;
-    CvMomentsInTileFunc func = 0;
-    CvContour contourHeader;
-    CvSeq* contour = 0;
-    CvSeqBlock block;
-    double buf[TILE_SIZE*TILE_SIZE];
-    uchar nzbuf[TILE_SIZE*TILE_SIZE];
+    m00 = m10 = m01 = m20 = m11 = m02 = m30 = m21 = m12 = m03 =
+    mu20 = mu11 = mu02 = mu30 = mu21 = mu12 = mu03 =
+    nu20 = nu11 = nu02 = nu30 = nu21 = nu12 = nu03 = 0.;
+}
+
+Moments::Moments( double _m00, double _m10, double _m01, double _m20, double _m11,
+                  double _m02, double _m30, double _m21, double _m12, double _m03 )
+{
+    m00 = _m00; m10 = _m10; m01 = _m01;
+    m20 = _m20; m11 = _m11; m02 = _m02;
+    m30 = _m30; m21 = _m21; m12 = _m12; m03 = _m03;
 
-    if( CV_IS_SEQ( array ))
+    double cx = 0, cy = 0, inv_m00 = 0;
+    if( std::abs(m00) > DBL_EPSILON )
     {
-        contour = (CvSeq*)array;
-        if( !CV_IS_SEQ_POINT_SET( contour ))
-            CV_Error( CV_StsBadArg, "The passed sequence is not a valid contour" );
+        inv_m00 = 1./m00;
+        cx = m10*inv_m00; cy = m01*inv_m00;
     }
 
-    if( !moments )
-        CV_Error( CV_StsNullPtr, "" );
+    mu20 = m20 - m10*cx;
+    mu11 = m11 - m10*cy;
+    mu02 = m02 - m01*cy;
 
-    memset( moments, 0, sizeof(*moments));
+    mu30 = m30 - cx*(3*mu20 + cx*m10);
+    mu21 = m21 - cx*(2*mu11 + cx*m01) - cy*mu20;
+    mu12 = m12 - cy*(2*mu11 + cy*m10) - cx*mu02;
+    mu03 = m03 - cy*(3*mu02 + cy*m01);
 
-    if( !contour )
-    {
-        mat = cvGetMat( mat, &stub, &coi );
-        type = CV_MAT_TYPE( mat->type );
+    double inv_sqrt_m00 = std::sqrt(std::abs(inv_m00));
+    double s2 = inv_m00*inv_m00, s3 = s2*inv_sqrt_m00;
 
-        if( type == CV_32SC2 || type == CV_32FC2 )
-        {
-            contour = cvPointSeqFromMat(
-                CV_SEQ_KIND_CURVE | CV_SEQ_FLAG_CLOSED,
-                mat, &contourHeader, &block );
-        }
-    }
+    nu20 = mu20*s2; nu11 = mu11*s2; nu02 = mu02*s2;
+    nu30 = mu30*s3; nu21 = mu21*s3; nu12 = mu12*s3; nu03 = mu03*s3;
+}
 
-    if( contour )
-    {
-        icvContourMoments( contour, moments );
-        return;
-    }
+Moments::Moments( const CvMoments& m )
+{
+    *this = Moments(m.m00, m.m10, m.m01, m.m20, m.m11, m.m02, m.m30, m.m21, m.m12, m.m03);
+}
+
+Moments::operator CvMoments() const
+{
+    CvMoments m;
+    m.m00 = m00; m.m10 = m10; m.m01 = m01;
+    m.m20 = m20; m.m11 = m11; m.m02 = m02;
+    m.m30 = m30; m.m21 = m21; m.m12 = m12; m.m03 = m03;
+    m.mu20 = mu20; m.mu11 = mu11; m.mu02 = mu02;
+    m.mu30 = mu30; m.mu21 = mu21; m.mu12 = mu12; m.mu03 = mu03;
+    double am00 = std::abs(m00);
+    m.inv_sqrt_m00 = am00 > DBL_EPSILON ? 1./std::sqrt(am00) : 0;
+
+    return m;
+}
+
+}
+
+
+cv::Moments cv::moments( InputArray _src, bool binary )
+{
+    const int TILE_SIZE = 32;
+    Mat mat = _src.getMat();
+    MomentsInTileFunc func = 0;
+    double buf[TILE_SIZE*TILE_SIZE];
+    uchar nzbuf[TILE_SIZE*TILE_SIZE];
+    Moments m;
+    int type = mat.type();
+    int depth = CV_MAT_DEPTH( type );
+    int cn = CV_MAT_CN( type );
 
-    type = CV_MAT_TYPE( mat->type );
-    depth = CV_MAT_DEPTH( type );
-    cn = CV_MAT_CN( type );
+    if( mat.checkVector(2) >= 0 && (depth == CV_32F || depth == CV_32S))
+        return contourMoments(mat);
 
-    cv::Size size = cvGetMatSize( mat );
+    Size size = mat.size();
 
-    if( cn > 1 && coi == 0 )
+    if( cn > 1 )
         CV_Error( CV_StsBadArg, "Invalid image type" );
 
     if( size.width <= 0 || size.height <= 0 )
-        return;
+        return m;
 
     if( binary || depth == CV_8U )
         func = momentsInTile<uchar, int, int>;
@@ -388,25 +412,18 @@ CV_IMPL void cvMoments( const void* array, CvMoments* moments, int binary )
     else
         CV_Error( CV_StsUnsupportedFormat, "" );
 
-    cv::Mat src0(mat);
+    Mat src0(mat);
 
     for( int y = 0; y < size.height; y += TILE_SIZE )
     {
-        cv::Size tileSize;
+        Size tileSize;
         tileSize.height = std::min(TILE_SIZE, size.height - y);
 
         for( int x = 0; x < size.width; x += TILE_SIZE )
         {
             tileSize.width = std::min(TILE_SIZE, size.width - x);
-            cv::Mat src(src0, cv::Rect(x, y, tileSize.width, tileSize.height));
+            Mat src(src0, cv::Rect(x, y, tileSize.width, tileSize.height));
 
-            if( coi > 0 )
-            {
-                cv::Mat tmp(tileSize, depth, buf);
-                int pairs[] = {coi-1, 0};
-                cv::mixChannels(&src, 1, &tmp, 1, pairs, 1);
-                src = tmp;
-            }
             if( binary )
             {
                 cv::Mat tmp(tileSize, CV_8U, nzbuf);
@@ -429,77 +446,89 @@ CV_IMPL void cvMoments( const void* array, CvMoments* moments, int binary )
             // accumulate moments computed in each tile
 
             // + m00 ( = m00' )
-            moments->m00 += mom[0];
+            m.m00 += mom[0];
 
             // + m10 ( = m10' + x*m00' )
-            moments->m10 += mom[1] + xm;
+            m.m10 += mom[1] + xm;
 
             // + m01 ( = m01' + y*m00' )
-            moments->m01 += mom[2] + ym;
+            m.m01 += mom[2] + ym;
 
             // + m20 ( = m20' + 2*x*m10' + x*x*m00' )
-            moments->m20 += mom[3] + x * (mom[1] * 2 + xm);
+            m.m20 += mom[3] + x * (mom[1] * 2 + xm);
 
             // + m11 ( = m11' + x*m01' + y*m10' + x*y*m00' )
-            moments->m11 += mom[4] + x * (mom[2] + ym) + y * mom[1];
+            m.m11 += mom[4] + x * (mom[2] + ym) + y * mom[1];
 
             // + m02 ( = m02' + 2*y*m01' + y*y*m00' )
-            moments->m02 += mom[5] + y * (mom[2] * 2 + ym);
+            m.m02 += mom[5] + y * (mom[2] * 2 + ym);
 
             // + m30 ( = m30' + 3*x*m20' + 3*x*x*m10' + x*x*x*m00' )
-            moments->m30 += mom[6] + x * (3. * mom[3] + x * (3. * mom[1] + xm));
+            m.m30 += mom[6] + x * (3. * mom[3] + x * (3. * mom[1] + xm));
 
             // + m21 ( = m21' + x*(2*m11' + 2*y*m10' + x*m01' + x*y*m00') + y*m20')
-            moments->m21 += mom[7] + x * (2 * (mom[4] + y * mom[1]) + x * (mom[2] + ym)) + y * mom[3];
+            m.m21 += mom[7] + x * (2 * (mom[4] + y * mom[1]) + x * (mom[2] + ym)) + y * mom[3];
 
             // + m12 ( = m12' + y*(2*m11' + 2*x*m01' + y*m10' + x*y*m00') + x*m02')
-            moments->m12 += mom[8] + y * (2 * (mom[4] + x * mom[2]) + y * (mom[1] + xm)) + x * mom[5];
+            m.m12 += mom[8] + y * (2 * (mom[4] + x * mom[2]) + y * (mom[1] + xm)) + x * mom[5];
 
             // + m03 ( = m03' + 3*y*m02' + 3*y*y*m01' + y*y*y*m00' )
-            moments->m03 += mom[9] + y * (3. * mom[5] + y * (3. * mom[2] + ym));
+            m.m03 += mom[9] + y * (3. * mom[5] + y * (3. * mom[2] + ym));
         }
     }
-
-    icvCompleteMomentState( moments );
+    
+    completeMomentState( &m );
+    return m;
 }
 
 
-CV_IMPL void cvGetHuMoments( CvMoments * mState, CvHuMoments * HuState )
+void cv::HuMoments( const Moments& m, double hu[7] )
 {
-    if( !mState || !HuState )
-        CV_Error( CV_StsNullPtr, "" );
-
-    double m00s = mState->inv_sqrt_m00, m00 = m00s * m00s, s2 = m00 * m00, s3 = s2 * m00s;
-
-    double nu20 = mState->mu20 * s2,
-        nu11 = mState->mu11 * s2,
-        nu02 = mState->mu02 * s2,
-        nu30 = mState->mu30 * s3,
-        nu21 = mState->mu21 * s3, nu12 = mState->mu12 * s3, nu03 = mState->mu03 * s3;
-
-    double t0 = nu30 + nu12;
-    double t1 = nu21 + nu03;
+    double t0 = m.nu30 + m.nu12;
+    double t1 = m.nu21 + m.nu03;
 
     double q0 = t0 * t0, q1 = t1 * t1;
 
-    double n4 = 4 * nu11;
-    double s = nu20 + nu02;
-    double d = nu20 - nu02;
+    double n4 = 4 * m.nu11;
+    double s = m.nu20 + m.nu02;
+    double d = m.nu20 - m.nu02;
 
-    HuState->hu1 = s;
-    HuState->hu2 = d * d + n4 * nu11;
-    HuState->hu4 = q0 + q1;
-    HuState->hu6 = d * (q0 - q1) + n4 * t0 * t1;
+    hu[0] = s;
+    hu[1] = d * d + n4 * m.nu11;
+    hu[3] = q0 + q1;
+    hu[5] = d * (q0 - q1) + n4 * t0 * t1;
 
     t0 *= q0 - 3 * q1;
     t1 *= 3 * q0 - q1;
 
-    q0 = nu30 - 3 * nu12;
-    q1 = 3 * nu21 - nu03;
+    q0 = m.nu30 - 3 * m.nu12;
+    q1 = 3 * m.nu21 - m.nu03;
 
-    HuState->hu3 = q0 * q0 + q1 * q1;
-    HuState->hu5 = q0 * t0 + q1 * t1;
-    HuState->hu7 = q1 * t0 - q0 * t1;
+    hu[2] = q0 * q0 + q1 * q1;
+    hu[4] = q0 * t0 + q1 * t1;
+    hu[6] = q1 * t0 - q0 * t1;
+}
+
+void cv::HuMoments( const Moments& m, OutputArray _hu )
+{
+    _hu.create(7, 1, CV_64F);
+    Mat hu = _hu.getMat();
+    CV_Assert( hu.isContinuous() );
+    HuMoments(m, (double*)hu.data);
+}
+
+
+CV_IMPL void cvMoments( const CvArr* arr, CvMoments* moments, int binary )
+{
+    const IplImage* img = (const IplImage*)arr;
+    cv::Mat src;
+    if( CV_IS_IMAGE(arr) && img->roi && img->roi->coi > 0 )
+        cv::extractImageCOI(arr, src, img->roi->coi-1);
+    else
+        src = cv::cvarrToMat(arr);
+    cv::Moments m = cv::moments(src, binary != 0);
+    CV_Assert( moments != 0 );
+    *moments = m;
 }
 
 
@@ -526,7 +555,7 @@ CV_IMPL double cvGetCentralMoment( CvMoments * moments, int x_order, int y_order
         CV_Error( CV_StsOutOfRange, "" );
 
     return order >= 2 ? (&(moments->m00))[4 + order * 3 + y_order] :
-           order == 0 ? moments->m00 : 0;
+    order == 0 ? moments->m00 : 0;
 }
 
 
@@ -543,109 +572,43 @@ CV_IMPL double cvGetNormalizedCentralMoment( CvMoments * moments, int x_order, i
 }
 
 
-namespace cv
-{
-
-Moments::Moments()
-{
-    m00 = m10 = m01 = m20 = m11 = m02 = m30 = m21 = m12 = m03 =
-    mu20 = mu11 = mu02 = mu30 = mu21 = mu12 = mu03 =
-    nu20 = nu11 = nu02 = nu30 = nu21 = nu12 = nu03 = 0.;
-}
-
-Moments::Moments( double _m00, double _m10, double _m01, double _m20, double _m11,
-                  double _m02, double _m30, double _m21, double _m12, double _m03 )
-{
-    m00 = _m00; m10 = _m10; m01 = _m01;
-    m20 = _m20; m11 = _m11; m02 = _m02;
-    m30 = _m30; m21 = _m21; m12 = _m12; m03 = _m03;
-
-    double cx = 0, cy = 0, inv_m00 = 0;
-    if( std::abs(m00) > DBL_EPSILON )
-    {
-        inv_m00 = 1./m00;
-        cx = m10*inv_m00; cy = m01*inv_m00;
-    }
-
-    mu20 = m20 - m10*cx;
-    mu11 = m11 - m10*cy;
-    mu02 = m02 - m01*cy;
-
-    mu30 = m30 - cx*(3*mu20 + cx*m10);
-    mu21 = m21 - cx*(2*mu11 + cx*m01) - cy*mu20;
-    mu12 = m12 - cy*(2*mu11 + cy*m10) - cx*mu02;
-    mu03 = m03 - cy*(3*mu02 + cy*m01);
-
-    double inv_sqrt_m00 = std::sqrt(std::abs(inv_m00));
-    double s2 = inv_m00*inv_m00, s3 = s2*inv_sqrt_m00;
-
-    nu20 = mu20*s2; nu11 = mu11*s2; nu02 = mu02*s2;
-    nu30 = mu30*s3; nu21 = mu21*s3; nu12 = mu12*s3; nu03 = mu03*s3;
-}
-
-Moments::Moments( const CvMoments& m )
-{
-    *this = Moments(m.m00, m.m10, m.m01, m.m20, m.m11, m.m02, m.m30, m.m21, m.m12, m.m03);
-}
-
-Moments::operator CvMoments() const
+CV_IMPL void cvGetHuMoments( CvMoments * mState, CvHuMoments * HuState )
 {
-    CvMoments m;
-    m.m00 = m00; m.m10 = m10; m.m01 = m01;
-    m.m20 = m20; m.m11 = m11; m.m02 = m02;
-    m.m30 = m30; m.m21 = m21; m.m12 = m12; m.m03 = m03;
-    m.mu20 = mu20; m.mu11 = mu11; m.mu02 = mu02;
-    m.mu30 = mu30; m.mu21 = mu21; m.mu12 = mu12; m.mu03 = mu03;
-    double am00 = std::abs(m00);
-    m.inv_sqrt_m00 = am00 > DBL_EPSILON ? 1./std::sqrt(am00) : 0;
-
-    return m;
-}
+    if( !mState || !HuState )
+        CV_Error( CV_StsNullPtr, "" );
 
-}
+    double m00s = mState->inv_sqrt_m00, m00 = m00s * m00s, s2 = m00 * m00, s3 = s2 * m00s;
 
-cv::Moments cv::moments( InputArray _array, bool binaryImage )
-{
-    CvMoments om;
-    Mat arr = _array.getMat();
-    CvMat c_array = arr;
-    cvMoments(&c_array, &om, binaryImage);
-    return om;
-}
+    double nu20 = mState->mu20 * s2,
+    nu11 = mState->mu11 * s2,
+    nu02 = mState->mu02 * s2,
+    nu30 = mState->mu30 * s3,
+    nu21 = mState->mu21 * s3, nu12 = mState->mu12 * s3, nu03 = mState->mu03 * s3;
 
-void cv::HuMoments( const Moments& m, double hu[7] )
-{
-    double t0 = m.nu30 + m.nu12;
-    double t1 = m.nu21 + m.nu03;
+    double t0 = nu30 + nu12;
+    double t1 = nu21 + nu03;
 
     double q0 = t0 * t0, q1 = t1 * t1;
 
-    double n4 = 4 * m.nu11;
-    double s = m.nu20 + m.nu02;
-    double d = m.nu20 - m.nu02;
+    double n4 = 4 * nu11;
+    double s = nu20 + nu02;
+    double d = nu20 - nu02;
 
-    hu[0] = s;
-    hu[1] = d * d + n4 * m.nu11;
-    hu[3] = q0 + q1;
-    hu[5] = d * (q0 - q1) + n4 * t0 * t1;
+    HuState->hu1 = s;
+    HuState->hu2 = d * d + n4 * nu11;
+    HuState->hu4 = q0 + q1;
+    HuState->hu6 = d * (q0 - q1) + n4 * t0 * t1;
 
     t0 *= q0 - 3 * q1;
     t1 *= 3 * q0 - q1;
 
-    q0 = m.nu30 - 3 * m.nu12;
-    q1 = 3 * m.nu21 - m.nu03;
+    q0 = nu30 - 3 * nu12;
+    q1 = 3 * nu21 - nu03;
 
-    hu[2] = q0 * q0 + q1 * q1;
-    hu[4] = q0 * t0 + q1 * t1;
-    hu[6] = q1 * t0 - q0 * t1;
+    HuState->hu3 = q0 * q0 + q1 * q1;
+    HuState->hu5 = q0 * t0 + q1 * t1;
+    HuState->hu7 = q1 * t0 - q0 * t1;
 }
 
-void cv::HuMoments( const Moments& m, OutputArray _hu )
-{
-    _hu.create(7, 1, CV_64F);
-    Mat hu = _hu.getMat();
-    CV_Assert( hu.isContinuous() );
-    HuMoments(m, (double*)hu.data);
-}
 
 /* End of file. */
index 17a46cf..c58d1f5 100644 (file)
@@ -111,6 +111,8 @@ void CV_MomentsTest::get_test_array_types_and_sizes( int test_case_idx,
     types[INPUT][0] = CV_MAKETYPE(depth, cn);
     types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_64FC1;
     sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(MOMENT_COUNT,1);
+    if(CV_MAT_DEPTH(types[INPUT][0])>=CV_32S)
+        sizes[INPUT][0].width = MAX(sizes[INPUT][0].width, 3);
 
     is_binary = cvtest::randInt(rng) % 2 != 0;
     coi = 0;