opencv笔记三十二(图像矩moments,轮廓面积contourArea,轮廓周长arcLength)

 

理论来自:

https://blog.csdn.net/keith_bb/article/details/70197104

1.概述

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

从图像中计算出来的矩通常描述了图像不同种类的几何特征如:大小、灰度、方向、形状等,图像矩广泛应用于模式识别、目标分类、目标识别与防伪估计、图像编码与重构等领域。

严格来讲矩是概率与统计中的一个概念,是随机变量的一种数字特征。设 xx 为随机变量,C为常数,则量E[(x−c)^k]称为X关于C点的k阶矩。比较重要的两种情况如下:

1.c=0,这时a_k=E(X^k)称为X的k阶原点矩;

2.c=E(X),这时μ_k=E[(X−EX)^k]称为X的k阶中心矩

一阶原点矩就是期望,一阶中心矩μ_1=0,二阶中心矩μ_2就是X的方差Var(X)。在统计学上,高于4阶的矩极少使用,μ_3可以去衡量分布是否有偏,μ_4可以衡量分布(密度)在均值拘谨的陡峭程度。

针对一幅图像,我们把像素的坐标看成是一个二维随机变量(X, Y),那么一副灰度图可以用二维灰度图密度函数来表示,因此可以用矩来描述灰度图像的特征。 
不变矩(Invariant Moments)是一种高度浓缩的图像特征,具有平移、灰度、尺度、旋转不变性,由M.K.Hu在1961年首先提出,1979年M.R.Teague根据正交多项式理论提出了Zernike矩

opencv中提供的API用来计算中心矩和Hu矩,下面主要介绍Hu的原理。

2.原理

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

其中f(i,j)为图像在坐标点(i,j)处的灰度值。

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

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

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

3.opencv API

opencv中提供了moments()来计算图像中的中心矩(最高到三阶),HuMoments()用于由中心矩计算Hu矩.同时配合函数contourArea函数计算轮廓面积和arcLength来计算轮廓或曲线长度

moments()

cv::moments (   InputArray  array,
                bool    binaryImage = false 
            )   

array:输入数组,可以是光栅图像(单通道,8-bit或浮点型二维数组),或者是一个二维数组(1 X N或N X 1),二维数组类型为Point或Point2f

binaryImage:默认值是false,如果为true,则所有非零的像素都会按值1对待,也就是说相当于对图像进行了二值化处理,阈值为1,此参数仅对图像有效。

contourArea()

double cv::contourArea  (   InputArray  contour,
                            bool    oriented = false 
                        )       

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

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

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

double cv::arcLength    (   InputArray  curve,
                            bool    closed 
                            )

代码如下:

#include<opencv2\opencv.hpp>
#include<math.h>
#include<iostream>
using namespace cv;
using namespace std;
Mat t1, t2, t3, t4;
char *c1 = "OLD", *c2 = "MID", *c3 = "NEW", *c4 = "END";
RNG rng(123456);

int main(int agrc, char** agrv) {
	t1=imread("test1.jpg");
	if (!t1.data) {
		cout << "WRONG";
		return -1;
	}	

	GaussianBlur(t1, t2, Size(3, 3), 0, 0, BORDER_CONSTANT);
	cvtColor(t2, t2, CV_BGR2GRAY);
	threshold(t2, t3, 0, 255, THRESH_OTSU);
	
	vector<vector<Point>> contours;
	vector<Vec4i> hierarchy;
	findContours(t3, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
	vector<Moments> mom(contours.size());
	vector<Point2f> m(contours.size());

	for (size_t i = 0; i < contours.size(); i++) {
		mom[i] = moments(contours[i], false);
		m[i] = Point(static_cast<float>(mom[i].m10 / mom[i].m00), static_cast<float>(mom[i].m01 / mom[i].m00));
		//static_cast< type-id >( expression )	该运算符把expression转换为type - id类型
	}
	
	for (size_t i = 0; i < contours.size(); i++) {
		Scalar color = Scalar(rng.uniform(0, 180), rng.uniform(0, 180), rng.uniform(0, 180));
		drawContours(t1, contours, i, color, 1, 8, hierarchy);
		circle(t1, m[i], 5, color, 2, 8);
		cout << "i=" << i << endl;
		cout << "x=" << m[i].x << "  y=" << m[i].y << "  area=" << contourArea(contours[i], false) << "  arcLength" << arcLength(contours[i], true)<<endl;
	}


	imshow(c1, t1);
	imshow(c2, t3);
	waitKey(0);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_31647835/article/details/81087467