图形矩(Image Moments)- 求取图像质心,面积,长度

1、矩的概念;
2、API;
3、Code;

图形矩

1、几何矩: P(x,y) —像素值, x , y x,y x,y表示像素点的位置,有各阶矩;
2、中心距: m u ( j i ) mu_(ji) mu(ji);
3、中心归一化距: n u ( j i ) nu_(ji) nu(ji)

4、中心距与中心归一化距是几何矩的变种,矩用来对二值图像的轮廓进行计算从而得到图像的轮廓特征; 弧矩(用来进行模式识别)…还有很多其他的矩;

5、图像中心Center: 与对象的位置有关系,是对象的质心位置;


注: 这些值存储在Moment数据结构中

API

计算长度,面积,质心(实现图像的对象测量)
1、图像矩计算API : cv::moments()求出图像从1阶到3阶的所有图像矩;
array : 输入数据为findContours()计算出来的数据
2、面积计算API : contourArea() : 计算对象的面积;
3、弧长计算API : arcLength() : 计算对象轮廓的弧长(长度);

使用步骤

1、提取图像边缘(Canny算法);
2、发现轮廓;
3、计算每个轮廓图像的矩;
4、计算每个图像的中心,弧长,面积;

Code

注意: findContours找到的图像轮廓有很多,应使用for循环将轮廓数据进行全部处理

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

using namespace std;
using namespace cv;

Mat src, gray_src;
int threshold_value = 50;
int threshold_max = 255;

const char *OUTPUT_WIN = "image moment demo";
const char *INPUT_WIN = "input image";

RNG rng(12345);

void Moments_Demo(int, void*);

int main(int argc, char** argv)
{
   
	src = imread("C:\\Users\\hello\\Desktop\\24.jpg");
	if (src.empty())
	{
   
		cout << "could not load the image..." << endl;
		return -1;
	}
	cvtColor(src, gray_src, CV_BGR2GRAY);
	GaussianBlur(gray_src, gray_src, Size(3, 3), 0, 0);  //降低图像的噪声,Canny算法对噪声比较敏感

	namedWindow(INPUT_WIN, WINDOW_AUTOSIZE);
	namedWindow(OUTPUT_WIN, WINDOW_AUTOSIZE);
	imshow(INPUT_WIN, gray_src);

	createTrackbar("Threshold value: ", INPUT_WIN, &threshold_value, threshold_max, Moments_Demo);
	Moments_Demo(threshold_value, 0);

	waitKey(0);
	return 0;
}

void Moments_Demo(int, void*)
{
   
	Mat canny_output;
	vector<vector<Point>> contours;
	vector<Vec4i> hierarchy;
	//边缘检测
	Canny(gray_src, canny_output, threshold_value, threshold_value * 2, 3, false);  //Sobel算子的大小3
	//发现轮廓
	findContours(canny_output, contours, RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(-1, -1));
	//对每个轮廓计算矩 初始化一下大小
	vector<Moments> contours_moments(contours.size());
	vector<Point2f> ccs(contours.size());  //中心位置

	for (size_t i = 0; i < contours.size(); i++)
	{
   
		if (contours[i].size() < 30)  //轮廓像素点少的不打印
		{
   
			continue;
		}
		contours_moments[i] = moments(contours[i], true);  //以函数返回值形式返回图形矩
		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));   //质心位置
	}
	//绘制中心位置

	//Mat drawImage = Mat::zeros(src.size(), CV_8UC3);
	Mat drawImage;
	src.copyTo(drawImage);
	for (size_t i = 0; i < contours.size(); i++)
	{
   
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		printf("center point x : %.2f , y : %.2f\n", ccs[i].x, ccs[i].y);

		printf("contours %d area : %.2f ; arc length : %.2f\r\n",
				i, contourArea(contours[i], false), arcLength(contours[i], true));
		circle(drawImage, ccs[i],2, color, 2, LINE_8);  //圈出质心
		drawContours(drawImage, contours, i, color,2, LINE_8, hierarchy, 0, Point(0, 0)); //层次结构给hierarchy
	}
	imshow(OUTPUT_WIN, drawImage);   //显示图像

}

效果

图形矩可以有效的计算出图片中对象的面积,质心,长度数据: