概念介绍
测试一个点是否在给定的多边形内部,边缘或者外部
API介绍
API
double cv::pointPolygonTest(InputArray contour, Point2f pt, bool measureDist)
参数介绍
- 第一个参数InputArray contour,输入的轮廓
- 第二个参数Point2f pt,需要测试的点坐标
- 第三个参数bool measureDist
- 当
measureDist
设置为true
时,返回实际距离值。若返回值为正,表示点在多边形内部,返回值为负,表示在多边形外部,返回值为0
,表示在多边形上。 - 当
measureDist
设置为false
时,返回-1
、0
、1
三个固定值。若返回值为+1
,表示点在多边形内部,返回值为-1
,表示在多边形外部,返回值为0
,表示在多边形上。
- 当
- 返回值为
double
类型
演示代码处理步骤
- 构建一张
400x400
大小的图片,Mat::zero(400,400,cv_8UC1)
; - 画上一个六边形闭合区域
line
- 发现轮廓
- 对图像中所有的点做点、多边形测试,得到距离,归一化后显示。
代码演示
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace cv;
using namespace std;
int main(void)
{
int r = 100; //定义图片边缘
Mat src = Mat::zeros(4*r,4*r,CV_8UC1); //创建一张图片
//绘制六边形
vector<Point2f> vect(6);
//六边形顶点赋值
vect[0] = Point(3 * r / 2, static_cast<int>(1.34 * r));
vect[1] = Point(1 * r , 2 * r);
vect[2] = Point(3 * r / 2, static_cast<int>(2.866 * r));
vect[3] = Point(5 * r / 2, static_cast<int>(2.886 * r));
vect[4] = Point(3 * r , 2 * r);
vect[5] = Point(5 * r / 2, static_cast<int>(1.34 * r));
if (src.empty()) {
cout << "图片不存在" << endl;
return -1;
}
//绘制六边形
for (size_t i = 0; i < 6; i++)
{
line(src, vect[i], vect[(i + 1)%6], Scalar(255), 2, 8, 0); //循环划线绘制闭合多边形
}
namedWindow("原始图片", WINDOW_AUTOSIZE);
imshow("原始图片", src);
//寻找轮廓
vector<vector<Point>> contours; //定义轮廓点集
vector<Vec4i> hierarchy; //定义轮廓拓扑关系
findContours(src, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0)); //寻找轮廓
Mat raw_dist = Mat::zeros(src.size(), CV_32FC1); //存储点与轮廓的距离信息
for(size_t row = 0;row<raw_dist.rows;row++) //行数
for (size_t col = 0; col < raw_dist.cols; col++)
{
//获取每个点与轮廓的距离 并 存储
double dist = pointPolygonTest(contours[0], Point(static_cast<float>(col), static_cast<float>(row)), true);
raw_dist.at<float>(row, col) = static_cast<float>(dist);
}
double minValue, maxValue; //定义最大值 最小值变量
minMaxLoc(raw_dist, &minValue, &maxValue); //获取图片距离的最大值最小值
Mat dst = Mat::zeros(400,400,CV_8UC3); //创建一个rgb3通道图,用来显示距离关系
for (size_t row = 0; row < dst.rows; row++) //行数
for (size_t col = 0; col < dst.cols; col++)
{
float distance = raw_dist.at<float>(row, col);
if (distance > 0) //多边形内部
{
dst.at<Vec3b>(row, col)[0] = (uchar)(abs(distance / maxValue * 255)); //通道b 赋值
}
else if (distance < 0) //多边形外部
{
dst.at<Vec3b>(row, col)[2] = (uchar)(abs(distance/minValue * 255)); //通道r 赋值
}
else //在边缘上赋值
{
dst.at<Vec3b>(row, col)[0] = (uchar)(abs(255-distance));
dst.at<Vec3b>(row, col)[1] = (uchar)(abs(255 - distance));
dst.at<Vec3b>(row, col)[2] = (uchar)(abs(255 - distance));
}
}
namedWindow("最终图片", WINDOW_AUTOSIZE);
imshow("最终图片", dst);
waitKey(0);
destroyAllWindows();
return 0;
}