cv2.fillPoly是生成多边形掩码最直接可靠的方法:需将顶点转为int32、(n,1,2)形状,用uint8零数组初始化后填1,再转bool;注意坐标系、边界检查及孔洞/自相交限制。

用 cv2.fillPoly 生成多边形掩码最直接
NumPy 本身不提供“按多边形顶点生成布尔掩码”的内置函数,硬靠 np.meshgrid + 射线法或绕数法写逻辑既慢又易错。实际项目中,cv2.fillPoly(来自 OpenCV)是更可靠的选择:它底层用优化的扫描线算法填充多边形,输出就是和目标图像等尺寸的 uint8 掩码,可直接转为 bool 用于 NumPy 索引。
关键点:
-
cv2.fillPoly输入顶点必须是int32类型的ndarray,形状为(n, 1, 2)(OpenCV 要求),不是常见的(n, 2) - 掩码数组需预先用
np.zeros((h, w), dtype=np.uint8)初始化,尺寸必须匹配你要提取坐标的图像/网格 - 填充值用
1(非 255),方便后续.astype(bool)转换,避免误判灰度值
import numpy as np import cv2 <h1>假设目标区域是四边形,顶点顺序顺时针或逆时针均可</h1><p>pts = np.array([[10, 20], [50, 15], [45, 60], [5, 50]], dtype=np.int32) mask_h, mask_w = 100, 100 mask = np.zeros((mask_h, mask_w), dtype=np.uint8) cv2.fillPoly(mask, [pts.reshape((-1, 1, 2))], color=1) mask_bool = mask.astype(bool) # → 可用于布尔索引
想纯 NumPy 实现?小心绕数法的边界和性能陷阱
如果因环境限制不能用 OpenCV,可用绕数法(winding number)判断点是否在多边形内,但要注意:shapely 不算纯 NumPy,而手写向量化绕数计算在大网格上极易内存爆炸或出错。
常见错误现象:
立即学习“Python免费学习笔记(深入)”;
- 顶点数组未闭合(首尾点不重合),导致绕数计算偏差
- 用
np.vectorize包裹标量绕数函数——看似简洁,实则比 Python 循环还慢,完全失去 NumPy 优势 - 对高分辨率网格(如 1000×1000)做全量逐点判断,内存占用达 GB 级,且无必要
可行折中方案:
SkillSub Pro - Python 题解与代码注释双功能技能功能概述SkillSub Pro - Python 题解与代码注释双功能技能是一项面向实际任务的技能,主要用于SkillSub Pro 是一个 Python 题解生成与代码注释的 双功能合体技能 ,专为学生、算法学习者和开发者设计;✅ 一个技能,两种用途 :;核心要点📝 题解模式 :输入题目/题号,自动生成完整 Python 题解(含详细注释、解题思路、复杂度分析);💬 注释模式 :输入 Python 代码,自动添加详细中。它将相关步骤、
- 先用
cv2.boundingRect(pts)获取多边形外接矩形,在该 ROI 内做绕数判断,大幅减少计算量 - 用
numba.jit(nopython=True)加速绕数核心循环,比纯 Python 快 10–50 倍 - 避免返回完整
bool矩阵,改用np.column_stack(np.where(...))直接提取坐标对,节省内存
提取坐标时别直接用 np.where(mask_bool) 做二维索引
np.where(mask_bool) 返回的是 (row_indices, col_indices) 元组,直接用于图像切片会出错——因为图像索引是 [y, x],而多数人习惯按 (x, y) 存顶点。坐标系错位会导致掩码区域偏移或翻转。
正确做法:
- 确认你的多边形顶点是按图像坐标系(y 向下、x 向右)定义的,还是绘图坐标系(y 向上);OpenCV 默认前者
- 若需 (x, y) 格式的坐标列表,显式转置:
coords = np.stack(np.where(mask_bool)[::-1], axis=-1) - 若后续要索引原图
img,直接用img[mask_bool]提取像素值,无需手动拼坐标
示例:
# img.shape == (100, 100, 3) pixels_inside = img[mask_bool] # ✅ 正确,一维数组,长度 = True 个数 # 错误写法:img[np.where(mask_bool)] → 返回 tuple,不能直接索引
多边形含孔洞或自相交?cv2.fillPoly 默认不支持
cv2.fillPoly 对单个简单多边形可靠,但遇到带孔洞(hole)或多段不连通轮廓时,需拆解处理:
- 孔洞必须用负面积方向(如外轮廓逆时针、内轮廓顺时针)绘制,且 OpenCV 3.4+ 才支持自动识别;旧版本需手动用
cv2.subtract - 自相交多边形(如五角星)可能被当成多个子区域,
cv2.fillPoly填充结果依赖于渲染模式(non-zero vs even-odd),默认是 non-zero - 复杂情况建议先用
shapely.ops.unary_union归一化几何体,再转为像素掩码
真正容易被忽略的是:当多边形顶点坐标含浮点数时,cv2.fillPoly 会静默截断为整数,导致亚像素偏移。务必提前 np.round().astype(int),并检查是否仍在图像边界内。

















