OpenCV 笔记(15):轮廓的矩特征

矩(moment) 是概率与统计中的一个概念,是随机变量的一种数字特征,是对变量分布和形态特点的一组度量。

矩的定义如下:

<math xmlns="http://www.w3.org/1998/Math/MathML"> m n = ∫ − ∞ ∞ x n f ( x ) d x m_n = \textstyle \int_{-\infty}^{\infty} x^nf(x) dx </math>mn = ∫−∞∞xnf(x)dx

其中,f(x) 是随机变量的概率密度函数或概率质量函数,n 是正整数表示矩的阶数。

矩可以用来描述变量的均值、方差、偏度、峰度等特性。矩的性质如下:

  • 零阶矩是变量的均值。
  • 一阶矩是变量的均方根。
  • 二阶矩是变量的方差。
  • 三阶矩是变量的偏度。
  • 四阶矩是变量的峰度。

在图像处理中,图像的矩是指图像的某些特定像素灰度的加权平均值,或者是图像具有类似功能或意义的属性。图像矩可以表示图像的一些特征,通过这些特征便于对图像进行识别。

1. 空间矩/几何矩

空间矩 是图像矩特征中最基本的一种,它只考虑图像的像素值

<math xmlns="http://www.w3.org/1998/Math/MathML"> m p q = ∑ x , y f ( x , y ) ( x p + y q ) m_{pq} = \displaystyle \sum_{x,y} f(x,y)(x^p+y^q) </math>mpq = x,y∑ f(x,y)(xp+yq)

其中,f(x,y) 表示输入的图像,p、q 是正整数。

1.1 零阶矩

<math xmlns="http://www.w3.org/1998/Math/MathML"> m 00 = ∑ x , y f ( x , y ) m_{00} = \displaystyle \sum_{x,y} f(x,y) </math>m00 = x,y∑ f(x,y)

零阶矩可以用来描述图像的面积。

1.2 一阶矩

<math xmlns="http://www.w3.org/1998/Math/MathML"> m 10 = ∑ x , y x f ( x , y ) m_{10} = \displaystyle \sum_{x,y} xf(x,y) </math>m10 = x,y∑ xf(x,y)

<math xmlns="http://www.w3.org/1998/Math/MathML"> m 01 = ∑ x , y y f ( x , y ) m_{01} = \displaystyle \sum_{x,y} yf(x,y) </math>m01 = x,y∑ yf(x,y)

一阶矩可以用来描述图像的质心。

1.3 二阶矩

<math xmlns="http://www.w3.org/1998/Math/MathML"> m 20 = ∑ x , y x 2 f ( x , y ) m_{20} = \displaystyle \sum_{x,y} x^2f(x,y) </math>m20 = x,y∑ x2f(x,y)

<math xmlns="http://www.w3.org/1998/Math/MathML"> m 02 = ∑ x , y y 2 f ( x , y ) m_{02} = \displaystyle \sum_{x,y} y^2f(x,y) </math>m02 = x,y∑ y2f(x,y)

<math xmlns="http://www.w3.org/1998/Math/MathML"> m 11 = ∑ x , y x y f ( x , y ) m_{11} = \displaystyle \sum_{x,y} xyf(x,y) </math>m11 = x,y∑ xyf(x,y)

二阶矩可以用来描述图像的周长、长轴、短轴、扭矩等信息。

1.4 三阶矩

<math xmlns="http://www.w3.org/1998/Math/MathML"> m 30 = ∑ x , y x 3 f ( x , y ) m_{30} = \displaystyle \sum_{x,y}x^3f(x,y) </math>m30 = x,y∑x3f(x,y)

<math xmlns="http://www.w3.org/1998/Math/MathML"> m 03 = ∑ x , y y 3 f ( x , y ) m_{03} = \displaystyle \sum_{x,y}y^3f(x,y) </math>m03 = x,y∑y3f(x,y)

<math xmlns="http://www.w3.org/1998/Math/MathML"> m 21 = ∑ x , y x 2 y f ( x , y ) m_{21} = \displaystyle \sum_{x,y}x^2yf(x,y) </math>m21 = x,y∑x2yf(x,y)

<math xmlns="http://www.w3.org/1998/Math/MathML"> m 12 = ∑ x , y x y 2 f ( x , y ) m_{12} = \displaystyle \sum_{x,y}xy^2f(x,y) </math>m12 = x,y∑xy2f(x,y)

下面的代码找到图像中的有效轮廓后,通过 moments() 函数计算轮廓的空间矩。

cpp 复制代码
#include <iostream>
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"

using namespace std;
using namespace cv;

bool ascendSort(vector<Point> a,vector<Point> b)
{
    return contourArea(a) > contourArea(b);
}

int main(int argc, char **argv) {
    Mat src = imread("/Users/Tony/OpenCV_Learning/2.11/test.jpg");
    imshow("src", src);

    Mat gray,thresh;
    cvtColor(src, gray, cv::COLOR_BGR2GRAY);

    threshold(gray,thresh,0,255,THRESH_BINARY_INV | THRESH_OTSU);
    imshow("thresh", thresh);

    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    findContours(thresh, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
    sort(contours.begin(), contours.end(), ascendSort);//ascending sort

    for (size_t i = 0; i< contours.size(); i++) {
        double area = contourArea(contours[i]);

        if (area < 11000) {
            continue;
        }

        RotatedRect rrt = minAreaRect(contours[i]);

        Point2f pt[4];
        rrt.points(pt);
        line(src, pt[0], pt[1], Scalar(0, 0, 255), 8, 8);
        line(src, pt[1], pt[2], Scalar(0, 0, 255), 8, 8);
        line(src, pt[2], pt[3], Scalar(0, 0, 255), 8, 8);
        line(src, pt[3], pt[0], Scalar(0, 0, 255), 8, 8);

        Moments m = cv::moments(contours[i]);

        printf("m.m00 = %f, m.m10 = %f, m.m01 = %f,m.m20 = %f, m.m11 = %f, m.m02 = %f,m.m30 = %f, m.m21 = %f, m.m12 = %f, m.m03 = %f \n", m.m00, m.m10, m.m01, m.m20, m.m11, m.m02,m.m30,m.m21,m.m12,m.m03);

    }
    imshow("result", src);

    waitKey(0);
    return 0;
}

调用 moments() 函数会返回 Moments 对象,包含了空间矩以及中心矩和归一化中心矩。

cpp 复制代码
class CV_EXPORTS_W_MAP Moments
{
public:
    //! the default constructor
    Moments();
    //! the full constructor
    Moments(double m00, double m10, double m01, double m20, double m11,
            double m02, double m30, double m21, double m12, double m03 );
    ////! the conversion from CvMoments
    //Moments( const CvMoments& moments );
    ////! the conversion to CvMoments
    //operator CvMoments() const;

    //! @name spatial moments
    //! @{
    CV_PROP_RW double  m00, m10, m01, m20, m11, m02, m30, m21, m12, m03;
    //! @}

    //! @name central moments
    //! @{
    CV_PROP_RW double  mu20, mu11, mu02, mu30, mu21, mu12, mu03;
    //! @}

    //! @name central normalized moments
    //! @{
    CV_PROP_RW double  nu20, nu11, nu02, nu30, nu21, nu12, nu03;
    //! @}
};

空间矩的优点如下:

  • 计算简单
  • 易于实现。
  • 能够描述图像的形状、大小、位置等信息。

空间矩的缺点,也很明显:

  • 不具有尺度不变性和旋转不变性。
  • 对噪声敏感。

尺度不变性 是指图像中的物体尺寸变化不应该影响计算机视觉算法的性能。旋转不变性是指图像中的物体旋转后,计算机视觉算法仍能正确识别或检测该物体。

2. 中心矩

中心矩考虑了图像的像素值和质心位置。

<math xmlns="http://www.w3.org/1998/Math/MathML"> μ p q = ∑ x , y ( x − x ‾ ) p ( y − y ‾ ) q f ( x , y ) \mu_{pq} = \displaystyle \sum_{x,y}(x-\overline{x})^p(y-\overline{y})^qf(x,y) </math>μpq = x,y∑(x−x)p(y−y)qf(x,y)

其中,f(x,y) 表示输入的图像, <math xmlns="http://www.w3.org/1998/Math/MathML"> x ‾ \overline{x} </math>x 和 <math xmlns="http://www.w3.org/1998/Math/MathML"> y ‾ \overline{y} </math>y 是图像的质心,p、q 是正整数。

质心可以通过下面的公式进行计算: <math xmlns="http://www.w3.org/1998/Math/MathML"> x ‾ = m 10 m 00 \overline{x} = \frac{m_{10}}{m_{00}} </math>x = m00m10, <math xmlns="http://www.w3.org/1998/Math/MathML"> y ‾ = m 01 m 00 \overline{y} = \frac{m_{01}}{m_{00}} </math>y = m00m01

2.1 零阶矩

<math xmlns="http://www.w3.org/1998/Math/MathML"> μ 00 = ∑ x , y f ( x , y ) \mu_{00} = \displaystyle \sum_{x,y}f(x,y) </math>μ00 = x,y∑f(x,y)

中心矩的零阶矩与空间矩的零阶矩相同,可以用来描述图像的面积。

2.2 一阶矩

<math xmlns="http://www.w3.org/1998/Math/MathML"> μ 10 = ∑ x , y ( x − x ‾ ) f ( x , y ) \mu_{10} = \displaystyle \sum_{x,y}(x-\overline{x})f(x,y) </math>μ10 = x,y∑(x−x)f(x,y)

<math xmlns="http://www.w3.org/1998/Math/MathML"> μ 01 = ∑ x , y ( y − y ‾ ) f ( x , y ) \mu_{01} = \displaystyle \sum_{x,y}(y-\overline{y})f(x,y) </math>μ01 = x,y∑(y−y)f(x,y)

中心矩的一阶矩可以用来描述图像的质心位置的偏移。 <math xmlns="http://www.w3.org/1998/Math/MathML"> μ 10 \mu_{10} </math>μ10 表示图像质心在 x 方向的偏移量, <math xmlns="http://www.w3.org/1998/Math/MathML"> μ 01 \mu_{01} </math>μ01 表示图像质心在 y 方向的偏移量。

2.3 二阶矩

<math xmlns="http://www.w3.org/1998/Math/MathML"> μ 20 = ∑ x , y ( x − x ‾ ) 2 f ( x , y ) \mu_{20} = \displaystyle \sum_{x,y}(x-\overline{x})^2f(x,y) </math>μ20 = x,y∑(x−x)2f(x,y)

<math xmlns="http://www.w3.org/1998/Math/MathML"> μ 02 = ∑ x , y ( y − y ‾ ) 2 f ( x , y ) \mu_{02} = \displaystyle \sum_{x,y}(y-\overline{y})^2f(x,y) </math>μ02 = x,y∑(y−y)2f(x,y)

<math xmlns="http://www.w3.org/1998/Math/MathML"> μ 11 = ∑ x , y ( x − x ‾ ) ( y − y ‾ ) f ( x , y ) \mu_{11} = \displaystyle \sum_{x,y}(x -\overline{x})(y-\overline{y})f(x,y) </math>μ11 = x,y∑(x−x)(y−y)f(x,y)

中心矩的二阶矩表示图像的形状和大小。

二阶矩的物理意义如下:

<math xmlns="http://www.w3.org/1998/Math/MathML"> μ 20 \mu_{20} </math>μ20 表示图像的长轴方向的方差。

<math xmlns="http://www.w3.org/1998/Math/MathML"> μ 02 \mu_{02} </math>μ02 表示图像的短轴方向的方差。

<math xmlns="http://www.w3.org/1998/Math/MathML"> μ 11 \mu_{11} </math>μ11 表示图像的主轴方向的偏心度。

2.4 三阶矩

<math xmlns="http://www.w3.org/1998/Math/MathML"> μ 30 = ∑ x , y ( x − x ‾ ) 3 f ( x , y ) \mu_{30} = \displaystyle \sum_{x,y}(x-\overline{x})^3f(x,y) </math>μ30 = x,y∑(x−x)3f(x,y)

<math xmlns="http://www.w3.org/1998/Math/MathML"> μ 03 = ∑ x , y ( y − y ‾ ) 3 f ( x , y ) \mu_{03} = \displaystyle \sum_{x,y}(y-\overline{y})^3f(x,y) </math>μ03 = x,y∑(y−y)3f(x,y)

<math xmlns="http://www.w3.org/1998/Math/MathML"> μ 21 = ∑ x , y ( x − x ‾ ) 2 ( y − y ‾ ) f ( x , y ) \mu_{21} = \displaystyle \sum_{x,y}(x-\overline{x})^2(y-\overline{y})f(x,y) </math>μ21 = x,y∑(x−x)2(y−y)f(x,y)

<math xmlns="http://www.w3.org/1998/Math/MathML"> μ 12 = ∑ x , y ( x − x ‾ ) ( y − y ‾ ) 2 f ( x , y ) \mu_{12} = \displaystyle \sum_{x,y}(x-\overline{x})(y-\overline{y})^2f(x,y) </math>μ12 = x,y∑(x−x)(y−y)2f(x,y)

三阶矩的物理意义如下:

<math xmlns="http://www.w3.org/1998/Math/MathML"> μ 30 \mu_{30} </math>μ30 表示图像的偏度,反映了图像的对称性。

<math xmlns="http://www.w3.org/1998/Math/MathML"> μ 03 \mu_{03} </math>μ03 表示图像的峰度,反映了图像的尖锐程度。

<math xmlns="http://www.w3.org/1998/Math/MathML"> μ 21 \mu_{21} </math>μ21 表示图像的矩形程度,反映了图像的旋转不变性。

<math xmlns="http://www.w3.org/1998/Math/MathML"> μ 12 \mu_{12} </math>μ12 表示图像的椭圆程度,反映了图像的旋转不变性。

2.5 归一化中心矩

中心矩实现了平移不变性,但是仍然不具有尺度不变性和旋转不变性。

为了使目标区域不受缩放造成的尺度变化带来的影响也就是实现**尺度不变性,**使用 <math xmlns="http://www.w3.org/1998/Math/MathML"> μ 00 \mu_{00} </math>μ00对各阶中心距进行归一化处理:

<math xmlns="http://www.w3.org/1998/Math/MathML"> η p q = μ p q μ 00 p + q + 2 2 \eta_{pq} = \frac{\mu_{pq}}{\mu_{00}^{\frac{p+q+2}{2}}} </math>ηpq = μ002p+q+2μpq,其中 p+q = 2,3,4,...

可得归一化中心距

3. Hu 矩

Hu 矩是从中心矩推导出来的,图像在旋转、缩放、平移等操作后,Hu 矩仍能保持矩的不变性,实现了平移不变性、尺度不变性旋转不变性。

<math xmlns="http://www.w3.org/1998/Math/MathML"> h u [ 0 ] = η 20 + η 02 hu[0]= \eta_{20} + \eta_{02} </math>hu[0]= η20 + η02

<math xmlns="http://www.w3.org/1998/Math/MathML"> h u [ 1 ] = ( η 20 − η 02 ) 2 + 4 η 11 2 hu[1] =(\eta_{20} - \eta_{02})^2+4\eta_{11}^2 </math>hu[1]=(η20 − η02)2+4η112

<math xmlns="http://www.w3.org/1998/Math/MathML"> h u [ 2 ] = ( η 30 − 3 η 12 ) 2 + ( 3 η 21 − η 03 ) 2 hu[2] = (\eta_{30} - 3\eta_{12})^2 +( 3\eta_{21}-\eta_{03})^2 </math>hu[2]=(η30−3η12)2+(3η21−η03)2

<math xmlns="http://www.w3.org/1998/Math/MathML"> h u [ 3 ] = ( η 30 + η 12 ) 2 + ( η 21 + η 03 ) 2 hu[3] = (\eta_{30} + \eta_{12})^2 + ( \eta_{21}+\eta_{03})^2 </math>hu[3]=(η30+ η12)2+(η21+η03)2

<math xmlns="http://www.w3.org/1998/Math/MathML"> h u [ 4 ] = ( η 30 − 3 η 12 ) ( η 30 + η 12 ) [ ( η 30 + η 12 ) 2 − 3 ( η 21 + η 03 ) 2 ] + ( 3 η 21 − η 03 ) [ 3 ( η 30 + η 12 ) 2 − ( η 21 + η 03 ) 2 ] hu[4] = (\eta_{30} - 3\eta_{12}) (\eta_{30}+\eta_{12})[(\eta_{30}+\eta_{12})^2-3(\eta_{21}+\eta_{03})^2]+(3\eta_{21}-\eta_{03})[3(\eta_{30}+\eta_{12})^2-(\eta_{21}+\eta_{03})^2] </math>hu[4]=(η30− 3η12)(η30+η12)[(η30+η12)2−3(η21+η03)2]+(3η21−η03)[3(η30+η12)2−(η21+η03)2]

<math xmlns="http://www.w3.org/1998/Math/MathML"> h u [ 5 ] = ( η 20 − η 02 ) [ ( η 30 + η 12 ) 2 − ( η 21 + η 03 ) 2 + 4 η 11 ( η 30 + η 12 ) ( η 21 + η 03 ) ] hu[5] = (\eta_{20} - \eta_{02}) [(\eta_{30}+\eta_{12})^2-(\eta_{21}+\eta_{03})^2+4\eta_{11}(\eta_{30}+\eta_{12})(\eta_{21}+\eta_{03})] </math>hu[5]=(η20−η02)[(η30+η12)2−(η21+η03)2+4η11(η30+η12)(η21+η03)]

<math xmlns="http://www.w3.org/1998/Math/MathML"> h u [ 6 ] = ( 3 η 21 − η 03 ) ( η 30 + η 12 ) [ 3 ( η 30 + η 12 ) 2 − ( η 21 + η 03 ) 2 ] + ( η 30 − 3 η 12 ) ( η 21 + η 03 ) [ 3 ( η 30 + η 12 ) 2 − ( η 21 + η 03 ) 2 ] hu[6] = (3\eta_{21}-\eta_{03})(\eta_{30}+\eta_{12})[3(\eta_{30}+\eta_{12})^2-(\eta_{21}+\eta_{03})^2]+(\eta_{30} - 3\eta_{12}) (\eta_{21}+\eta_{03})[3(\eta_{30}+\eta_{12})^2-(\eta_{21}+\eta_{03})^2] </math>hu[6]=(3η21−η03)(η30+η12)[3(η30+η12)2−(η21+η03)2]+(η30− 3η12)(η21+η03)[3(η30+η12)2−(η21+η03)2]

Hu矩的特性如下:

  • 具有尺度不变性和旋转不变性。
  • 对噪声鲁棒性较好。
  • 可以描述图像的形状、大小、位置等信息。

OpenCV 提供了 HuMoments() 函数计算 Hu 矩。

下面的代码,通过 sample 图匹配原图中的物体。

cpp 复制代码
#include <iostream>
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"

using namespace std;
using namespace cv;

bool ascendSort(vector<Point> a,vector<Point> b)
{
    return contourArea(a) > contourArea(b);
}

int main(int argc, char **argv) {
    Mat src = imread("/Users/Tony/OpenCV_Learning/2.11/test.jpg");
    imshow("src", src);

    Mat gray,thresh;
    cvtColor(src, gray, cv::COLOR_BGR2GRAY);

    threshold(gray,thresh,0,255,THRESH_BINARY_INV | THRESH_OTSU);
    imshow("thresh", thresh);

    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    findContours(thresh, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
    sort(contours.begin(), contours.end(), ascendSort);//ascending sort

    Mat sample = imread("/Users/Tony/OpenCV_Learning/2.11/sample.jpg");
    imshow("sample", sample);

    Mat gray2,thresh2;
    cvtColor(sample, gray2, cv::COLOR_BGR2GRAY);
    threshold(gray2,thresh2,0,255,THRESH_BINARY_INV | THRESH_OTSU);

    vector<vector<Point>> contours2;
    vector<Vec4i> hierarchy2;
    findContours(thresh2, contours2, hierarchy2, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
    sort(contours2.begin(), contours2.end(), ascendSort);//ascending sort

    Moments sample_moments = cv::moments(contours2[0]);

    Mat sample_hu;
    HuMoments(sample_moments, sample_hu);

    for (size_t i = 0; i< contours.size(); i++) {
        double area = contourArea(contours[i]);

        if (area < 11000) {
            continue;
        }

        Moments m = cv::moments(contours[i]);

        Mat hu;
        HuMoments(m, hu);

        double dist = matchShapes(hu, sample_hu, CONTOURS_MATCH_I1, 0);
        printf("contour match distance : %.2f\n", dist);
        if (dist < 0.5) {
            RotatedRect rrt = minAreaRect(contours[i]);

            Point2f pt[4];
            rrt.points(pt);
            line(src, pt[0], pt[1], Scalar(0, 0, 255), 8, 8);
            line(src, pt[1], pt[2], Scalar(0, 0, 255), 8, 8);
            line(src, pt[2], pt[3], Scalar(0, 0, 255), 8, 8);
            line(src, pt[3], pt[0], Scalar(0, 0, 255), 8, 8);
        }
    }
    imshow("result", src);

    waitKey(0);
    return 0;
}

sample 图:

匹配到 sample 中的物体,并用红线框出:

matchShapes() 函数能够比较两个形状或两个轮廓,并返回一个显示相似性的度量。其结果越小,匹配就越好。

4. 总结

轮廓的矩特征是描述轮廓形状、大小、位置等信息的一种重要特征。轮廓的矩特征在图像处理、计算机视觉等领域有广泛的应用,矩特征可以用来进行轮廓的匹配、分类、识别等工作。

相关推荐
菜狗woc13 小时前
opencv-python的简单练习
人工智能·python·opencv
西猫雷婶15 小时前
python学opencv|读取图像(十四)BGR图像和HSV图像通道拆分
开发语言·python·opencv
云空16 小时前
《QT 5.14.1 搭建 opencv 环境全攻略》
开发语言·qt·opencv
编码小哥16 小时前
opencv中的色彩空间
opencv·计算机视觉
吃个糖糖16 小时前
34 Opencv 自定义角点检测
人工智能·opencv·计算机视觉
花花少年16 小时前
【Windows版】opencv 和opencv_contrib配置
opencv·opencv_contrib
YRr YRr16 小时前
解决Ubuntu 20.04上编译OpenCV 3.2时遇到的stdlib.h缺失错误
linux·opencv·ubuntu
葡萄爱18 小时前
OpenCV图像分割
人工智能·opencv·计算机视觉
编码小哥20 小时前
通过opencv加载、保存视频
人工智能·opencv
发呆小天才O.oᯅ20 小时前
YOLOv8目标检测——详细记录使用OpenCV的DNN模块进行推理部署C++实现
c++·图像处理·人工智能·opencv·yolo·目标检测·dnn