OpenCV3历程(9)——图像的矩及矩的匹配

本文深入探讨了图像矩的概念及其在OpenCV中的应用,包括零阶矩、一阶矩和二阶矩的计算,以及如何利用这些矩来确定图像的重心、方向和面积。此外,还介绍了不变矩的特性及其在图像识别中的作用,展示了如何通过匹配图像矩来进行图像的相似度比较。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本片博客转载自(感谢博主分享):https://blog.youkuaiyun.com/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阶矩,也就是二阶矩、三阶矩...

  • 矩的概念:

图像识别的一个核心问题就是图像的特征提取,简单描述即为用一组简单的数据(图像描述量)来描述整个图像,这组数据越简单越有代表性越好。良好的特征不受光线、噪声、几何形变的干扰。图像识别发展几十年,不断有新的特征提出,而图像不变矩就是其中一个。矩是概率与统计中的一个概念,是随机变量的一种数字特征。

设XX为随机变量,CC为常数,kk为正整数,则量:E[(x−c)k]E[(x−c)k]称为XX关于CC点的kk阶矩。

比较重要的有两种情况:

(1)c=0,c=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);
}

效果:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值