Python在图片上画多边形:从简单轮廓到复杂区域标注

张开发
2026/4/19 22:34:20 15 分钟阅读

分享文章

Python在图片上画多边形:从简单轮廓到复杂区域标注
这是一篇为您定制的技术博客风格延续了上一篇的实用教程风重点讲解如何使用 Python 绘制多边形适合发布在 CSDN、知乎、掘金等技术社区。在上一篇《Python在图片上画圆形》中我们掌握了基础的几何绘制。但在实际的计算机视觉任务中比如图像分割、目标检测框选、不规则区域标注如标注车牌、建筑物轮廓仅仅画圆和矩形是不够的。多边形Polygon才是描述不规则形状的王者。今天我们就来深入探讨如何使用 Python 的 OpenCV 和 Pillow 库在图片上绘制任意形状的多边形。一、 为什么需要画多边形数据标注在制作 AI 数据集时需要精确框出物体的边缘Polygon Annotation。ROI 提取指定图像中的感兴趣区域Region of Interest屏蔽掉无关背景。视觉特效在图片上添加水印遮罩、马赛克块本质也是多边形组合。二、 环境准备确保你已经安装了必要的库pipinstallopencv-python pipinstallPillow pipinstallnumpy准备一张测试图片test_image.jpg。三、 方法一使用 OpenCV (cv2) —— 精准控制OpenCV 是处理多边形的首选因为它提供了非常底层的控制能力。核心函数是cv2.polylines()和cv2.fillPoly()。1. 核心难点点的格式OpenCV 对多边形顶点的格式要求非常严格必须是int32类型的 NumPy 数组且形状为(-1, 1, 2)。2. 基础代码画一个五边形importcv2importnumpyasnp# 1. 读取图片imagecv2.imread(test_image.jpg)ifimageisNone:print(图片读取失败)exit()# 2. 定义多边形的顶点坐标 (x, y)# 假设我们要画一个五边形手动定义5个点pointsnp.array([[100,300],# 点1[200,200],# 点2[300,300],# 点3[250,400],# 点4[150,400]# 点5],dtypenp.int32)# 3. 重塑数组形状 (这一步非常重要)# 从 (5, 2) 变为 (5, 1, 2)pointspoints.reshape((-1,1,2))# 4. 绘制轮廓# 参数图像, [顶点数组], 是否闭合, 颜色(BGR), 线条粗细cv2.polylines(image,[points],isClosedTrue,color(0,255,255),thickness3)# 5. 显示与保存cv2.imshow(Polygon (Outline),image)cv2.imwrite(result_polyline.jpg,image)cv2.waitKey(0)cv2.destroyAllWindows()3. 参数详解isClosedTrue多边形是闭合的最后一个点会连回第一个点。False多边形是开放的折线。color依然是 BGR 格式。(0, 255, 255)是黄色。thickness正数如3线条宽度。负数如-1如果是用cv2.fillPoly或者配合特定参数表示填充。注意cv2.polylines不支持直接填充填充请用下面的方法。4. 进阶填充实心多边形如果你想画一个实心的红色多边形使用cv2.fillPoly()# 复制原图以免混淆filled_imageimage.copy()# 使用 fillPoly# 注意这里不需要 reshape 成 (-1, 1, 2)直接传 (N, 2) 也可以但传标准格式更安全cv2.fillPoly(filled_image,[points],color(0,0,255))# 红色 (BGR)cv2.imshow(Polygon (Filled),filled_image)cv2.waitKey(0)5. 高级技巧半透明多边形Alpha 混合在做标注时我们常需要半透明的遮罩。OpenCV 没有直接的 “Alpha” 参数需要手动混合# 创建一个和原图一样大的透明层overlayimage.copy()# 在透明层上画实心多边形cv2.fillPoly(overlay,[points],color(0,0,255))# 红色# 混合原图和透明层 (原图权重0.7, 覆盖层权重0.3)alpha0.3cv2.addWeighted(overlay,alpha,image,1-alpha,0,image)cv2.imshow(Transparent Polygon,image)cv2.waitKey(0)四、 方法二使用 Pillow (PIL) —— 简单直观Pillow 的 API 设计更符合人类直觉不需要复杂的数组重塑。1. 基础代码示例fromPILimportImage,ImageDraw# 1. 打开图片imageImage.open(test_image.jpg)drawImageDraw.Draw(image)# 2. 定义顶点 (直接是扁平列表 [x1, y1, x2, y2, ...] 或 元组列表)# Pillow 支持 [(x1, y1), (x2, y2), ...] 格式更友好polygon_points[(100,300),(200,200),(300,300),(250,400),(150,400)]# 3. 绘制# outline: 边框颜色 (RGB)# fill: 填充颜色 (RGB)# width: 边框宽度draw.polygon(polygon_points,outline(255,0,0),fill(0,255,0),width3)# 4. 显示与保存image.show()image.save(result_pillow_poly.jpg)2. Pillow 的优势坐标格式支持简单的元组列表[(x, y), ...]不需要 Reshape。颜色格式使用标准的 RGB不用记 BGR。抗锯齿Pillow 的绘制引擎自带抗锯齿效果边缘看起来更平滑OpenCV 需要手动开启抗锯齿比较麻烦。五、 实战案例不规则区域标注模拟 LabelMe假设我们要在图片上标注出一个不规则的区域并打上标签。使用 OpenCV 实现完整流程importcv2importnumpyasnp# 读取图片imgcv2.imread(test_image.jpg)# 1. 定义不规则区域的顶点 (模拟鼠标点击选取)ptsnp.array([[50,50],[400,100],[300,300],[100,350]],np.int32)ptspts.reshape((-1,1,2))# 2. 画轮廓 (黄色粗线)cv2.polylines(img,[pts],True,(0,255,255),2)# 3. 计算区域中心点用于写文字Mcv2.moments(pts)cXint(M[m10]/M[m00])cYint(M[m01]/M[m00])# 4. 写标签文字labelObject Acv2.putText(img,label,(cX-30,cY),cv2.FONT_HERSHEY_SIMPLEX,0.6,(0,255,255),2)# 5. 显示结果cv2.imshow(Annotation,img)cv2.waitKey(0)cv2.destroyAllWindows()六、 常见坑与 FAQQ1: 运行 OpenCV 代码报错(-2115:Assertion failed)怎么办A:90% 的情况是点数组的维度或数据类型不对。检查是否执行了points.reshape((-1, 1, 2))。检查数据类型是否为np.int32。检查传入的是[points](列表包裹数组)而不是直接传points。Q2: 多边形画出来一部分在屏幕外怎么办A:OpenCV 和 Pillow 都会自动裁剪Clip到图像边界不会报错但超出部分看不见。如果需要处理坐标越界需要自己写逻辑判断if 0 x width。Q3: 如何画带虚线的多边形A: 这是一个进阶需求。Pillow不支持直接画虚线多边形需要自己循环画线段。OpenCV可以通过计算线段交点或者使用cv2.line循环绘制每一条边来模拟虚线效果。Q4: 如何生成多边形的掩码MaskA: 这是一个非常常用的操作用于抠图。# 创建一张全黑的单通道图masknp.zeros(img.shape[:2],dtypenp.uint8)# 在掩码上画白色的实心多边形cv2.fillPoly(mask,[points],255)# 使用 mask 提取原图区域resultcv2.bitwise_and(img,img,maskmask)七、 总结特性OpenCV (cv2.polylines)Pillow (ImageDraw.polygon)易用性⭐⭐ (需处理数组维度)⭐⭐⭐⭐⭐ (非常简单)性能⭐⭐⭐⭐⭐ (极快)⭐⭐⭐ (够用)功能支持掩码、抗锯齿(较复杂)、填充支持抗锯齿、简单填充颜色BGR (易踩坑)RGB (直观)推荐场景视频处理、实时标注、生成Mask简单图片编辑、生成静态图画多边形是图像处理从“初级”迈向“中级”的标志。当你能熟练地在图片上绘制任意多边形并生成掩码时你就已经掌握了图像分割和复杂目标检测的基础工具。下一篇我们将讲解如何结合鼠标事件实时交互地在图片上画多边形像 LabelMe 一样敬请期待如果这篇文章帮你解决了问题欢迎点赞、关注支持

更多文章