矩的概念介绍
- 几何矩
- 几何矩
- 中心矩
- 中心归一化矩
- 图像中心
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),二维数组类型为
Point
或Point2f
- binaryImage:默认值是
false
,如果为true
,则所有非零的像素都会按值1
对待,也就是说相当于对图像进行了二值化处理,阈值为1
,此参数仅对图像有效。 - 返回值为Moments类型集合
contourArea函数API
double cv::contourArea ( InputArray contour,
bool oriented = false
)
参数介绍
- contour:是一个向量,二维点,可以是
vector
或Mat
类型 - oriented:有默认值
false
,面向区域标识符,如果为true
,该函数返回一个带符号的面积,其正负取决于轮廓的方向(顺时针还是逆时针)。根据这个特性可以根据面积的符号来确定轮廓的位置。如果是默认值false
,则面积以绝对值的形式返回.
该函数使用Green formula计算轮廓面积,返回面积和非零像素数量如果使用drawContours或fillPoly绘制轮廓,可能导致不同。
官方文档中给出调用**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:输入二维点集,可以是
vector
或Mat
类型 - 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);
}
程序运行结果