图像的矩 图像的轮廓面积和长度

1. 矩的概念

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

矩是概率与统计中的一个概念,是随机变量的一种数字特征。设XX为随机变量,cc为常数,kk为正整数。则量E[(xc)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[(XEX)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矩。下面主要介绍这两种矩特征的算法原理与实现。

2. Hu矩

一幅M×NM×N的数字图像f(i,j)f(i,j),其p+qp+q阶几何矩mpqmpq和中心矩μpqμpq为:

mpq=i=1Mj=1Nipjqf(i,j)mpq=∑i=1M∑j=1Nipjqf(i,j)
 
μpq=i=1Mj=1N(ii¯)p(jj¯)qf(i,j)μpq=∑i=1M∑j=1N(i−i¯)p(j−j¯)qf(i,j)

其中f(i,j)f(i,j)为图像在坐标点(i,j)(i,j)处的灰度值。i¯=m10/m00,j¯=m01/m00i¯=m10/m00,j¯=m01/m00

若将m00m00看作是图像的灰度质量,则(i¯,j¯)(i¯,j¯)为图像的质心坐标,那么中心矩μpaμpa反映的是图像灰度相对于其灰度质心的分布情况。可以用几何矩来表示中心矩,0~3阶中心矩与几何矩的关系如下:

μ00=Mi=1Nj=1(ii¯)0(jj¯)0f(i,j)=m00μ00=∑i=1M∑j=1N(i−i¯)0(j−j¯)0f(i,j)=m00

μ10=Mi=1Nj=1(ii¯)1(jj¯)0f(i,j)=0μ10=∑i=1M∑j=1N(i−i¯)1(j−j¯)0f(i,j)=0

μ01=Mi=1Nj=1(ii¯)0(jj¯)1f(i,j)=0μ01=∑i=1M∑j=1N(i−i¯)0(j−j¯)1f(i,j)=0

μ11=Mi=1Nj=1(ii¯)1(jj¯)1f(i,j)=m11y¯m10μ11=∑i=1M∑j=1N(i−i¯)1(j−j¯)1f(i,j)=m11−y¯m10

μ20=Mi=1Nj=1(ii¯)2(jj¯)0f(i,j)=m20y¯m01μ20=∑i=1M∑j=1N(i−i¯)2(j−j¯)0f(i,j)=m20−y¯m01

μ02=Mi=1Nj=1(ii¯)0(jj¯)2f(i,j)=m02y¯m01μ02=∑i=1M∑j=1N(i−i¯)0(j−j¯)2f(i,j)=m02−y¯m01

μ30=Mi=1Nj=1(ii¯)3(jj¯)0f(i,j)=m302x¯m20+2x¯2m10μ30=∑i=1M∑j=1N(i−i¯)3(j−j¯)0f(i,j)=m30−2x¯m20+2x¯2m10

μ12=Mi=1Nj=1(ii¯)1(jj¯)2f(i,j)=m122y¯m11x¯m02+2y¯2m10μ12=∑i=1M∑j=1N(i−i¯)1(j−j¯)2f(i,j)=m12−2y¯m11−x¯m02+2y¯2m10

μ21=Mi=1Nj=1(ii¯)2(jj¯)1f(i,j)=m212x¯m11y¯m20+2x¯2m01μ21=∑i=1M∑j=1N(i−i¯)2(j−j¯)1f(i,j)=m21−2x¯m11−y¯m20+2x¯2m01

μ03=Mi=1Nj=1(ii¯)0(jj¯)3f(i,j)=m032y¯m02+2y¯2m01μ03=∑i=1M∑j=1N(i−i¯)0(j−j¯)3f(i,j)=m03−2y¯m02+2y¯2m01

为了消除图像比例变化带来的影响,定义规格化中心矩如下:

 

ηpq=μpaμγ00,(γ=p+q2,p+q=2,3,)ηpq=μpaμ00γ,(γ=p+q2,p+q=2,3,…)

 

利用二阶和三阶规格中心矩可以导出下面7个不变矩组(Φ1 Φ7)(Φ1 Φ7),它们在图像平移、旋转和比例变化时保持不变。

Φ1=η20+η02Φ1=η20+η02

Φ2=(η20η02)2+4η211Φ2=(η20−η02)2+4η112

Φ3=(η203η12)2+3(η21η03)2Φ3=(η20−3η12)2+3(η21−η03)2

Φ4=(η30+η12)2+(η21+η03)2Φ4=(η30+η12)2+(η21+η03)2

Φ5=(η30+3η12)(η30+η12)[(η30+η12)23(η21+η03)2]+(3η21η03)(η21+η03)[3(η30+η12)2(η21+η03)2]Φ5=(η30+3η12)(η30+η12)[(η30+η12)2−3(η21+η03)2]+(3η21−η03)(η21+η03)[3(η30+η12)2−(η21+η03)2]

Φ6=(η20η02)[(η30+η12)2(η21+η03)2]+4η11(η30+η12)(η21+η03)Φ6=(η20−η02)[(η30+η12)2−(η21+η03)2]+4η11(η30+η12)(η21+η03)

Φ7=(3η21η03)(η30+η12)[(η30+η12)23(η21+η03)2]+]+(3η12η30)(η21+η03)[3(η30+η12)2(η21+η03)2]

3. 利用OpenCV计算Hu矩

opencv里对Hu矩的计算有直接的API,它分为了两个函数:moments()函数用于计算中心矩,HuMoments函数用于由中心矩计算Hu矩。

Moments moments(InputArray array, bool binaryImage=false )

参数说明

  • 输入参数:array是一幅单通道,8-bits的图像,或一个二维浮点数组(Point of Point2f)。binaryImage用来指示输出图像是否为一幅二值图像,如果是二值图像,则图像中所有非0像素看作为1进行计算。
  • 输出参数:moments是一个类

4.contourArea()

contour:是一个向量,二维点,可以是vector或Mat类型

oriented:有默认值false,面向区域标识符,如果为true,该函数返回一个带符号的面积,其正负取决于轮廓的方向(顺时针还是逆时针)。根据这个特性可以根据面积的符号来确定轮廓的位置。如果是默认值false,则面积以绝对值的形式返回.

该函数使用Green formula计算轮廓面积,返回面积和非零像素数量如果使用drawContours或fillPoly绘制轮廓,可能导致不同。

5. arcLength()

 用于计算封闭轮廓的周长或曲线的长度

curve:输入二维点集,可以是vector或Mat类型 
closed:曲线是否封闭的标志位,true则封闭否则不封闭

 1 #include<opencv2/imgproc/imgproc.hpp>
 2 #include<opencv2/highgui/highgui.hpp>
 3 #include<iostream>
 4 
 5 using namespace cv;
 6 using namespace std;
 7 
 8 Mat src, grayImage;
 9 int Thresh = 100;
10 int MaxThresh = 255;
11 RNG rng(12345);
12 Mat canny_output;
13 vector<vector<Point>>contours;
14 vector<Vec4i>hierarchy;
15 
16 void on_threshChange(int, void *);
17  
18 int main()
19 {
20     src = imread("D:/meinv.jpg");
21 
22     cvtColor(src, grayImage, COLOR_BGR2GRAY);
23     blur(grayImage, grayImage, Size(3, 3));
24 
25     namedWindow("原图", CV_WINDOW_AUTOSIZE);
26     imshow("原图", src);
27 
28     //创建滚动条并进行初始化
29     createTrackbar("阈值", "原图", &Thresh, MaxThresh, on_threshChange);
30     on_threshChange(0, 0);
31     waitKey(0);
32     return(0);
33 }
34 
35 void on_threshChange(int, void*)
36 {   
37     //使用Canny检测边缘
38     Canny(grayImage, canny_output, Thresh, Thresh * 2, 3);
39     //找到轮廓
40     findContours(canny_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
41     //计算矩
42     vector<Moments>mu(contours.size());
43     for (int i = 0; i < contours.size(); i++)
44     {
45         mu[i] = moments(contours[i], false);
46     }
47     //计算图像的质心
48     vector<Point2f>mc(contours.size());
49     for (int i = 0; i < contours.size(); i++)
50     {
51         mc[i] = Point2f(static_cast<float>(mu[i].m10 / mu[i].m00), static_cast<float>(mu[i].m01 / mu[i].m00));
52     }
53     //绘制轮廓
54     Mat drawing = Mat::zeros(canny_output.size(), CV_8UC3);
55     for (int i = 0; i < contours.size(); i++)
56     {
57         Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
58         drawContours(drawing, contours, i, color, 2, 8, hierarchy, 0, Point());
59         circle(drawing, mc[i], 4, color, -1, 8, 0);
60     }
61     //显示到窗口中
62     namedWindow("轮廓图", WINDOW_AUTOSIZE);
63     imshow("轮廓图", drawing);
64 
65     //用moments矩集计算轮廓面积并与opencv函数计算结果进行比较
66     printf("\t Info: Area and Contour Length \n");
67     for (int i = 0; i < contours.size(); i++)
68     {
69         printf("* Contour[%d] - Area(M_00)=%.2f-Area OpenCV:%.2f - Length:%.2f\n", i, mu[i].m00, contourArea(contours[i]), arcLength(contours[i], true));
70         Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
71         drawContours(drawing, contours, i, color, 2, 8, hierarchy, 0, Point());
72         circle(drawing, mc[i], 4, color, -1, 8, 0);
73     }
74 }

效果图:

 

本文参考自:https://blog.csdn.net/keith_bb/article/details/70197104

      http://www.cnblogs.com/ronny/p/3985810.html

posted @ 2018-09-29 19:31  RamboBai  阅读(1436)  评论(0编辑  收藏  举报