OpenCV---pointPolygonTest

news2025/6/2 2:32:15

一、基本概念与用途

pointPolygonTest 是 OpenCV 中用于判断点与多边形关系的重要函数,常用于:

  • 目标检测:判断像素点是否属于检测到的轮廓区域
  • 碰撞检测:检测物体是否重叠
  • 图像分割:确定点是否在分割区域内
  • 几何分析:计算点到多边形边界的距离

与简单边界框判断的区别:

  • 边界框只能进行粗略的矩形区域判断
  • pointPolygonTest 能够精确判断任意形状的多边形区域

在这里插入图片描述

二、函数定义与参数

1. 函数原型(C++/Python)
// C++
double pointPolygonTest(InputArray contour, Point2f pt, bool measureDist);

// Python
retval = cv2.pointPolygonTest(contour, pt, measureDist)
2. 参数说明
参数名类型描述
contourInputArray输入的多边形轮廓,通常为 vector<Point>numpy.ndarray
ptPoint2f待测试的二维点坐标
measureDistbool是否计算距离:
- True:返回带符号的距离值
- False:返回-1/0/1的符号值

三、返回值详解

函数返回值根据 measureDist 参数分为两种模式:

1. 符号判断模式(measureDist = False
  • 返回值 > 0:点在多边形内部
  • 返回值 = 0:点在多边形边界上
  • 返回值 < 0:点在多边形外部
2. 距离计算模式(measureDist = True
  • 返回正值:点在多边形内部,值为点到最近边界的距离
  • 返回0:点在多边形边界上
  • 返回负值:点在多边形外部,值为点到最近边界的负距离
3. 精度说明
  • 边界判断使用 eps = 1e-5 的容差(即距离小于该值被认为在边界上)
  • 返回值类型为 double(C++)或 float(Python)

四、核心知识点讲解

1. 多边形表示要求
  • 多边形轮廓需为简单闭合曲线(不自交)
  • 顶点顺序可为顺时针或逆时针
  • 推荐使用 findContours 函数获取的轮廓作为输入
2. 算法原理

函数基于射线法(Ray Casting Algorithm)实现:

  1. 从测试点发射一条水平射线(通常向右)
  2. 统计射线与多边形边的交点数量
  3. 奇数交点表示点在内部,偶数交点表示点在外部
3. 距离计算方法
  • 内部点:计算到最近边的垂直距离
  • 外部点:计算到最近顶点或边的最小距离
  • 边界点:返回0(考虑浮点数精度误差)
4. 性能特性
  • 时间复杂度:O(n),n为多边形顶点数
  • 空间复杂度:O(1)
  • 适合处理中小规模多边形(顶点数<1000)

五、示例代码

1. 基本用法示例
import cv2
import numpy as np

# 创建测试多边形
contour = np.array([[10, 10], [100, 10], [100, 100], [10, 100]], dtype=np.int32)

# 测试点
point_inside = (50, 50)
point_outside = (150, 150)
point_boundary = (10, 50)

# 符号判断模式
ret_inside = cv2.pointPolygonTest(contour, point_inside, False)
ret_outside = cv2.pointPolygonTest(contour, point_outside, False)
ret_boundary = cv2.pointPolygonTest(contour, point_boundary, False)

print(f"内部点结果: {ret_inside}")  # 输出: 1
print(f"外部点结果: {ret_outside}")  # 输出: -1
print(f"边界点结果: {ret_boundary}")  # 输出: 0

# 距离计算模式
dist_inside = cv2.pointPolygonTest(contour, point_inside, True)
dist_outside = cv2.pointPolygonTest(contour, point_outside, True)
dist_boundary = cv2.pointPolygonTest(contour, point_boundary, True)

print(f"内部点距离: {dist_inside}")  # 输出: 40.0
print(f"外部点距离: {dist_outside}")  # 输出: -70.71067811865476
print(f"边界点距离: {dist_boundary}")  # 输出: 0.0
2. 可视化示例
import cv2
import numpy as np

# 创建空白图像
img = np.ones((200, 200, 3), dtype=np.uint8) * 255

# 定义多边形
contour = np.array([[50, 50], [150, 30], [180, 120], [80, 150]], dtype=np.int32)

# 绘制多边形
cv2.drawContours(img, [contour], -1, (0, 255, 0), 2)

# 测试多个点
test_points = [(100, 80), (20, 20), (100, 100), (150, 150)]
colors = [(255, 0, 0), (0, 0, 255), (0, 255, 255), (255, 255, 0)]

for i, pt in enumerate(test_points):
    # 计算距离
    dist = cv2.pointPolygonTest(contour, pt, True)
    
    # 根据距离判断颜色和标签
    if dist > 0:
        status = "内部"
        color = (0, 0, 255)  # 红色
    elif dist < 0:
        status = "外部"
        color = (255, 0, 0)  # 蓝色
    else:
        status = "边界"
        color = (0, 255, 0)  # 绿色
    
    # 绘制点和标签
    cv2.circle(img, pt, 5, colors[i], -1)
    cv2.putText(img, f"{status}:{dist:.1f}", (pt[0]+10, pt[1]), 
                cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 1)

# 显示结果
cv2.imshow("Point Polygon Test", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

六、注意事项与常见误区

  1. 多边形方向无关性

    • 函数对顺时针和逆时针多边形同样有效
    • 无需关心轮廓的生成方向
  2. 浮点数精度问题

    • 边界判断存在 1e-5 的容差
    • 对于精确边界判断,建议先进行整数化处理
  3. 性能优化建议

    • 对于大规模点集测试,可先进行边界框粗筛
    • 使用 measureDist = False 可提升约30%的性能
  4. 自相交多边形处理

    • 函数对自相交多边形可能返回不可预期的结果
    • 建议先使用 approxPolyDP 进行多边形简化

七、进阶应用场景

1. 图像分割后处理
# 根据距离值进行区域细化
mask = np.zeros((height, width), dtype=np.uint8)
for y in range(height):
    for x in range(width):
        dist = cv2.pointPolygonTest(contour, (x, y), True)
        if dist >= 0:  # 内部点
            mask[y, x] = 255
        elif dist > -5:  # 边界附近点
            mask[y, x] = 128  # 半透明区域
2. 非均匀边界缓冲区域生成
# 生成边界内外的缓冲区域
inner_buffer = np.zeros_like(mask)
outer_buffer = np.zeros_like(mask)

for y in range(height):
    for x in range(width):
        dist = cv2.pointPolygonTest(contour, (x, y), True)
        if 0 < dist <= 10:  # 内部10像素缓冲
            inner_buffer[y, x] = 255
        elif -10 <= dist < 0:  # 外部10像素缓冲
            outer_buffer[y, x] = 255
3. 多边形碰撞检测优化
def polygon_collision(poly1, poly2):
    # 快速边界框检测
    rect1 = cv2.boundingRect(poly1)
    rect2 = cv2.boundingRect(poly2)
    if not (rect1[0] < rect2[0]+rect2[2] and 
            rect1[0]+rect1[2] > rect2[0] and 
            rect1[1] < rect2[1]+rect2[3] and 
            rect1[1]+rect1[3] > rect2[1]):
        return False
    
    # 精确点集检测
    for pt in poly1:
        if cv2.pointPolygonTest(poly2, tuple(pt[0]), False) >= 0:
            return True
    for pt in poly2:
        if cv2.pointPolygonTest(poly1, tuple(pt[0]), False) >= 0:
            return True
    return False

八、跨语言差异(C++ vs Python)

特性C++Python
函数参数InputArray, Point2f, boolnumpy.ndarray, tuple, bool
返回值类型doublefloat
异常处理可能抛出 cv::Exception返回 None 或抛出异常
内存管理自动管理自动垃圾回收

九、数学原理补充

1. 点到线段的距离计算

设线段端点为 A(x1,y1)B(x2,y2),测试点为 P(x0,y0),则距离计算步骤:

  1. 计算线段向量 AB = (x2-x1, y2-y1)
  2. 计算点P到A的向量 AP = (x0-x1, y0-y1)
  3. 计算点积 dot = AP · AB
  4. 计算投影比例 t = dot / ||AB||²
  5. 确定最近点:
    • t < 0 时,最近点为A
    • t > 1 时,最近点为B
    • 0 ≤ t ≤ 1 时,最近点为 A + t·AB
  6. 计算点P到最近点的欧氏距离
2. 射线法判断点在多边形内部的原理
  • 从测试点水平向右发射射线
  • 统计与多边形边的交点数量
  • 交点数量为奇数时,点在内部
  • 特殊情况处理:
    • 射线经过顶点时,仅统计边的起点
    • 射线与边共线时,忽略该边

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2393510.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Qt 的简单示例 -- 地址簿

这个工程里有两个窗口&#xff0c;都是QWidget派生的窗口 主窗口&#xff1a; 1. 运用了布局&#xff0c;按钮控件&#xff0c;单行编辑框&#xff0c;富文本编辑框等窗口部件&#xff1b; 2. 运用了 QMap 类&#xff1b; 3. 实现了点击按钮弹出子窗口的功能&#xff0c;这里子…

什么是DevOps的核心目标?它如何解决传统开发与运维之间的冲突?​

在当今数字化转型加速的时代&#xff0c;DevOps 已成为软件开发领域备受瞩目的明星理念。今天&#xff0c;本文将聚焦于 DevOps 的核心目标&#xff0c;并深入探讨它如何巧妙化解传统开发与运维之间的冲突&#xff0c;为大家揭开 DevOps 的神秘面纱并分享实用经验。本次介绍的与…

Android studio 查看aar源码出现/* compiled code */

如图查看aar源码时看不到具体实现&#xff0c;在排除是sdk版本导致的问题后&#xff0c;下面说解决方法 打开设置&#xff0c;找到插件 输入decompiler 搜索 这个是自带的反编译工具&#xff0c;启用就好了

用HTML5+JavaScript实现汉字转拼音工具

用HTML5JavaScript实现汉字转拼音工具 前一篇博文&#xff08;https://blog.csdn.net/cnds123/article/details/148067680&#xff09;提到&#xff0c;当需要将拼音添加到汉字上面时&#xff0c;用python实现比HTML5JavaScript实现繁琐。在这篇博文中用HTML5JavaScript实现汉…

基于Java,SpringBoot,Vue,UniAPP医院预约挂号买药就诊病例微信小程序系统设计

摘要 随着医疗信息化的不断推进以及“互联网医疗”模式的广泛普及&#xff0c;传统医院挂号流程中存在的排队时间长、资源分配不均等问题日益凸显&#xff0c;急需通过数字化手段加以解决。本研究设计并实现了一套基于Java、SpringBoot、Vue与UniAPP技术栈的医院预约挂号微信小…

ONNX模型的动态和静态量化

引言  通常我们将模型转换为onnx格式之后&#xff0c;模型的体积可能比较大&#xff0c;这样在某些场景下就无法适用。最近想在移动端部署语音识别、合成模型&#xff0c;但是目前的效果较好的模型动辄几个G&#xff0c;于是便想着将模型压缩一下。本文探索了两种压缩方法&…

如何用Python抓取Google Scholar

文章目录 [TOC](文章目录) 前言一、为什么要抓取Google Scholar&#xff1f;二、Google Scholar 抓取需要什么三、为什么代理对于稳定的抓取是必要的四、一步一步谷歌学者抓取教程4.1. 分页和循环4.2. 运行脚本 五、完整的Google Scholar抓取代码六、抓取Google Scholar的高级提…

Wireshark对usb设备进行抓包找不到USBPcap接口的解决方案

引言 近日工作需要针对usb设备进行抓包&#xff0c;但按照wireshark安装程序流程一步步走&#xff0c;即使勾选了安装USBPcap安装完成后开启wireshark依然不显示USBPcap接口&#xff0c;随设法进行解决。 最终能够正常显示USBPcap接口并能够正常使用进行抓包 解决方案&#x…

Socket 编程 UDP

目录 1. UDP网络编程 1.1 echo server 1.1.1 接口 1.1.1.1 创建套接字 1.1.1.2 绑定 1.1.1.3 bzero 1.1.1.4 htons&#xff08;主机序列转网络序列&#xff09; 1.1.1.5 inet_addr&#xff08;主机序列IP转网络序列IP&#xff09; 1.1.1.6 recvfrom&#xff08;让服务…

Jenkins实践(8):服务器A通过SSH调用服务器B执行Python自动化脚本

Jenkins实践(8):服务器A通过SSH调用服务器B执行Python自动化脚本 1、需求: 1、Jenkins服务器在74上,Python脚本在196服务器上 2、需要在服务器74的Jenkins上调用196上的脚本执行Python自动化测试 2、操作步骤 第一步:Linux Centos7配置SSH免密登录 Linux Centos7配置S…

lua的注意事项2

总之&#xff0c;下面的返回值不是10&#xff0c;a&#xff0c;b 而且

前端八股之HTML

前端秘籍-HTML篇 1. src和href的区别 src 用于替换当前元素&#xff0c;href 用于在当前文档和引用资源之间确立联系。 &#xff08;1&#xff09;src src 是 source 的缩写&#xff0c;指向外部资源的位置&#xff0c;指向的内容将会嵌入到文档中当前标签所在位置&#xff1…

鲲鹏Arm+麒麟V10,国产化信创 K8s 离线部署保姆级教程

Rainbond V6 国产化部署教程&#xff0c;针对鲲鹏 CPU 麒麟 V10 的离线环境&#xff0c;手把手教你从环境准备到应用上线&#xff0c;所有依赖包提前打包好&#xff0c;步骤写成傻瓜式操作指南。别说技术团队了&#xff0c;照着文档一步步来&#xff0c;让你领导来都能独立完成…

【C++ Qt】认识Qt、Qt 项目搭建流程(图文并茂、通俗易懂)

每日激励&#xff1a;“不设限和自我肯定的心态&#xff1a;I can do all things。 — Stephen Curry” 绪论​&#xff1a; 本章将开启Qt的学习&#xff0c;Qt是一个较为古老但仍然在GUI图形化界面设计中有着举足轻重的地位&#xff0c;因为它适合嵌入式和多种平台而被广泛使用…

IoT/HCIP实验-1/物联网开发平台实验Part2(HCIP-IoT实验手册版)

文章目录 概述产品和设备实例的产品和设备产品和设备的关联单个产品有多个设备为产品创建多个设备产品模型和物模型设备影子&#xff08;远程代理&#xff09; 新建产品模型定义编解码插件开发编解码插件工作原理消息类型与二进制码流添加消息&#xff08;数据上报消息&#xf…

Replacing iptables with eBPF in Kubernetes with Cilium

source: https://archive.fosdem.org/2020/schedule/event/replacing_iptables_with_ebpf/attachments/slides/3622/export/events/attachments/replacing_iptables_with_ebpf/slides/3622/Cilium_FOSDEM_2020.pdf 使用Cilium&#xff0c;结合eBPF、Envoy、Istio和Hubble等技术…

数学建模之最短路径问题

1 问题的提出 这个是我们的所要写的题目&#xff0c;我们要用LINGO编程进行编写这个题目&#xff0c;那么就是需要进行思考这个怎么进行构建这个问题的模型 首先起点&#xff0c;中间点&#xff0c;终点我们要对这个进行设计 2 三个点的设计 起点的设计 起点就是我们进去&am…

测试概念 和 bug

一 敏捷模型 在面对在开发项目时会遇到客户变更需求以及合并新的需求带来的高成本和时间 出现的敏捷模型 敏捷宣言 个人与交互重于过程与工具 强调有效的沟通 可用的软件重于完备的文档 强调轻文档重产出 客户协作重于合同谈判 主动及时了解当下的要求 相应变化…

zynq 级联多个ssd方案设计(ECAM BUG修改)

本文讲解采用zynq7045芯片如何实现200T容量高速存储方案设计&#xff0c;对于大容量高速存储卡&#xff0c;首先会想到采用pcie switch级联方式&#xff0c;因为单张ssd的容量是有限制的&#xff08;目前常见的m.2接口容量为4TB&#xff0c;U.2接口容量为16TB&#xff09;&…

brep2seq 论文笔记

Brep2Seq: a dataset and hierarchical deep learning network for reconstruction and generation of computer-aided design models | Journal of Computational Design and Engineering | Oxford Academic 这段文本描述了一个多头自注意力机制&#xff08;MultiHead Attenti…