在力学中,矩是表示距离和物理量乘积的物理量,表征物体的空间分布。原则上任何物理量和距离相乘都会产生力矩,质量,电荷分布等。单个点的力矩:,多个点则是积分的空间密度:,如果点表示质量,则第零矩是总质量,一阶矩是重心,二阶矩是转动惯量。
在统计学中,矩表征随机量的分布。如一个“二阶矩”在一维上可测量其“宽度”,,在更高阶的维度上由于其使用于橢球的空间分布。其他矩用来描述诸如与均值的偏差分布情况(偏态),或峰值的分布情况(峰态)。实数域的实函数相对于值c的n阶矩为:,如果点表示概率密度,则第零阶矩表示总概率(即1),1,2,3阶矩依次为以下三项。数学中的概念与物理学中矩的概念密切相关。
归一化n阶中心矩或者说标准矩,是n阶中心矩除以标准差,归一化n阶中心矩。
矩函数在图像分析中有着广泛的应用,如模式识别、目标分类、目标识别与方位估计、图像编码与重构等。一个从一幅数字图形中计算出来的矩集,通常描述了该图像形状的全局特征,并提供了大量的关于该图像不同类型的几何特性信息,比如大小、位置、方向及形状等。图像矩的这种特性描述能力被广泛的应用在各种图像处理、计算机视觉和机器人技术领域的目标识别与方位估计中。
一阶矩与形状有关,
二阶矩显示曲线围绕直线平均值的扩展程度,三阶矩则是关于平均值的对称性的测量。
由二阶矩和三阶矩可以导出一组共七个不变矩。
不变矩是图像的统计特性,满足平移、伸缩、旋转均不变的不变性,在图像识别领域得到了广泛的应用。
不变矩的物理含义:
如果把图像看成是一块质量密度不均匀的薄板,其图像的灰度分布函数f(x,y)就是薄板的密度分布函数,则其各阶矩有着不同的含义,如零阶矩表示它的总质量;一阶矩表示它的质心;二阶矩又叫惯性矩,表示图像的大小和方向。事实上,如果仅考虑阶次为2的矩集,则原始图像等同于一个具有确定的大小、方向和离心率,以图像质心为中心且具有恒定辐射率的椭圆。由三阶矩以下矩构成的七个矩不变量具有平移、旋转和尺度不变性等等。当密度分布函数发生改变时,图像的实质没有改变,仍然可以看做一个薄板,只是密度分布有所改变。虽然此时各阶矩的值可能发生变化,但由各阶矩计算出的不变矩仍具有平移、旋转和尺度不变性。这样 ,可对图像进行简化处理,保留最能反映目标特性的信息,再用简化后的图像计算不变矩特征,可减少计算量。
只有基于二阶矩的不变矩对二维物体的描述才是真正的与旋转、平移和尺度无关的。较高阶的矩对于成像过程中的误差,微小的变形等因素非常敏感,所以相应的不变矩基本上不能用于有效的物体识别。即使是基于二阶矩的不变矩也只能用来识别外形相差特别大的物理,否则他们的不变矩会因为很相似而不能识别。
Moments moments
( InputArray array,
bool binaryImage = false
);
double contourArea(
InputArray contour, // 轮廓数据
bool oriented = false
);
double arcLength(
InputArray curve, // 输入曲线数据
bool closed // 是否同封闭的
)
(1)转化为灰度图
(2)图像平滑处理(模糊)
(3)边缘和轮廓提取
(4)计算轮廓的矩
(5)计算每中轮廓的中心、边长、面积。
// 第1步,灰度图
cvtColor(srcImg1, grayImg, CV_BGR2GRAY);
// 第2步, 高斯模糊
GaussianBlur(grayImg, gausImg, Size(3, 3), 0);
// 第3步, 边缘提取
Canny(gausImg, cannyImg, 150, 200);
// 第4步, 轮廓提取
vector<vector<Point>> ptContours;
vector<Vec4i> hierarchy;
findContours(cannyImg, ptContours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE, Point(0, 0));
// 第5步, 计算矩
vector<Moments> contour_moment(ptContours.size());
vector<Point2f> centerpos(ptContours.size());
char text[1024];
for (int i = 0; i < ptContours.size(); i++)
{
contour_moment[i] = moments(ptContours[i]);
// 太小的区域不画出,太多的输出画面太乱。
if (ptContours[i].size() < 500)
{
continue;
}
// 第6步, 计算中心点
centerpos[i].x = contour_moment[i].m01 / contour_moment[i].m00;
centerpos[i].y = contour_moment[i].m10 / contour_moment[i].m00;
// 画轮廓线
drawContours(srcImg1,
ptContours,
i,
Scalar(0, 255, 0),
1
);
// 画出中心的位置
circle(srcImg1, centerpos[i],3,Scalar(0,0,255));
// 第7步, 计算面积和弧度长
double area = contourArea(ptContours[i]);
double len = arcLength(ptContours[i], true);
// 在图上显示面积和弧度长信息
sprintf(text, "area=%.2f arclen=%.2f", area, len);
putText(srcImg1, text, centerpos[i], 1, 1.0, Scalar(0,255,0));
}
imshow(src_file_name1, srcImg1);
本文源码在Debug–x64下编译运行。
ZIP包中包含开发环境,下载解压后可直接编译运行。
下载源码。