Opencv2.4学习::轮廓矩

轮廓矩


原理部分:

一、概率论上的定义

 看到矩这个字,很容易联想到概率论,在概率论中,定义如下:

Opencv2.4学习::轮廓矩

或者说:

设 X 和 Y 是随机变量,c 为常数,k 为正整数, 
如果E(|X−c|^k)E(|X−c|^k)存在,则称E(|X−c|^k)E(|X−c|^k)为 X 关于点 c 的 k 阶矩。

  • c = 0 时, 称为 k 阶原点矩;
  • c = E(x) 时,称为 k 阶中心矩。

如果E(|X−c1|^p⋅|Y−c2|^q)存在,则称其为 X,Y 关于 c 点 p+q 阶矩。

其余基本概率论知识可参考:https://www.cnblogs.com/wyuzl/p/7845948.html 

 

 二、在图像学上的定义

一幅M×N的数字图像f(i,j),其p+q阶几何矩Opencv2.4学习::轮廓矩和中心矩Opencv2.4学习::轮廓矩为:

                                                             Opencv2.4学习::轮廓矩

                                                            Opencv2.4学习::轮廓矩

其中:

  • f(i,j)为图像在坐标点(i,j)处的灰度值。
  • 重心:Opencv2.4学习::轮廓矩,也是图像的一阶矩

 

三、几何矩Opencv2.4学习::轮廓矩的基本意义

(1)零阶矩

                                                            Opencv2.4学习::轮廓矩

可以发现,当图像为二值图时,Opencv2.4学习::轮廓矩就是这个图像上白色区域的总和,因此,Opencv2.4学习::轮廓矩可以用来求二值图像(轮廓,连通域)的面积。

(2)一阶矩

                                                           Opencv2.4学习::轮廓矩

                                                           Opencv2.4学习::轮廓矩

当图像为二值图时,Opencv2.4学习::轮廓矩就是白色像素关于x坐标的累加和,而Opencv2.4学习::轮廓矩则是y坐标的累加和

由此,可获得图像的重心:Opencv2.4学习::轮廓矩,也就是前文提到的。

(3)二阶矩

                                                           Opencv2.4学习::轮廓矩

                                                           Opencv2.4学习::轮廓矩

                                                           Opencv2.4学习::轮廓矩

二阶矩可以用来求物体形状的方向。 

后续会有介绍,具体可参考:https://blog.****.net/qq826309057/article/details/70039397

 

四、由几何矩可表示出中心距如下:

摘自:https://blog.****.net/keith_bb/article/details/70197104

Opencv2.4学习::轮廓矩

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

Opencv2.4学习::轮廓矩

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

Opencv2.4学习::轮廓矩


Opencv应用部分

核心函数:

(1)求矩

Moments moments(inputArray array, bool binaryImage=false) 
  • 输入参数,可以是光栅图像(单通道,8位或浮点的二维数组)或二维数组(1N或N1)
  • 默认值false,若此参数取true,则所有非零像素为1.此参数仅对图像使用

(2)计算轮廓面积

double contourArea(inputArray contour, bool oriented=false) 
  • 输入的向量,二维点(轮廓顶点)
  • 面向区域标识符,若为true,该函数返回一个带符号的面积值,其正负取决于轮廓的方向(顺时针还是逆时针)。根据这个特性我们可以根据面积的符号来确定轮廓的位置。需要注意的是,这个参数有默认值false,表示以绝对值返回,不带符号。

(3) 计算轮廓长度

double arcLength(inputArray curve,bool closed) 
  •  输入的二维点集
  • 一个用于指示曲线是否封闭的标识符,默认值closed,表示曲线封闭

 

一、求图像的重心和方向

前面提到二阶矩可以用来求物体形状的方向。 
Opencv2.4学习::轮廓矩

其中:

Opencv2.4学习::轮廓矩,

Opencv2.4学习::轮廓矩

Opencv2.4学习::轮廓矩
fastAtan2()为opencv的函数,输入向量,返回一个0-360的角度。 

个人认为:关于fastAtan2()的推算如下:

 Opencv2.4学习::轮廓矩

当然这只是个人推导,有兴趣的同学可以验证一下。 

另外,fastAtan2()返回的角度指自然坐标系下x轴正半轴按顺时针到图像轴的角,如下图的α角:

【注意:实际处理时,需把目标部分变成白色,背景为黑色。这里只是为了方便看才把目标变成黑色而已】

Opencv2.4学习::轮廓矩

测试代码:

#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/features2d/features2d.hpp>
#include<stdlib.h>
#include<stdio.h>
#include<iostream>
using namespace std;
using namespace cv;

void main()
{
	Mat srcImg;
	srcImg = imread("F:\\opencv_re_learn\\flash.jpg");
	if (!srcImg.data){
		cout<< "failed to read" << endl;
		system("pause");
		return;
	}
	Mat srcGray;
	cvtColor(srcImg, srcGray, CV_BGR2GRAY);
	Mat thresh;
	threshold(srcGray, thresh, 100, 255, CV_THRESH_BINARY_INV |
		CV_THRESH_OTSU);//二值化时主要要让目标部分是白色像素
	Moments m = moments(thresh, true);//moments()函数计算出三阶及一下的矩
	Point2d center(m.m10 / m.m00, m.m01 / m.m00);//此为重心
	//计算方向
	double a = m.m20 / m.m00 - center.x*center.x;
	double b = m.m11 / m.m00 - center.x*center.y;
	double c = m.m02 / m.m00 - center.y*center.y;
	double theta = fastAtan2(2 * b, (a - c)) / 2;//此为形状的方向
	cout << 2 * b << endl;
	cout << a - c << endl;
	cout <<"角度是:"<< theta << endl;
	//绘制重心
	circle(srcImg, center, 2, Scalar(0, 0, 255),2);
	imshow("src", srcImg);
	imshow("Gray", srcGray);
	imshow("Thresh", thresh);
	waitKey(0);
}

Opencv2.4学习::轮廓矩

未完待续



 参考文章:

https://blog.****.net/qq_31531635/article/details/73692611

https://blog.****.net/qq826309057/article/details/70039397

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

https://blog.****.net/mingzhentanwo/article/details/45155307