
目录一、绘图前置基础画布如何创建1. 画布本质2. 颜色规则二、基础线条绘制直线三、矩形绘制四、圆形绘制五、椭圆绘制六、多边形绘制七、画布写入文字八、综合交互RGB动态调色滑块九、绘图通用参数对照表十、绘图高频踩坑点1. 画布 shape 顺序高度在前宽度在后2. 颜色顺序是 BGR不是 RGB3. 坐标系统x 是水平方向y 是垂直方向4. cv2.waitKey(0) 在循环中不能填 05. 滑动条回调函数不能省略或删除6. 多边形顶点数组需要外层再加 []7. cv2.putText 原生不支持中文8. 椭圆角度单位是角度制不是弧度9. cv2.polylines 不会填充多边形十一、本章小结在上一章中我们完成了 OpenCV 的基础入门掌握了图片的读取与写入、缩放旋转、摄像头拍摄与录像等图像基础操作。这些技能让我们能够熟练地处理已有的图像数据。然而图像处理不仅仅是“处理”更是“创造”。本章我们将脱离对本地照片的依赖从一张空白的画布开始系统地学习 OpenCV 强大的绘图 API。我们将从最基础的直线、矩形、圆形、椭圆、多边形绘制到在画布上写入文字最后通过一个综合案例——结合滑动条Trackbar实现一个可实时调整的 RGB 调色面板将理论与实践紧密结合。一、绘图前置基础画布如何创建1. 画布本质画布就是numpy创建的像素矩阵格式np.zeros(高度, 宽度, 通道数, 数据类型)通道3BGR彩色画布蓝、绿、红三色通道通道1灰度黑白画布np.uint8像素取值范围0~255图像标准数据类型2. 颜色规则OpenCV颜色书写格式为(B, G, R)三个数值范围0~255数值越大对应颜色越亮。二、基础线条绘制直线函数语法cv2.line(画布, 起点(x,y), 终点(x,y), 颜色(BGR), 线宽, 线型)下表详细列出了cv2.line函数的各个参数参数名数据类型默认值作用说明示例值画布 (img)numpy.ndarray无要在其上绘制直线的图像矩阵通常由np.zeros()或cv2.imread()创建。img一个形状为 (800,800,3) 的数组起点 (pt1)tuple (int, int)无直线的起始点坐标格式为(x, y)其中 x 为水平方向从左到右y 为垂直方向从上到下。(0, 0)终点 (pt2)tuple (int, int)无直线的结束点坐标格式同样为(x, y)。(200, 200)颜色 (color)tuple (int, int, int)无线条的 BGR 颜色值每个分量取值范围 0~255。例如(255, 0, 255)表示紫色B255, G0, R255。(255, 0, 255)线宽 (thickness)int1线条的粗细以像素为单位。必须为正整数。值越大线条越粗。5线型 (lineType)int8控制线条的绘制算法和连接方式影响线条的平滑度和抗锯齿效果。常用值44-连通线型。使用 Bresenham 算法只允许在水平、垂直或对角线方向45度绘制像素。线条可能出现锯齿但绘制速度快。88-连通线型默认。使用 Bresenham 算法允许在水平、垂直以及对角线45度方向绘制像素线条相对更平滑。cv2.LINE_AA抗锯齿线型。使用高斯滤波进行抗锯齿处理线条边缘最平滑但绘制速度稍慢。通常用于需要高质量显示的图形。在代码中cv2.LINE_AA的值通常为 16。4,8,cv2.LINE_AAshift (可选)int0坐标和半径值中的小数位数。例如shift1表示坐标值可以精确到 0.5 像素即坐标值乘以 2shift。通常保持默认值 0。0关于线型参数的进一步说明4-连通 (lineType4)在绘制斜线时只能沿严格的对角线方向45度移动因此线条可能看起来有“阶梯”感不够平滑。适用于对性能要求高、对视觉效果要求不高的场景。8-连通 (lineType8)允许更灵活的像素连接方式斜线绘制更平滑是大多数情况下的推荐选择。抗锯齿 (lineTypecv2.LINE_AA)通过插值算法使线条边缘过渡平滑消除锯齿。在需要高质量显示如文字、精细图形时使用。在示例代码中第一条线使用lineType4第二条线使用lineType8你可以运行代码观察两者视觉上的细微差别。# opencv直线.py import cv2 import numpy as np # 创建800×800黑色三通道画布 img np.zeros(shape (800,800,3), dtype np.uint8) # 第一条线起点(0,0)终点(200,200)紫粉色线宽54线型 cv2.line(img, (0,0), (200,200), (255, 0, 255),5,4) # 第二条线起点(0,200)终点(200,0)浅紫线宽108线型 cv2.line(img, (0,200), (200,0), (255, 100, 255),10,8) # 展示画布 cv2.imshow(line, img) # 循环监听q退出 while 1: key cv2.waitKey(10) if key ord(q): break cv2.destroyAllWindows()三、矩形绘制函数语法cv2.rectangle(画布, 左上角坐标, 右下角坐标, 颜色, 线宽)线宽填-1代表填充内部大于0仅绘制边框# opencv绘制矩形圆形.py import cv2 import numpy as np # 512×512空白画布 img np.zeros((512,512,3), np.uint8) # 绘制矩形左上(100,100) 右下(300,300)紫色边框线宽5 cv2.rectangle(img, (100,100), (300,300), (255, 0, 255),5,4) # 绘制圆形圆心(300,300)半径100紫色线宽5 cv2.circle(img, (300,300), 100, (255, 0, 255),5,4) cv2.imshow(img, img) while 1: key cv2.waitKey(10) if key ord(q): break cv2.destroyAllWindows()四、圆形绘制函数语法cv2.circle(画布, 圆心(x,y), 半径, 颜色, 线宽)线宽-1直接填充整圆。五、椭圆绘制函数语法cv2.ellipse(画布, 中心点, (半长轴,半短轴), 旋转角度, 起始角, 结束角, 颜色, 线宽)# opencv绘制椭圆.py import cv2 import numpy as np img np.zeros((512,512,3), np.uint8) # 中心点(200,200)长半轴100短半轴50无旋转完整360度椭圆 cv2.ellipse(img, (200,200), (100,50), 0, 0, 360, (255, 0, 255), 5, 4) cv2.imshow(img, img) while 1: key cv2.waitKey(10) if key ord(q): break cv2.destroyAllWindows()六、多边形绘制函数说明cv2.polylines(画布, [顶点数组], 是否闭合, 颜色, 线宽)顶点必须用np.int32类型外层加[]包裹fillPoly实现填充多边形# opencv绘制多边形.py import cv2 import numpy as np img np.zeros((512,512,3), np.uint8) # 定义四个顶点坐标 pts np.array([(10,5),(200,70),(54,200),(500,483)], np.int32) # 绘制闭合多边形蓝色线宽3使用抗锯齿线型 cv2.polylines(img, [pts], True, (255,0,0), 3, cv2.LINE_AA) # 取消注释可填充多边形 # cv2.fillPoly(img, [pts], (0,255,0)) cv2.imshow(img, img) while 1: key cv2.waitKey(10) if key ord(q): break cv2.destroyAllWindows()七、画布写入文字函数语法cv2.putText(画布, 文字内容, 文字左下角坐标, 字体, 字号, 颜色, 线宽, lineType, bottomLeftOrigin)# opencv绘制文字.py import cv2 import numpy as np img np.zeros((520,520,3), np.uint8) # 在坐标(10,500)写入文字基础字体字号1紫色 cv2.putText(img, Hello World, (10, 500), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 255), 2, cv2.LINE_AA,False) cv2.imshow(img, img) while 1: key cv2.waitKey(10) if key ord(q): break cv2.destroyAllWindows()八、综合交互RGB动态调色滑块核心知识点createTrackbar创建滑动条绑定回调函数getTrackbarPos获取滑块实时数值实时修改画布全部像素BGR数值实现变色效果# opencv调色块.py import cv2 import numpy as np # 空回调函数滑动条变动时触发 def callback(val): pass # 创建可缩放窗口 cv2.namedWindow(trackbar,cv2.WINDOW_NORMAL) cv2.resizeWindow(trackbar,680,480) # 创建R、G、B三条滑动条取值范围0~255 cv2.createTrackbar(R,trackbar,0,255,callback) cv2.createTrackbar(G,trackbar,0,255,callback) cv2.createTrackbar(B,trackbar,0,255,callback) # 创建480行680列三通道黑色画布 img np.zeros(shape (480,680,3) , dtype np.uint8) # 循环实时读取滑块数值更新画布颜色 while 1: # 获取三个通道滑块值 r cv2.getTrackbarPos(R,trackbar) g cv2.getTrackbarPos(G,trackbar) b cv2.getTrackbarPos(B,trackbar) # 整张画布统一填充BGR颜色 img[:] [b,g,r] cv2.imshow(trackbar,img) key cv2.waitKey(10) # 循环不能填0画面实时刷新 if key ord(q): break cv2.destroyAllWindows()九、绘图通用参数对照表绘图函数必传核心参数填充规则cv2.line起点、终点、颜色、线宽仅线条无填充cv2.rectangle对角两点、颜色、线宽thickness-1 内部填充cv2.circle圆心、半径、颜色、线宽thickness-1 实心圆cv2.ellipse中心、轴长、角度、颜色可绘制完整/部分圆弧cv2.polylines顶点数组、闭合开关fillPoly专门用来实现内部填充十、绘图高频踩坑点OpenCV 绘图功能虽然强大但新手在使用时常常会遇到一些看似简单却容易卡住的细节问题。本节汇总了从画布创建到图形绘制、交互操作中最常见的 9 个踩坑点帮你快速避坑。1. 画布 shape 顺序高度在前宽度在后创建画布时np.zeros()的第一个参数是(高度, 宽度, 通道数)而不是(宽度, 高度, 通道数)。这与图像读取后得到的数组维度一致但容易与日常的“宽×高”习惯混淆。# 正确高度在前宽度在后 img np.zeros((480, 640, 3), dtypenp.uint8) # 480行高× 640列宽× 3通道 错误宽度在前高度在后会导致后续坐标计算混乱 img_wrong np.zeros((640, 480, 3), dtypenp.uint8)2. 颜色顺序是 BGR不是 RGBOpenCV 默认使用 BGR 颜色通道顺序这与大多数图像处理库如 Matplotlib、PIL的 RGB 顺序相反。直接使用 RGB 三元组会导致颜色显示异常。# 正确BGR 顺序 color_bgr (255, 0, 0) # 蓝色B255, G0, R0 color_green (0, 255, 0) # 绿色 color_red (0, 0, 255) # 红色 错误RGB 顺序在 OpenCV 中会显示为红、绿、蓝错乱 color_wrong (255, 0, 0) # 在 RGB 中是红色在 OpenCV 中显示为蓝色3. 坐标系统x 是水平方向y 是垂直方向OpenCV 使用笛卡尔坐标系但原点在左上角。坐标表示为(x, y)其中x是水平方向从左到右y是垂直方向从上到下。这与数学中常见的(行, 列)或(y, x)顺序不同。# 正确(x, y) 顺序 cv2.circle(img, (100, 200), 30, (0, 255, 0), -1) # 圆心在 x100, y200 处 错误颠倒顺序可能导致图形绘制在画布外 cv2.circle(img, (200, 100), 30, (0, 255, 0), -1) # 如果画布尺寸较小可能超出边界4. cv2.waitKey(0) 在循环中不能填 0在实时交互程序如滑动条调色板中cv2.waitKey()的参数表示等待时间毫秒。如果填 0程序会无限等待用户按键导致画面无法实时刷新。# 正确在循环中使用非零值如 10 毫秒 while True: cv2.imshow(window, img) key cv2.waitKey(10) # 等待 10 毫秒然后继续循环 if key ord(q): break 错误在循环中填 0画面会卡住不动 while True: cv2.imshow(window, img) key cv2.waitKey(0) # 程序停在这里直到用户按键 if key ord(q): break5. 滑动条回调函数不能省略或删除cv2.createTrackbar()的最后一个参数是回调函数即使不需要执行任何操作也必须传入一个空函数。如果传入None或省略滑动条创建会失败。# 正确定义空回调函数 def nothing(x): pass cv2.createTrackbar(R, window, 0, 255, nothing) 错误省略回调函数参数 cv2.createTrackbar(R, window, 0, 255) # 会报错6. 多边形顶点数组需要外层再加 []cv2.polylines()和cv2.fillPoly()要求顶点数组外层用方括号包裹即使只有一个多边形也要写成[pts]形式。import numpy as np 正确外层加 [] pts np.array([(10, 20), (30, 40), (50, 60)], np.int32) cv2.polylines(img, [pts], True, (255, 0, 0), 2) # 注意 [pts] cv2.fillPoly(img, [pts], (0, 255, 0)) # 同样需要 [pts] 错误直接传入 pts cv2.polylines(img, pts, True, (255, 0, 0), 2) # 会报错7. cv2.putText 原生不支持中文OpenCV 的cv2.putText函数默认只支持 ASCII 字符集直接写入中文字符会显示为乱码或方块。这是因为 OpenCV 底层使用的字体库不包含中文字形。解决方案使用 PIL (Pillow) 库配合 OpenCV先用 PIL 绘制中文文字到图像再转换为 OpenCV 格式使用支持中文的字体文件如微软雅黑、宋体等import cv2 import numpy as np from PIL import Image, ImageDraw, ImageFont 创建空白画布 img np.zeros((200, 400, 3), dtypenp.uint8) img.fill(255) # 白色背景 转换为 PIL 图像 img_pil Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) draw ImageDraw.Draw(img_pil) 加载中文字体需要指定字体文件路径 font ImageFont.truetype(msyh.ttc, 20) # 微软雅黑字体 绘制中文 draw.text((50, 50), 你好OpenCV, fontfont, fill(0, 0, 255)) 转换回 OpenCV 格式 img_cv cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR) cv2.imshow(Chinese Text, img_cv) cv2.waitKey(0) cv2.destroyAllWindows()8. 椭圆角度单位是角度制不是弧度cv2.ellipse函数的angle参数旋转角度使用的是角度制而不是弧度制。很多初学者误以为和数学中的弧度制相同导致椭圆方向错误。关键点angle椭圆绕中心点顺时针旋转的角度单位是度0-360startAngle和endAngle椭圆弧的起始和结束角度同样是度为单位0 度指向水平向右x 轴正方向import cv2 import numpy as np img np.zeros((400, 400, 3), dtypenp.uint8) 绘制一个旋转45度的椭圆 angle45 表示顺时针旋转45度0度指向水平向右 cv2.ellipse(img, (200, 200), (100, 50), 45, 0, 360, (0, 255, 0), 2) 绘制参考线水平向右的红色箭头 cv2.arrowedLine(img, (200, 200), (300, 200), (0, 0, 255), 2) cv2.imshow(Ellipse Angle Demo, img) cv2.waitKey(0) cv2.destroyAllWindows()9. cv2.polylines 不会填充多边形cv2.polylines函数只绘制多边形的轮廓不会填充内部。很多新手误以为通过设置thickness参数或闭合标志就能实现填充实际上必须单独调用cv2.fillPoly函数。正确用法cv2.polylines绘制多边形轮廓边框cv2.fillPoly填充多边形内部可以同时使用两个函数实现带边框的填充多边形import cv2 import numpy as np img np.zeros((400, 400, 3), dtypenp.uint8) 定义三角形顶点 pts np.array([(100, 100), (300, 100), (200, 300)], np.int32) 错误以为 polylines 能填充 cv2.polylines(img, [pts], True, (0, 255, 0), -1) # -1 不会填充 正确先填充内部再绘制边框 cv2.fillPoly(img, [pts], (0, 255, 0)) # 绿色填充 cv2.polylines(img, [pts], True, (0, 0, 255), 3) # 红色边框线宽3 cv2.imshow(Polygon Fill Demo, img) cv2.waitKey(0) cv2.destroyAllWindows()总结掌握这 9 个高频踩坑点能帮你节省大量调试时间。记住画布尺寸是高, 宽、颜色用 BGR 顺序、坐标是 (x, y)、循环中waitKey不能填 0、滑动条回调不能省、多边形顶点要加 []、中文显示需额外处理、椭圆角度用度不用弧度、多边形填充必须用fillPoly。十一、本章小结本章我们从一张空白画布出发系统掌握了 OpenCV 绘图的核心 API直线、矩形、圆形、椭圆、多边形以及画布文字写入最后通过 RGB 动态调色滑块把绘图与交互结合起来。回顾一下画布本质是np.zeros创建的像素矩阵尺寸顺序是高, 宽, 通道数颜色一律使用 BGR 顺序坐标是 (x, y)原点在左上角。绘制时thickness-1表示填充椭圆角度用角度制多边形顶点要加[]cv2.putText原生不支持中文循环里waitKey不能填 0滑动条回调不能省略填充多边形必须用fillPoly。这些细节看似琐碎却是写出稳定绘图程序的关键。学会了在画布上绘制各种图形下一步就是让画面真正“动”起来。下一章我们将进入 OpenCV 的视频处理与实时视觉应用从摄像头视频流的读取与保存到帧率控制、画面翻转与多窗口显示一步步搭建属于你自己的实时视觉小工具。