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

OpenCV提供的API

  • 说明
    函数确定是否给定的点在轮廓的外部或者内部或者在边缘线上。函数返回正数(点在轮廓内部)、负数(点在轮廓外部)、零(点在边缘上)。当measureDist参数设定为false,返回值为+1、-1、0。否则,返回值为点与最邻近轮廓点的距离。
  • 声明
double pointPolygonTest( 
    InputArray contour, 
    Point2f pt, 
    bool measureDist 
);
  • 参数

contour

输入的轮廓

pt

待测试的点。

measureDist

设置为true时,返回实际距离值。若返回值为,表示点在多边形内部,返回值为,表示在多边形外部,返回值为0,表示在多边形上

应用

步骤:

  1. 构建一张400x400大小的图片, Mat::Zero(400, 400, CV_8UC1)
  2. 画上一个六边形的闭合区域line
  3. 发现轮廓
  4. 对图像中所有像素点做点 多边形测试,得到距离,归一化后显示。
void pointPolyTest1() {

	//1 绘制待处理的图像
	const int r = 100;
	Mat src = Mat::zeros(Size(400, 400), CV_8U);

	//1.1 绘制一系列的点
	vector<Point2f> points(6);
	points[0] = Point(r * 3 / 2, static_cast<int>(1.34 * r));
	points[1] = Point(r * 1, 2 * r);
	points[2] = Point(r * 3 / 2, static_cast<int>(2.866 * r));
	points[3] = Point(r * 5 / 2, static_cast<int>(2.866 * r));
	points[4] = Point(r * 3, 2 * r);
	points[5] = Point(r * 5 / 2, static_cast<int>(1.34 * r));
	//1.2  绘制出由点连接而成的直线
	for (int i = 0; i < 6; i++)
	{
		line(src, points[i], points[(i + 1) % 6], Scalar(255), 2);
	}


	//2 查找轮廓
	vector<vector<Point>> contours;
	Mat dst;
	src.copyTo(dst);
	findContours(dst, contours, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));

	//3 测试是在轮廓内还是轮廓外
	//测试要生成一张距离的图
	Mat dst_dist = Mat::zeros(dst.size(), CV_32F);
	//3.1 对每一个像素做多边形测试,得到了每一个点跟多边形的距离
	for (size_t i = 0; i < dst.rows; i++)
	{
		for (size_t j = 0; j < dst.cols; j++)
		{
			//3.2 多边形测试,返回像素到轮廓的距离
			double dist = pointPolygonTest(contours[0], Point2f(static_cast<float>(j), static_cast<float>(i)), true);
			//3.3 每个像素点存放的是距离值
			dst_dist.at<float>(i, j) = static_cast<float>(dist);  
			/*输出在轮廓内的所有点的距离
			int z = 0;
			if (dist>0)
			{
				cout << "[" << i << "," << j << "]: " << dist << "     ";
				z++;
				if (z % 6 == 0)
					cout << endl;
			}
			*/
		}
	}

	//4 寻找最大、最小值、以及最大值的坐标
	//由于最大的值为正数,肯定在轮廓内;以轮廓内距离轮廓最远的点为圆心,距离轮廓最远的值为半径画圆,圆一定是在多边形内部,即为多边形的最大内接圆的半径
	double minValue, maxValue;
	Point maxDistPt;
	minMaxLoc(dst_dist, &minValue, &maxValue,NULL,&maxDistPt);


	//5 根据最大最小值把像素重新算出来然后生成一张图
	Mat drawImg = Mat::zeros(src.size(), CV_8UC3);
	for (size_t i = 0; i < src.rows; i++)
	{
		for (size_t j = 0; j < src.cols; j++)
		{
			//5.1 对每一个像素获取距离值
			float dist = dst_dist.at<float>(i, j);
			if (dist < 0) {//在多边形的外部
				// blue通道
				//距离轮廓越远的点,颜色越偏向于蓝色
				drawImg.at<Vec3b>(i, j)[0] = (uchar)(255 - abs(dist) * 255 / minValue);
			}
			else if (dist > 0)  //在多边形的内部
			{
				// red通道--bgr
				//距离轮廓越近的点,颜色越偏向于红色
				drawImg.at<Vec3b>(i, j)[2] = (uchar)(255 - dist * 255 / maxValue);
			}
			else //在多边形的边界线上
			{
				//颜色为白色
				drawImg.at<Vec3b>(i, j)[0] = 255;
				drawImg.at<Vec3b>(i, j)[1] = 255;
				drawImg.at<Vec3b>(i, j)[2] = 255;
			}
		}
	}

	circle(drawImg, maxDistPt, int(maxValue), Scalar(255, 255, 255),2);
	imshow("src", src);
	imshow("dst", drawImg);
	waitKey(0);

}

opencv求区域最大内接矩形 opencv最大内接圆_opencv求区域最大内接矩形


opencv求区域最大内接矩形 opencv最大内接圆_opencv求区域最大内接矩形_02

void pointPolyTest(Mat &src){

	//1 图片预处理
	//1.1 图片转化成灰度图像
	Mat gray;
	cvtColor(src, gray, COLOR_BGR2GRAY);
	

	//1.2 图像模糊消除噪音
	Mat blur_img;
	blur(gray, blur_img, Size(3, 3), Point(-1, -1));

	//1.3 图片转化成2值图像
	Mat binary;
	threshold(blur_img, binary, 127, 255, THRESH_BINARY | THRESH_OTSU);


	//2 查找轮廓
	vector<vector<Point>> contours;
	Mat dst;
	binary.copyTo(dst);
	findContours(dst, contours, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
	drawContours(dst, contours, 1, Scalar::all(255), 2, 8);

	//3 测试是在轮廓内还是轮廓外
	//测试要生成一张距离的图
	Mat dst_dist = Mat::zeros(dst.size(), CV_32F);
	//3.1 对每一个像素做多边形测试,得到了每一个点跟多边形的距离
	for (size_t i = 0; i < dst.rows; i++)
	{
		for (size_t j = 0; j < dst.cols; j++)
		{
			//3.2 多边形测试,返回像素到轮廓的距离
			double dist = pointPolygonTest(contours[1], Point2f(static_cast<float>(j), static_cast<float>(i)), true);
			//3.3 每个像素点存放的是距离值
			dst_dist.at<float>(i, j) = static_cast<float>(dist);
		}
	}

	//4 寻找最大、最小值、以及最大值的坐标
	//由于最大的值为正数,肯定在轮廓内;以轮廓内距离轮廓最远的点为圆心,距离轮廓最远的值为半径画圆,圆一定是在多边形内部,即为多边形的最大内接圆的半径
	double minValue, maxValue;
	Point maxDistPt;
	minMaxLoc(dst_dist, &minValue, &maxValue, NULL, &maxDistPt);


	//5 根据最大最小值把像素重新算出来然后生成一张图
	Mat drawImg = Mat::zeros(src.size(), CV_8UC3);
	for (size_t i = 0; i < src.rows; i++)
	{
		for (size_t j = 0; j < src.cols; j++)
		{
			//5.1 对每一个像素获取距离值
			float dist = dst_dist.at<float>(i, j);
			if (dist < 0) {//在多边形的外部
				// blue通道
				//距离轮廓越远的点,颜色越偏向于蓝色
				drawImg.at<Vec3b>(i, j)[0] = (uchar)(255 - abs(dist) * 255 / minValue);
			}
			else if (dist > 0)  //在多边形的内部
			{
				// red通道--bgr
				//距离轮廓越近的点,颜色越偏向于红色
				drawImg.at<Vec3b>(i, j)[2] = (uchar)(255 - dist * 255 / maxValue);
			}
			else //在多边形的边界线上
			{
				//颜色为白色
				drawImg.at<Vec3b>(i, j)[0] = 255;
				drawImg.at<Vec3b>(i, j)[1] = 255;
				drawImg.at<Vec3b>(i, j)[2] = 255;
			}
		}
	}

	circle(drawImg, maxDistPt, int(maxValue), Scalar(255, 255, 255), 2);
	imshow("src", src);
	imshow("dst", drawImg);
	waitKey(0);



}

opencv求区域最大内接矩形 opencv最大内接圆_OpenCV_03

opencv求区域最大内接矩形 opencv最大内接圆_i++_04