opencv中Hu矩的学习心得

Hu矩的确很神奇,它具有平移不变性、旋转不变性和缩放不变性,是图形匹配的一个不错的工具。

通过大致对Hu矩的学习,我认为对Hu矩的学习应该有一下几步,第一步要了解什么是矩;第二步再开始了解Hu矩。为了方便大家的使用,先简单介绍下Hu矩用于模板匹配的用法。

用法:

其实Hu矩用于匹配已经在opencv中的cvMatchShape函数中应用了,下面是cvMatchShape的源代码(可以跳过):

cvMatchShapes( const void* contour1, const void* contour2,
               int method, double )
{
    CvMoments moments;
    CvHuMoments huMoments;
    double ma[7], mb[7];
    int i, sma, smb;
    double eps = 1.e-5;
    double mmm;
    double result = 0;

    CV_FUNCNAME( "cvMatchShapes" );

    __BEGIN__;

    if( !contour1 || !contour2 )
        CV_ERROR( CV_StsNullPtr, "" );


    CV_CALL( cvMoments( contour1, &moments ));


    CV_CALL( cvGetHuMoments( &moments, &huMoments ));

    ma[0] = huMoments.hu1;
    ma[1] = huMoments.hu2;
    ma[2] = huMoments.hu3;
    ma[3] = huMoments.hu4;
    ma[4] = huMoments.hu5;
    ma[5] = huMoments.hu6;
    ma[6] = huMoments.hu7;



    CV_CALL( cvMoments( contour2, &moments ));


    CV_CALL( cvGetHuMoments( &moments, &huMoments ));

    mb[0] = huMoments.hu1;
    mb[1] = huMoments.hu2;
    mb[2] = huMoments.hu3;
    mb[3] = huMoments.hu4;
    mb[4] = huMoments.hu5;
    mb[5] = huMoments.hu6;
    mb[6] = huMoments.hu7;

    switch (method)
    {
    case 1:
        {
            for( i = 0; i < 7; i++ )
            {
                double ama = fabs( ma[i] );
                double amb = fabs( mb[i] );

                if( ma[i] > 0 )
                    sma = 1;
                else if( ma[i] < 0 )
                    sma = -1;
                else
                    sma = 0;
                if( mb[i] > 0 )
                    smb = 1;
                else if( mb[i] < 0 )
                    smb = -1;
                else
                    smb = 0;

                if( ama > eps && amb > eps )
                {
                    ama = 1. / (sma * log10( ama ));
                    amb = 1. / (smb * log10( amb ));
                    result += fabs( -ama + amb );
                }
            }
            break;
        }

    case 2:
        {
            for( i = 0; i < 7; i++ )
            {
                double ama = fabs( ma[i] );
                double amb = fabs( mb[i] );

                if( ma[i] > 0 )
                    sma = 1;
                else if( ma[i] < 0 )
                    sma = -1;
                else
                    sma = 0;
                if( mb[i] > 0 )
                    smb = 1;
                else if( mb[i] < 0 )
                    smb = -1;
                else
                    smb = 0;

                if( ama > eps && amb > eps )
                {
                    ama = sma * log10( ama );
                    amb = smb * log10( amb );
                    result += fabs( -ama + amb );
                }
            }
            break;
        }

    case 3:
        {
            for( i = 0; i < 7; i++ )
            {
                double ama = fabs( ma[i] );
                double amb = fabs( mb[i] );

                if( ma[i] > 0 )
                    sma = 1;
                else if( ma[i] < 0 )
                    sma = -1;
                else
                    sma = 0;
                if( mb[i] > 0 )
                    smb = 1;
                else if( mb[i] < 0 )
                    smb = -1;
                else
                    smb = 0;

                if( ama > eps && amb > eps )
                {
                    ama = sma * log10( ama );
                    amb = smb * log10( amb );
                    mmm = fabs( (ama - amb) / ama );
                    if( result < mmm )
                        result = mmm;
                }
            }
            break;
        }
    default:
        CV_ERROR_FROM_STATUS( CV_BADCOEF_ERR );
    }

    __END__;

    return result;
}

因此,我们只需要传入两个轮廓或两幅图片,再选择一种评价的方式,就可以用这个函数进行匹配了,至于hu矩,在这个函数中已经帮我们计算好了,我们只需要选择一种匹配的方法就可以的到一个评价相似性的值了,该函数提供了三种方法来评价这两幅图的相似性,值越小越相似。

如果我们要单独计算hu矩怎么办??

opencv中有一个结构体叫CvMoments,他的定义是

 typedef struct CvMoments
     {
          double  m00, m10, m01, m20, m11, m02, m30, m21, m12, m03;
          double  mu20, mu11, mu02, mu30, mu21, mu12, mu03;
          double  inv_sqrt_m00;
     }
     CvMoments;

这个结构体是用来保存矩的数据的,其中第一行是普通矩,第二行是中心距。接着有一个函数叫做CVAPI(void) cvMoments( const CvArr* arr, CvMoments* moments, int binary CV_DEFAULT(0));,这个函数是用来计算矩的,其中第一个参数是传入的图像,第二个参数是之前创建的CvMoments变量,第三个参数是是否二值化(如果是0的话,那么原图像是什么值就是什么值,如果大于0,就二值化,其中阀值我也不知道怎么确定的,但是和这个参数是没有关系的)。

同样,要计算Hu矩也有一个结构体叫CvHuMoments,他的定义是

typedef struct CvHuMoments
     {
           double hu1, hu2, hu3, hu4, hu5, hu6, hu7;
     }
       CvHuMoments;

这里用于储存计算出来的七个值,同时又有一个函数叫CVAPI(void) cvGetHuMoments( CvMoments*  moments, CvHuMoments*  hu_moments );用来计算Hu矩,其中第一个参数就是上面所计算好的moments,第二个参数就是刚创建的CvHuMoments hu_moments,计算的结果就保存的这个变量中。

以上就是我认为用hu矩进行模板匹配的方法了。

接下来我按照第二段所述的步骤介绍下我对Hu矩的理解:

第一步什么是矩:个人认为,矩的理解可以从力矩上,在高中物理上力矩的定义是力乘以力臂,所以在图像中的矩也可以这么认为,它的定义参照http://www.cnblogs.com/skyseraph/archive/2011/07/19/2110183.html中所述,其中Xpq中p+q的值称为矩的阶数。

第二步什么是hu矩:hu矩就是利用矩里边的1阶矩、二阶矩和三阶矩经过算术运算构造出来的具有平移、缩放和旋转不变性的七个矩,在上面的网址中也有讲到,我也是从上面的那个网址中学习过。

本人初学opencv,以上仅是本人学习Hu矩的一点心得,如有发现错误,请回复,我将尽快更改,同时也希望对和我一样的初学者有一丝丝的帮助。

最后非常感谢以下作品及其作者:

http://www.cnblogs.com/skyseraph/archive/2011/07/19/2110183.html

http://v.youku.com/v_show/id_XNDcyOTE3MzQ4.html

发布了9 篇原创文章 · 获赞 7 · 访问量 5579

猜你喜欢

转载自blog.csdn.net/u013702040/article/details/84879924