图像的矩 图像的轮廓面积和长度
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矩。下面主要介绍这两种矩特征的算法原理与实现。
2. Hu矩
一幅M×NM×N的数字图像f(i,j)f(i,j),其p+qp+q阶几何矩mpqmpq和中心矩μpqμpq为:
其中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=1∑Nj=1(i−i¯)0(j−j¯)0f(i,j)=m00μ00=∑i=1M∑j=1N(i−i¯)0(j−j¯)0f(i,j)=m00
μ10=∑Mi=1∑Nj=1(i−i¯)1(j−j¯)0f(i,j)=0μ10=∑i=1M∑j=1N(i−i¯)1(j−j¯)0f(i,j)=0
μ01=∑Mi=1∑Nj=1(i−i¯)0(j−j¯)1f(i,j)=0μ01=∑i=1M∑j=1N(i−i¯)0(j−j¯)1f(i,j)=0
μ11=∑Mi=1∑Nj=1(i−i¯)1(j−j¯)1f(i,j)=m11−y¯m10μ11=∑i=1M∑j=1N(i−i¯)1(j−j¯)1f(i,j)=m11−y¯m10
μ20=∑Mi=1∑Nj=1(i−i¯)2(j−j¯)0f(i,j)=m20−y¯m01μ20=∑i=1M∑j=1N(i−i¯)2(j−j¯)0f(i,j)=m20−y¯m01
μ02=∑Mi=1∑Nj=1(i−i¯)0(j−j¯)2f(i,j)=m02−y¯m01μ02=∑i=1M∑j=1N(i−i¯)0(j−j¯)2f(i,j)=m02−y¯m01
μ30=∑Mi=1∑Nj=1(i−i¯)3(j−j¯)0f(i,j)=m30−2x¯m20+2x¯2m10μ30=∑i=1M∑j=1N(i−i¯)3(j−j¯)0f(i,j)=m30−2x¯m20+2x¯2m10
μ12=∑Mi=1∑Nj=1(i−i¯)1(j−j¯)2f(i,j)=m12−2y¯m11−x¯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=1∑Nj=1(i−i¯)2(j−j¯)1f(i,j)=m21−2x¯m11−y¯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=1∑Nj=1(i−i¯)0(j−j¯)3f(i,j)=m03−2y¯m02+2y¯2m01μ03=∑i=1M∑j=1N(i−i¯)0(j−j¯)3f(i,j)=m03−2y¯m02+2y¯2m01
为了消除图像比例变化带来的影响,定义规格化中心矩如下:
利用二阶和三阶规格中心矩可以导出下面7个不变矩组(Φ1 Φ7)(Φ1 Φ7),它们在图像平移、旋转和比例变化时保持不变。
Φ1=η20+η02Φ1=η20+η02
Φ2=(η20−η02)2+4η211Φ2=(η20−η02)2+4η112
Φ3=(η20−3η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)2−3(η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)2−3(η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