第32课 图像矩(Image Moments)

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矩。

1.1 图像矩相关公式

  • 几何矩
    在这里插入图片描述
  • 中心矩
    在这里插入图片描述
  • 中心归一化矩
    在这里插入图片描述
  • 图像中心Center(x0, y0)
    在这里插入图片描述

2. 步骤

  1. 提取图像边缘
  2. 发现轮廓
  3. 计算每个轮廓对象的矩
  4. 计算每个对象的中心、弧长、面积

3. 相关API

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

3.1 计算中心矩cv::moments()

  • 计算图像中的中心矩(最高到三阶)
moments(
InputArray  array,//输入数据,可以是光栅图像(单通道,8-bit或浮点型二维数组),或者是一个二维数组(1 X N或N X 1),二维数组类型为Point或Point2f。
bool   binaryImage=false // 是否为二值图像,默认值是false,如果为true,则所有非零的像素都会按值1对待,也就是说相当于对图像进行了二值化处理,阈值为1,此参数仅对图像有效。
)

3.2 contourArea()

contourArea(
InputArray  contour,//输入轮廓数据,是一个向量,二维点,可以是vector或Mat类型
bool   oriented// 默认false, 如果为true,该函数返回一个带符号的面积,其正负取决于轮廓的方向(顺时针还是逆时针)。根据这个特性可以根据面积的符号来确定轮廓的位置。如果是默认值false,则面积以绝对值的形式返回.
  • 该函数使用Green formula计算轮廓面积,返回面积和非零像素数量如果使用drawContours或fillPoly绘制轮廓,可能导致不同。

3.3 arcLength()

  • 计算轮廓或曲线长度。
arcLength(
InputArray  curve,//输入曲线数据,输入二维点集,可以是vector或Mat类型
bool   closed// 是否是封闭曲线

4. 例程

#include<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>

using namespace cv;
using namespace std;
Mat blured;
Mat src, dst;
RNG rng(12345);
int Threshold=81;
void CallBack(int, void*);

int main() {
	
	src = imread("D:/resource/images/硬币.jpg");
	if (src.empty()) {
		printf("the image couldn't be loaded...");
		return -1;
	}
	imshow("input", src);
	GaussianBlur(src, blured, Size(21, 21), 0);
	namedWindow("output");
	createTrackbar("Threshold:", "output", &Threshold, 255, CallBack);
	CallBack(0, 0);

	waitKey(0);
	return -1;

}
void CallBack(int, void*) {
	//提取边缘
	Mat canny_out;
	Canny(blured, canny_out, Threshold, Threshold * 2);
	imshow("canny_out", canny_out);
	vector<vector<Point>> contours;
	findContours(canny_out, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE,Point(0,0));

	vector<Moments> contours_moments(contours.size());//图像的中心矩
	vector<Point2f> ccs(contours.size());//图像中心坐标
	for (size_t i = 0; i < contours.size(); i++) {
		//提取各图像的中心矩和中心坐标
		contours_moments[i] = moments(contours[i]);
		ccs[i] = Point(static_cast<float>(contours_moments[i].m10 / contours_moments[i].m00), static_cast<float>(contours_moments[i].m01 / contours_moments[i].m00));
		
		//绘制边缘和各图像中心
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		drawContours(src, contours, i, color, 2, 8);
		circle(src, ccs[i], 2, color, 2, 8);

		//打印各图像中心坐标,面积和边缘长度
		printf("center point x : %.2f y : %.2f\n", ccs[i].x, ccs[i].y);
		printf("contours %d area : %.2f   arc length : %.2f\n", i, contourArea(contours[i]), arcLength(contours[i], true));
	}
	imshow("output", src);
	return;
	
}

在这里插入图片描述
在这里插入图片描述

发布了31 篇原创文章 · 获赞 12 · 访问量 2750

猜你喜欢

转载自blog.csdn.net/weixin_42877426/article/details/104405381