opencv之图像矩 image moments

矩的概念介绍

  • 几何矩
    • 几何矩
    • 中心矩
    • 中心归一化矩
  • 图像中心
    x 0 = m 10 ÷ m 00 x_0=m10\div m00 x0=m10÷m00
    y 0 = m 01 ÷ m 00 y_0=m01\div m00 y0=m01÷m00
    在这里插入图片描述

相关API介绍

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

moments函数API

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

参数介绍

  • array:输入数组,可以是光栅图像(单通道,8-bit或浮点型二维数组),或者是一个二维数组(1 X N或N X 1),二维数组类型为PointPoint2f
  • binaryImage:默认值是false,如果为true,则所有非零的像素都会按值1对待,也就是说相当于对图像进行了二值化处理,阈值为1,此参数仅对图像有效。
  • 返回值为Moments类型集合

contourArea函数API

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

参数介绍

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

该函数使用Green formula计算轮廓面积,返回面积和非零像素数量如果使用drawContoursfillPoly绘制轮廓,可能导致不同。
官方文档中给出调用**contourArea()**函数示例如下:

vector<Point> contour;
contour.push_back(Point2f(0, 0));
contour.push_back(Point2f(10, 0));
contour.push_back(Point2f(10, 10));
contour.push_back(Point2f(5, 4));
double area0 = contourArea(contour);
vector<Point> approx;
approxPolyDP(contour, approx, 5, true);
double area1 = contourArea(approx);
cout << "area0 =" << area0 << endl <<
        "area1 =" << area1 << endl <<
        "approx poly vertices" << approx.size() << endl;


arcLength函数API

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

参数介绍

  • curve:输入二维点集,可以是vectorMat类型
  • closed:曲线是否封闭的标志位,true则封闭否则不封闭
    用于计算封闭轮廓的周长或曲线的长度

编码步骤

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

代码演示

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

#define PIC_PATH "C:\\pic\\"
#define PIC_NAME "3.jpg"

using namespace cv;
using namespace std;
Mat src, gray_src;
int threshold_value = 25;
int threshold_max = 255;
void Moment_Demo(int, void*);

int main(void)
{
	string pic = string(PIC_PATH) + string(PIC_NAME);
	cout << "原始图片为:" << pic << endl;

	src = imread(pic);
	if (src.empty()) {
		cout << "图片不存在" << endl;
		return -1;
	}
	namedWindow("原始图片", WINDOW_AUTOSIZE);
	imshow("原始图片", src);


	cvtColor(src, gray_src, CV_BGR2GRAY);   //图片转化为灰度图
	namedWindow("边缘图片", WINDOW_AUTOSIZE);
	namedWindow("moment", WINDOW_AUTOSIZE);

	//高斯模糊去除噪点干扰
	GaussianBlur(gray_src, gray_src, Size(3, 3), 0, 0);

	//创建滑动条
	createTrackbar("阈值调整", "原始图片",& threshold_value, threshold_max, Moment_Demo);
	Moment_Demo(0, 0);
	
	waitKey(0);
	destroyAllWindows();
}

void Moment_Demo(int, void*)
{
	Mat canny_output;
	//边缘计算
	Canny(gray_src, canny_output, threshold_value, threshold_value * 2, 3, false);
	imshow("边缘图片", canny_output);

	vector<vector<Point>> contours;   //轮廓结合
	vector<Vec4i> hierarchy;          //轮廓拓扑结构

	//轮廓查找
	findContours(canny_output, contours, hierarchy, CV_RETR_TREE, 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));
	}
	RNG rng(123456);  //定义随机值
	Mat drawimg;
	src.copyTo(drawimg);    //创建目标图像
	
	for (size_t i = 0; i < contours.size(); i++)
	{
		//打印轮廓矩的编号 面积 周长
		printf("contour:%d\narea is %.2f\nlength is %.2f\n\n\n", static_cast<int>(i), contourArea(contours[i]), arcLength(contours[i],true));
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		drawContours(drawimg, contours, i, color, 2, 8, hierarchy);   //绘制轮廓
		circle(drawimg, ccs[i], 2, color, 2, 8);       //绘制中心
	}
	imshow("moment", drawimg);
}


程序运行结果

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

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值