OpenCV 边缘检测 点到多边形测试

相关概念

多边形测试(Point-in-Polygon Test)是计算机图形学和几何学中的一个经典问题,用于确定一个给定点是否位于一个多边形内部。这个测试在地理信息系统、计算机图形学、游戏开发和其他领域中非常有用。

如下方这张图,左边是给定一个多边形 ,右边图像每个像素点到这个多边形的距离分布,在多边形内部显示蓝色,距离越远,颜色越深,在多边形边上显示白色,多边形外部显示红色,距离越远颜色越深。

在这里插入图片描述

代码示例


void pot_test(){
    // 创建一个400x400的单通道图像,初始值为黑色(0)
    cv::Mat image = cv::Mat::zeros(400, 400, CV_8UC1);

    // 定义六边形的顶点
    std::vector<cv::Point> hexagon = {
            cv::Point(200, 100),
            cv::Point(300, 150),
            cv::Point(300, 250),
            cv::Point(200, 300),
            cv::Point(100, 250),
            cv::Point(100, 150)
    };

    // 绘制六边形
    cv::polylines(image, hexagon, true, cv::Scalar(255), 2);
    // 寻找轮廓
    std::vector<std::vector<cv::Point>> contours;
    cv::findContours(image, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
    // 定义要测试的点  (从图片中遍历每个像素点的位置) 这里定义为32位浮点数 是因为Mat 矩阵的值为每个位置到多边形的最短位置
    Mat raw_dist =Mat::zeros(image.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(row,col), true);
            raw_dist.at<float>(row,col) =dist;
        }
    }
    double minval,maxVal;
    //得到距离最大值和最小值
    minMaxLoc(raw_dist,&minval,&maxVal);
    cout<<"max distance is "<<maxVal<<" min distance is "<<minval;
    Mat draw_img = Mat::zeros(image.size(),CV_8UC3);

    for (int row = 0; row < draw_img.rows; ++row) {
        for (int col = 0; col < draw_img.cols; ++col) {
            //每个像素值其实是 就是点到多边形的距离
            float  dist = raw_dist.at<float>(row,col);
           if(dist>0){
                //在多边形内部  蓝色像素表示
                draw_img.at<Vec3b>(row,col)[0] = (dist/maxVal)*255 ;
            }else if(dist<0){
                // 在多边形外部 红色像素表示
                draw_img.at<Vec3b>(row,col)[2] = (dist/minval)*255 ;
            }else{
                //在边上显示白色
                draw_img.at<Vec3b>(row,col)[0] =255 ;
                draw_img.at<Vec3b>(row,col)[1] =255 ;
                draw_img.at<Vec3b>(row,col)[2] =255 ;
            }
        }
    }
    cv::imshow("source img",image);
    // 显示结果图像
    cv::imshow("Hexagon and Test Point", draw_img);
    cv::waitKey(0);
}

代码工作流程:确定一个多边形,进行轮廓寻找,确定多边形轮廓,生成与原图大小相等的距离矩阵,使用pointPolygonTest计算每个像素点的位置的多边形距离。对计算的距离进行归一化处理,在图像上以彩色形式显示。

pointPolygonTest 函数原型

CV_EXPORTS_W double pointPolygonTest( InputArray contour, Point2f pt, bool measureDist );

传入的参数:

1.轮廓检测结果数组,通常是通过findContours得到结果

2.要测试的位置

3.是否计算距离

分析函数返回结果,官方文档介绍如下;

/** @brief Performs a point-in-contour test.

The function determines whether the point is inside a contour, outside, or lies on an edge (or
coincides with a vertex). It returns positive (inside), negative (outside), or zero (on an edge)
value, correspondingly. When measureDist=false , the return value is +1, -1, and 0, respectively.
Otherwise, the return value is a signed distance between the point and the nearest contour edge.

See below a sample output of the function where each image pixel is tested against the contour:

![sample output](pics/pointpolygon.png)

@param contour Input contour.
@param pt Point tested against the contour.
@param measureDist If true, the function estimates the signed distance from the point to the
nearest contour edge. Otherwise, the function only checks if the point is inside a contour or not.
 */

如果不进行计算距离,测试点在多边形内部返回+1 ,在多边形外部返回-1,在边上返回0

如果第二个参数为True,代表需要计算距离,那么在多边形内部返回正的浮点数,在外部返回负的浮点数。在边上返回0

数学原理

cv2.pointPolygonTest() 函数的数学原理主要基于几何学中的射线投射法(Ray-Casting Method)和最小距离计算。以下是该方法的核心原理:

1. 射线投射法

射线投射法是判断一个点是否在多边形内部的常用方法。其基本思想是从该点出发,沿某个方向(通常是水平或垂直方向)发射一条射线,计算这条射线与多边形边界的交点数量。

具体步骤如下:

  1. 从测试点发射一条射线(通常向右水平)。
  2. 计算射线与多边形每条边的交点数量。
  3. 根据交点数量判断点的位置:
    • 如果交点数量为奇数,点在多边形内部。
    • 如果交点数量为偶数,点在多边形外部。

cv2.pointPolygonTest() 中,这种方法被用来快速判断点的位置关系。

2. 距离计算

measureDist 参数为 True 时,cv2.pointPolygonTest() 还会计算点到多边形边界的有符号距离。这涉及计算点到多边形所有边的最短距离:

  1. 对于每一条边,计算点到边的垂直距离。
  2. 找出最小的垂直距离作为点到多边形的最近距离。

如果点在多边形内部,这个距离是正值;如果点在多边形外部,这个距离是负值;如果点在多边形边界上,这个距离是0。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Trump. yang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值