【opencv学习之三十七】图像的矩及矩的匹配

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/abcvincent/article/details/79312900

图像的矩是归一化的灰度级图像的二维随机变量的概率密度,是一个统计学特征。OpenCV中实现了这个矩的算子是Moments();其中分为零阶矩M00、一阶矩M10和M01、二阶矩M20,M02和M11;其中当图像为二值图时,M00是图像面积(白色区域)的总和,或者说连通域的面积;而这时M10和M01是图像白色区域上x和y坐标值的累计,所以图像的的重心(Xc,Yc)可以由:

Xc=M10/M00;

Yc=M01/M00;

图像的二阶矩一般用来求图像的方向,方法是:


下面是OpenCV的实现代码:

1.调用opencv的矩算子:

//图像的矩
//根据S.M.罗斯的概率论教程,一阶矩指E[X],即数列X的均值称为一阶矩。
//以此类推,E[Xn] ,n≥1,称为X的 n阶矩,也就是二阶矩、三阶矩...
//1. 矩的概念
//图像识别的一个核心问题是图像的特征提取,简单描述即为用一组简单的
//数据(图像描述量)来描述整个图像,这组数据越简单越有代表性越好。
//良好的特征不受光线、噪点、几何形变的干扰。图像识别发展几十年,
//不断有新的特征提出,而图像不变矩就是其中一个。
//矩是概率与统计中的一个概念,是随机变量的一种数字特征。设XX为随
//机变量,cc为常数,kk为正整数。则量E[(x−c)k]E[(x−c)k]称为XX关
//于cc点的kk阶矩。
//比较重要的有两种情况:
//1. c=0c=0。这时ak=E(Xk)ak=E(Xk)称为XX的kk阶原点矩
//2. c=E(X)c=E(X)。这时μk=E[(X−EX)k]μk=E[(X−EX)k]称为XX的kk阶中心矩。
//一阶原点矩就是期望。一阶中心矩μ1=0μ1=0,二阶中心矩μ2μ2就是XX的方
//差Var(X)Var(X)。在统计学上,高于4阶的矩极少使用。μ3μ3可以去衡量分布
//是否有偏。μ4μ4可以去衡量分布(密度)在均值附近的陡峭程度如何。
//针对于一幅图像,我们把像素的坐标看成是一个二维随机变量(X,Y)(X,Y),那么
//一幅灰度图像可以用二维灰度密度函数来表示,因此可以用矩来描述灰度图像的特征。
//不变矩(Invariant Moments)是一处高度浓缩的图像特征,具有平移、灰度、尺
//度、旋转不变性。M.K.Hu在1961年首先提出了不变矩的概念。1979年M.R.Teague
//根据正交多项式理论提出了Zernike矩。下面主要介绍这两种矩特征的算法原理与实现。

void imgMoment()//27图像的矩
{
    //1.查找轮廓前的预处理
    Mat srcImg = imread("D:/ImageTest/11.png");
    Mat copyImg = srcImg.clone();
    cvtColor(srcImg, srcImg, CV_BGR2GRAY);
    threshold(srcImg, srcImg, 100, 255, CV_THRESH_BINARY_INV);
    imshow("thresh", srcImg);
    //2.查找轮廓
    vector<vector<Point>> contours;
    findContours(srcImg, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);//最外层轮廓
    drawContours(copyImg, contours, -1, Scalar(0, 255, 0), 2, 8);
    //3.轮廓矩的计算
    Moments moments0 = moments(contours[0],false);//计算轮廓矩
    cout << moments0.m00<< endl;//输出空间矩之一的m00
    //4添加文字
    char outText[10] = { 0 };
    double outValue =moments0.m00 ;
    sprintf(outText, "%.1f", outValue);
    putText(copyImg,  outText, Point(10, 50),//起始点
            CV_FONT_HERSHEY_COMPLEX, //字体
            2, //字体大小
            Scalar(0, 255, 0), 2, 8);
    imshow("contours", copyImg);
    waitKey(0);
}

效果:


2.矩的其他参数,角度,重心,面积:

void imgMoment2()//图像的矩其他参数
{
    //1.查找轮廓前的预处理
    Mat srcImg = imread("D:/ImageTest/12.png");
    Mat copyImg = srcImg.clone();
    cvtColor(srcImg, srcImg, CV_BGR2GRAY);
    threshold(srcImg, srcImg, 100, 255, CV_THRESH_BINARY_INV);
    imshow("thresh", srcImg);
    //2.查找轮廓
    vector<vector<Point>> contours;
    findContours(srcImg, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);//最外层轮廓
    drawContours(copyImg, contours, -1, Scalar(0, 255, 0), 2, 8);
    //3.轮廓矩的计算
    Moments moments0 = moments(contours[0],false);//计算轮廓矩
    cout << moments0.m00<< endl;//输出空间矩之一的m00
    //4添加文字
    char outText[10] = { 0 };
    double outValue =moments0.m00 ;
    sprintf(outText, "%.1f", outValue);
    putText(copyImg,  outText, Point(10, 50),//起始点
            CV_FONT_HERSHEY_COMPLEX, //字体
            2, //字体大小
            Scalar(0, 255, 0), 2, 8);

    Moments m = moments(contours[0], true);//moments()函数计算出三阶及以下的矩
    Point2d center(m.m10 / m.m00, m.m01 / m.m00);//此为重心
    //计算方向
    double a = m.m20 / m.m00 - center.x*center.x;
    double b = m.m11 / m.m00 - center.x*center.y;
    double c = m.m02 / m.m00 - center.y*center.y;
    double theta = fastAtan2(2*b,(a - c))/2;//此为形状的方向
    cout <<"theta:"<<theta<<endl;

    circle(copyImg,Point(m.m10 / m.m00, m.m01 / m.m00),3,Scalar(0,0,255),-1,8);
    char outText2[10] = { 0 };
    double outValue2 =m.m10 / m.m00 ;
    sprintf(outText2, "%.1f", outValue2);
    putText(copyImg, outText2, Point(m.m10 / m.m00, m.m01 / m.m00),//起始点
            CV_FONT_HERSHEY_COMPLEX, //字体
            1, //字体大小
            Scalar(0, 0,255), 1, 8);

    char outText3[10] = { 0 };
    double outValue3 =m.m01 / m.m00 ;
    sprintf(outText3, "%.1f", outValue3);
    putText(copyImg, outText3, Point(m.m10 / m.m00+100, m.m01 / m.m00),//起始点
            CV_FONT_HERSHEY_COMPLEX, //字体
            1, //字体大小
            Scalar(0, 0, 255), 1, 8);

    char outText4[10] = { 0 };
    double outValue4 =theta ;
    sprintf(outText4, "%.1f", outValue4);
    putText(copyImg, outText4, Point(m.m10 / m.m00, m.m01 / m.m00+25),//起始点
            CV_FONT_HERSHEY_COMPLEX, //字体
            1, //字体大小
            Scalar(255, 0, 0), 1, 8);

    imshow("moments", copyImg);
    waitKey(0);
}

效果:


3.图像hu矩:

void imgHuMoment()//图像hu矩
{
    //    不变矩(Invariant Moments)是一处高度浓缩的图像特征,具有平移、
    //    灰度、尺度、旋转不变性。M.K.Hu在1961年首先提出了不变矩的概
    //    念。1979年M.R.Teague根据正交多项式理论提出了Zernike矩;
    //    利用二阶和三阶规格中心矩可以导出7个不变矩组(Φ1 Φ7)(Φ1 Φ7),
    //    它们在图像平移、旋转和比例变化时保持不变。OpenCV只有Hu矩阵封装;

    Mat image = imread("D:/ImageTest/lena.png");
    Mat copyImg=image.clone();
    cvtColor(image, image, CV_BGR2GRAY);
    Moments mts = moments(image);
    double hu[7];
    HuMoments(mts, hu);
    for (int i=0; i<7; i++)
    {
        cout << log(abs(hu[i])) <<endl;//7个值

        char outText0[10] = { 0 };
        double outValue0 =i ;
        sprintf(outText0, "%.0f", outValue0);
        putText(copyImg, outText0, Point(5, 30+30*i),//起始点
                CV_FONT_HERSHEY_COMPLEX, //字体
                1, //字体大小
                Scalar(255, 0,255), 2, 8);

        char outText[10] = { 0 };
        double outValue =log(abs(hu[i])) ;
        sprintf(outText, "%.1f", outValue);
        putText(copyImg, outText, Point(35, 30+30*i),//起始点
                CV_FONT_HERSHEY_COMPLEX, //字体
                1, //字体大小
                Scalar(0, 0, 255), 2, 8);
    }
    imshow("moments", copyImg);
    waitKey(0);
}

效果:


4.图像矩的匹配:

void imgMatchShapes()//图像矩和匹配
{
    //1.查找模版图像的轮廓
    Mat templateImg = imread("D:/ImageTest/0tu.JPG");
    Mat copyImg1 = templateImg.clone();
    GaussianBlur(templateImg, templateImg,Size(5,5),0);//高斯滤波去除小噪点
    cvtColor(templateImg, templateImg, CV_BGR2GRAY);
    threshold(templateImg, templateImg, 100, 255, CV_THRESH_BINARY_INV );
    imshow("thresh1", templateImg);
    vector<vector<Point>> contours1;
    findContours(templateImg, contours1, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);//最外层轮廓
    drawContours(copyImg1, contours1, -1, Scalar(0, 255, 0), 2, 8);
     imshow("contours1", copyImg1);

     //2.查找待测试图像的轮廓
     Mat testImg = imread("D:/ImageTest/t.png");
     Mat copyImg2 = testImg.clone();
     GaussianBlur(testImg, testImg,Size(5,5),0);//高斯滤波去除小噪点
     cvtColor(testImg, testImg, CV_BGR2GRAY);
     threshold(testImg, testImg, 100, 255, CV_THRESH_BINARY_INV);//确保黑中找白
     imshow("thresh2", testImg);
     vector<vector<Point>> contours2;
     findContours(testImg, contours2, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);//最外层轮廓
     //     drawContours(copyImg2, contours2, -1, Scalar(0, 255, 0), 1, 8);
     //     imshow("contours2", copyImg2);

     //3.形状匹配---比较两个形状或轮廓间的相似度
     for (int i = 0; i < contours2.size();i++)//遍历待测试图像的轮廓
     {
         //返回此轮廓与模版轮廓之间的相似度,a0越小越相似
         double a0 = matchShapes(contours1[0],contours2[i],CV_CONTOURS_MATCH_I1,0);
         cout << "match  " << i << "  value: " << a0 << endl;//输出两个轮廓间的相似度
         if (a0<0.05)//如果此轮廓与模版轮廓的相似度小于0.1
         {
             drawContours(copyImg2, contours2, i, Scalar(0, 255, 0), 2, 8);//则在待测试图像上画出此轮廓
         }
         else
         {
          drawContours(copyImg2, contours2, i, Scalar(0, 0, 255), 2, 8);//红色轮廓没有匹配上
         }
         imshow("copyImg2", copyImg2);
         if (waitKey(0) == 27)//等待按键进行下一个轮廓,ESC则退出
         {
             cout << "ESC" << endl;
             break;
         }
     }
//     imshow("copyImg2", copyImg2);
    waitKey(0);
}

效果:


猜你喜欢

转载自blog.csdn.net/abcvincent/article/details/79312900