17- OpenCV:图像矩(Image Moments)和点多边形测试

目录

一、图像矩

1、矩的概念介绍

2、相关的API

3、代码演示

二、点多边形测试

1、概念介绍-点多边形测试

2、cv::pointPolygonTest

3、代码演示


一、图像矩

引言

在数字图像处理、计算机视觉与相关领域中,图像矩(Image moments)是指图像的某些特定像素灰度的加权平均值(矩),或者是图像具有类似功能或意义的属性。

图像矩通常用来描述 分割 后的图像对象。可以通过图像的矩来获得图像的部分性质,包括面积(或总体亮度),以及有关几何中心方向的信息 。

1、矩的概念介绍

图像矩是用于描述图像形状特征的一种数学工具。它们可以用于计算图像的几何特征,如质心、面积、方向等。

在图像处理中,常用的图像矩包括原始矩和中心矩。通过计算图像的原始矩和中心矩,可以得到一些常用的图像特征,如图像的面积、质心位置、方向、轮廓等。这些特征对于图像识别、形状匹配和目标跟踪等应用非常有用。

(1)原始矩:描述了图像中像素的位置和强度信息。

(2)几何矩  :

P代表像素,* 位置,算出所有的和

(3)中心距  :中心矩是以质心为中心的矩,相比原始矩,只要添加一个平移即可。中心矩是相对于图像质心的矩,可以用来描述图像的旋转和缩放特征。

周边的点到中心的距离

(4)中心归一化距

(5)图像中心Center(x0,y0)

17- OpenCV:图像矩(Image Moments)和点多边形测试_第1张图片

2、相关的API

(1)计算生成数据

17- OpenCV:图像矩(Image Moments)和点多边形测试_第2张图片

(2)cv::moments( )

cv::moments(

InputArray  array,//输入数据

bool   binaryImage=false // 是否为二值图像

)

(3)cv::contourArea()

contourArea(

InputArray  contour,//输入轮廓数据

bool   oriented// 默认false、返回绝对值

)

(4)cv::arcLength()

arcLength(

InputArray  curve,//输入曲线数据

bool   closed// 是否是封闭曲线

)

3、代码演示

主要的流程步骤:

(1)提取图像边缘

(2)发现轮廓

(3)计算每个轮廓对象的矩

(4)计算每个对象的中心、弧长、面积

#include 
#include 
#include 

using namespace std;
using namespace cv;

Mat src, gray_src;
int threshold_value = 80;
int threshold_max = 255;
const char* output_win = "image moents demo";
RNG rng(12345);
void Demo_Moments(int, void*);
int main(int argc, char** argv) {
	src = imread("D:/vcprojects/images/circle.png");
	if (!src.data) {
		printf("could not load image...\n");
		return -1;
	}
	cvtColor(src, gray_src, CV_BGR2GRAY);
	GaussianBlur(gray_src, gray_src, Size(3, 3), 0, 0);

	char input_win[] = "input image";
	namedWindow(input_win, CV_WINDOW_AUTOSIZE);
	namedWindow(output_win, CV_WINDOW_AUTOSIZE);
	imshow(input_win, src);

	createTrackbar("Threshold Value : ", output_win, &threshold_value, threshold_max, Demo_Moments);
	Demo_Moments(0, 0);

	waitKey(0);
	return 0;
}

void Demo_Moments(int, void*) {
	Mat canny_output;
	vector> contours;
	vector hierachy;

	Canny(gray_src, canny_output, threshold_value, threshold_value * 2, 3, false);
	findContours(canny_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));

	vector contours_moments(contours.size());
	vector ccs(contours.size());
	for (size_t i = 0; i < contours.size(); i++) {
		contours_moments[i] = moments(contours[i]);
		ccs[i] = Point(static_cast(contours_moments[i].m10 / contours_moments[i].m00), static_cast(contours_moments[i].m01 / contours_moments[i].m00));
	}

	Mat drawImg;// = Mat::zeros(src.size(), CV_8UC3);
	src.copyTo(drawImg);
	for (size_t i = 0; i < contours.size(); i++) {
		if (contours[i].size() < 100) {
			continue;
		}
		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\n", i, contourArea(contours[i]), arcLength(contours[i], true));
		drawContours(drawImg, contours, i, color, 2, 8, hierachy, 0, Point(0, 0));
		circle(drawImg, ccs[i], 2, color,2, 8);
	}

	imshow(output_win, drawImg);
	return;
}

效果展示:

17- OpenCV:图像矩(Image Moments)和点多边形测试_第3张图片

二、点多边形测试

1、概念介绍-点多边形测试

测试一个点是否在给定的多边形内部,边缘或者外部的一个方法。

根据左边的图进行点多边形测试之后,知道每个点在图像内部、边缘或者是在外部;

并计算出每个点到中间的距离,根据这些距离可以生出右边的图。

17- OpenCV:图像矩(Image Moments)和点多边形测试_第4张图片            17- OpenCV:图像矩(Image Moments)和点多边形测试_第5张图片

2、cv::pointPolygonTest

double cv::pointPolygonTest(

InputArray  contour,// 输入的轮廓

Point2f  pt, // 测试点

bool  measureDist // 是否返回距离值,true返回实际距离,

                                如果是false,1表示在内面,0表示在边界上,-1表示在外部

)

返回数据是double类型。

3、代码演示

演示代码主要步骤:

- 构建一张400x400大小的图片, Mat::Zero(400, 400, CV_8UC1)

- 画上一个六边形的闭合区域line

- 发现轮廓

- 对图像中所有像素点做点 多边形测试,得到距离,归一化后显示。

#include 
#include 
#include 

using namespace std;
using namespace cv;
int main(int argc, char** argv) {
	const int r = 100;
	Mat src = Mat::zeros(r * 4, r * 4, CV_8UC1);

	vector vert(6);
	vert[0] = Point(3 * r / 2, static_cast(1.34*r));   
	vert[1] = Point(1 * r, 2 * r);
	vert[2] = Point(3 * r / 2, static_cast(2.866*r));   
	vert[3] = Point(5 * r / 2, static_cast(2.866*r));
	vert[4] = Point(3 * r, 2 * r);   
	vert[5] = Point(5 * r / 2, static_cast(1.34*r));

	for (int i = 0; i < 6; i++) {
		line(src, vert[i], vert[(i + 1) % 6], Scalar(255), 3, 8, 0);
	}
	
	vector> contours;
	vector hierachy;
	Mat csrc;
	src.copyTo(csrc);
	findContours(csrc, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
	Mat raw_dist = Mat::zeros(csrc.size(), CV_32FC1);
	for (int row = 0; row < raw_dist.rows; row++) {
		for (int col = 0; col < raw_dist.cols; col++) {
			double dist = pointPolygonTest(contours[0], Point2f(static_cast(col), static_cast(row)), true);
			raw_dist.at(row, col) = static_cast(dist);
		}
	}

	double minValue, maxValue;
	minMaxLoc(raw_dist, &minValue, &maxValue, 0, 0, Mat());
	Mat drawImg = Mat::zeros(src.size(), CV_8UC3);
	for (int row = 0; row < drawImg.rows; row++) {
		for (int col = 0; col < drawImg.cols; col++) {
			float dist = raw_dist.at(row, col);
			if (dist > 0) {
				drawImg.at(row, col)[0] = (uchar)(abs(1.0 - (dist / maxValue)) * 255);
			}
			else if (dist < 0) {
				drawImg.at(row, col)[2] = (uchar)(abs(1.0 - (dist / minValue)) * 255);
			} else {
				drawImg.at(row, col)[0] = (uchar)(abs(255 - dist));
				drawImg.at(row, col)[1] = (uchar)(abs(255 - dist));
				drawImg.at(row, col)[2] = (uchar)(abs(255 - dist));
			}
		}
	}

	const char* output_win = "point polygon test demo";
	char input_win[] = "input image";
	namedWindow(input_win, CV_WINDOW_AUTOSIZE);
	namedWindow(output_win, CV_WINDOW_AUTOSIZE);

	imshow(input_win, src);
	imshow(output_win, drawImg);

	waitKey(0);
	return 0;
}

效果展示:

17- OpenCV:图像矩(Image Moments)和点多边形测试_第6张图片

可以了解一下不同位置的点:

(1)内部

drawImg.at(row, col)[0] = (uchar)((abs(dist / maxValue) * 255);

(2)外部

drawImg.at(row, col)[1] = (uchar)((abs(dist / minValue) * 255);

(3)边缘线

drawImg.at(row, col)[0] =255;
drawImg.at(row, col)[1] = saturate_cast(minValue);
drawImg.at(row, col)[2] = saturate_cast(minValue);

你可能感兴趣的:(OpenCV,opencv,人工智能,计算机视觉,图像矩)