OpenCV---pointPolygonTest
一、基本概念与用途
pointPolygonTest
是 OpenCV 中用于判断点与多边形关系的重要函数,常用于:
- 目标检测:判断像素点是否属于检测到的轮廓区域
- 碰撞检测:检测物体是否重叠
- 图像分割:确定点是否在分割区域内
- 几何分析:计算点到多边形边界的距离
与简单边界框判断的区别:
- 边界框只能进行粗略的矩形区域判断
pointPolygonTest
能够精确判断任意形状的多边形区域
二、函数定义与参数
1. 函数原型(C++/Python)
// C++
double pointPolygonTest(InputArray contour, Point2f pt, bool measureDist);// Python
retval = cv2.pointPolygonTest(contour, pt, measureDist)
2. 参数说明
参数名 | 类型 | 描述 |
---|---|---|
contour | InputArray | 输入的多边形轮廓,通常为 vector<Point> 或 numpy.ndarray |
pt | Point2f | 待测试的二维点坐标 |
measureDist | bool | 是否计算距离: - 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)实现:
- 从测试点发射一条水平射线(通常向右)
- 统计射线与多边形边的交点数量
- 奇数交点表示点在内部,偶数交点表示点在外部
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()
六、注意事项与常见误区
-
多边形方向无关性:
- 函数对顺时针和逆时针多边形同样有效
- 无需关心轮廓的生成方向
-
浮点数精度问题:
- 边界判断存在
1e-5
的容差 - 对于精确边界判断,建议先进行整数化处理
- 边界判断存在
-
性能优化建议:
- 对于大规模点集测试,可先进行边界框粗筛
- 使用
measureDist = False
可提升约30%的性能
-
自相交多边形处理:
- 函数对自相交多边形可能返回不可预期的结果
- 建议先使用
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] = 255elif 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] = 255elif -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 Truefor pt in poly2:if cv2.pointPolygonTest(poly1, tuple(pt[0]), False) >= 0:return Truereturn False
八、跨语言差异(C++ vs Python)
特性 | C++ | Python |
---|---|---|
函数参数 | InputArray , Point2f , bool | numpy.ndarray , tuple, bool |
返回值类型 | double | float |
异常处理 | 可能抛出 cv::Exception | 返回 None 或抛出异常 |
内存管理 | 自动管理 | 自动垃圾回收 |
九、数学原理补充
1. 点到线段的距离计算
设线段端点为 A(x1,y1)
和 B(x2,y2)
,测试点为 P(x0,y0)
,则距离计算步骤:
- 计算线段向量
AB = (x2-x1, y2-y1)
- 计算点P到A的向量
AP = (x0-x1, y0-y1)
- 计算点积
dot = AP · AB
- 计算投影比例
t = dot / ||AB||²
- 确定最近点:
t < 0
时,最近点为At > 1
时,最近点为B0 ≤ t ≤ 1
时,最近点为A + t·AB
- 计算点P到最近点的欧氏距离
2. 射线法判断点在多边形内部的原理
- 从测试点水平向右发射射线
- 统计与多边形边的交点数量
- 交点数量为奇数时,点在内部
- 特殊情况处理:
- 射线经过顶点时,仅统计边的起点
- 射线与边共线时,忽略该边
相关文章:

OpenCV---pointPolygonTest
一、基本概念与用途 pointPolygonTest 是 OpenCV 中用于判断点与多边形关系的重要函数,常用于: 目标检测:判断像素点是否属于检测到的轮廓区域碰撞检测:检测物体是否重叠图像分割:确定点是否在分割区域内几何分析&am…...

Qt 的简单示例 -- 地址簿
这个工程里有两个窗口,都是QWidget派生的窗口 主窗口: 1. 运用了布局,按钮控件,单行编辑框,富文本编辑框等窗口部件; 2. 运用了 QMap 类; 3. 实现了点击按钮弹出子窗口的功能,这里子…...
Linux 下 C 语言实现工厂模式
Linux 下 C 语言实现工厂模式:设计理念与实战 🧠 一、工厂模式简介什么是工厂模式?C 语言实现设计模式的挑战 🏗️ 二、实现简单工厂模式(Simple Factory)1. 定义传感器接口(device.h࿰…...

什么是DevOps的核心目标?它如何解决传统开发与运维之间的冲突?
在当今数字化转型加速的时代,DevOps 已成为软件开发领域备受瞩目的明星理念。今天,本文将聚焦于 DevOps 的核心目标,并深入探讨它如何巧妙化解传统开发与运维之间的冲突,为大家揭开 DevOps 的神秘面纱并分享实用经验。本次介绍的与…...
RocketMQ 死信队列(DLQ)实战:原理 + 开发 + 运维 + 架构应用指南
🚀RocketMQ 死信队列(DLQ)实战:原理 开发 运维 架构应用指南 第一章:什么是死信队列(DLQ)? 1.1 死信队列定义 在 RocketMQ 中,死信队列(Dead Letter Que…...

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

用HTML5+JavaScript实现汉字转拼音工具
用HTML5JavaScript实现汉字转拼音工具 前一篇博文(https://blog.csdn.net/cnds123/article/details/148067680)提到,当需要将拼音添加到汉字上面时,用python实现比HTML5JavaScript实现繁琐。在这篇博文中用HTML5JavaScript实现汉…...

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

ONNX模型的动态和静态量化
引言 通常我们将模型转换为onnx格式之后,模型的体积可能比较大,这样在某些场景下就无法适用。最近想在移动端部署语音识别、合成模型,但是目前的效果较好的模型动辄几个G,于是便想着将模型压缩一下。本文探索了两种压缩方法&…...
PHP 垃圾回收高级特性
PHP 垃圾回收高级特性 1. 循环引用与内存泄漏 单纯的引用计数在遇到循环引用时会导致内存泄漏,主要原因是引用计数无法正确识别那些仅通过循环引用相互关联但实际上已经不可达的对象。 1.1 引用计数的基本原理 引用计数是一种内存管理机制,通过维护每…...
OpenFeign vs MQ:微服务通信如何选型?详解同步与异步的适用场景
OpenFeign vs MQ:微服务通信如何选型?详解同步与异步的适用场景 引言 在微服务架构中,服务之间的通信方式直接影响系统的性能、可靠性和可维护性。常见的通信方式有 OpenFeign(同步HTTP调用) 和 MQ(消息队…...
如何用命令行将 PDF 表格转换为 HTML 表格
本文将介绍如何使用命令行将可填写的 PDF 表单转换为 HTML 表单。只需几行代码即可完成转换。将可填写的 PDF 表单转换为 HTML 表单后,你可以在网页上显示这些表单。本指南使用 FormVu 来演示转换过程。 使用命令行将可填写 PDF 表单转换为 HTML 表单 你可以通过命…...
html5的响应式布局的方法示例详解
以下是HTML5实现响应式布局的5种核心方法及代码示例: 1. 媒体查询(核心方案) /* 默认样式(移动优先) */ .container {padding: 15px; }/* 中等屏幕(平板) */ @media (min-width: 768px) {.container {padding: 30px;max-width: 720px;} }/* 大屏幕(桌面) */ @media …...

如何用Python抓取Google Scholar
文章目录 [TOC](文章目录) 前言一、为什么要抓取Google Scholar?二、Google Scholar 抓取需要什么三、为什么代理对于稳定的抓取是必要的四、一步一步谷歌学者抓取教程4.1. 分页和循环4.2. 运行脚本 五、完整的Google Scholar抓取代码六、抓取Google Scholar的高级提…...
电脑革命家测试版:硬件检测,6MB 轻量无广告 清理垃圾 + 禁用系统更新
各位电脑小白和大神们,我跟你们说啊!有个超牛的东西叫电脑革命家测试版,这是吾爱破解论坛的开发者搞出来的免费无广告系统工具集合,主打硬件检测和系统优化,就像是鲁大师这些软件的平替。下面我给你们唠唠它的核心功能…...

Wireshark对usb设备进行抓包找不到USBPcap接口的解决方案
引言 近日工作需要针对usb设备进行抓包,但按照wireshark安装程序流程一步步走,即使勾选了安装USBPcap安装完成后开启wireshark依然不显示USBPcap接口,随设法进行解决。 最终能够正常显示USBPcap接口并能够正常使用进行抓包 解决方案&#x…...
题目 3298: 蓝桥杯2024年第十五届决赛真题-兔子集结
题目 3298: 蓝桥杯2024年第十五届决赛真题-兔子集结 时间限制: 2s 内存限制: 192MB 提交: 2499 解决: 309 题目描述 在森林幽静的一隅,有一村落居住着 n 只兔子。 某个月光皎洁的夜晚,这些兔子列成一队,准备开始一场集结跳跃活动。村落中…...
Unity开发之Webgl自动更新程序包
之前让客户端更新webgl程序是在程序里写版本号然后和服务器对比,不同就调用 window.location.reload(true);之前做的客户端都是给企业用,用户数少看不出来啥问题。后来自己开发一个小网站,用户数量还是挺多,然后就会遇到各种各样的…...
深入理解设计模式之状态模式
深入理解设计模式之:状态模式(State Pattern) 一、什么是状态模式? 状态模式(State Pattern)是一种行为型设计模式。它允许一个对象在其内部状态发生改变时,改变其行为(即表现出不…...

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(主机序列转网络序列) 1.1.1.5 inet_addr(主机序列IP转网络序列IP) 1.1.1.6 recvfrom(让服务…...

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…...
Spring AI系列之Spring AI 集成 ChromaDB 向量数据库
1. 概述 在传统数据库中,我们通常依赖精确的关键词或基本的模式匹配来实现搜索功能。虽然这种方法对于简单的应用程序已经足够,但它无法真正理解自然语言查询背后的含义和上下文。 向量存储解决了这一限制,它通过将数据以数值向量的形式存储…...

lua的注意事项2
总之,下面的返回值不是10,a,b 而且...
主流电商平台的反爬机制解析
随着数据成为商业决策的重要资源,越来越多企业和开发者希望通过技术手段获取电商平台的公开信息,用于竞品分析、价格监控、市场调研等。然而,主流电商平台如京东、淘宝(含天猫)等为了保护数据安全和用户体验࿰…...

前端八股之HTML
前端秘籍-HTML篇 1. src和href的区别 src 用于替换当前元素,href 用于在当前文档和引用资源之间确立联系。 (1)src src 是 source 的缩写,指向外部资源的位置,指向的内容将会嵌入到文档中当前标签所在位置࿱…...
tiktoken学习
1.tiktoken是OpenAI编写的进行高效分词操作的库文件。 2.操作过程: enc tiktoken.get_encoding("gpt2") train_ids enc.encode_ordinary(train_data) val_ids enc.encode_ordinary(val_data) 以这段代码为例,get_encoding是创建了一个En…...

鲲鹏Arm+麒麟V10,国产化信创 K8s 离线部署保姆级教程
Rainbond V6 国产化部署教程,针对鲲鹏 CPU 麒麟 V10 的离线环境,手把手教你从环境准备到应用上线,所有依赖包提前打包好,步骤写成傻瓜式操作指南。别说技术团队了,照着文档一步步来,让你领导来都能独立完成…...
历年厦门大学计算机保研上机真题
2025厦门大学计算机保研上机真题 2024厦门大学计算机保研上机真题 2023厦门大学计算机保研上机真题 在线测评链接:https://pgcode.cn/school 数字变换过程的最大值与步数 题目描述 输入一个数字 n n n,如果 n n n 是偶数就将该偶数除以 2 2 2&…...

【C++ Qt】认识Qt、Qt 项目搭建流程(图文并茂、通俗易懂)
每日激励:“不设限和自我肯定的心态:I can do all things。 — Stephen Curry” 绪论: 本章将开启Qt的学习,Qt是一个较为古老但仍然在GUI图形化界面设计中有着举足轻重的地位,因为它适合嵌入式和多种平台而被广泛使用…...

IoT/HCIP实验-1/物联网开发平台实验Part2(HCIP-IoT实验手册版)
文章目录 概述产品和设备实例的产品和设备产品和设备的关联单个产品有多个设备为产品创建多个设备产品模型和物模型设备影子(远程代理) 新建产品模型定义编解码插件开发编解码插件工作原理消息类型与二进制码流添加消息(数据上报消息…...