当前位置: 首页 > news >正文

Python在图片上画线:从基础到进阶的实用指南

在日常的编程工作中,我们经常需要对图像进行处理。无论是给图片加水印、标注目标检测的边框,还是简单的图像编辑,“在图片上画线”都是最基础也是最常用的操作之一。

今天,我们就来详细聊聊如何使用 Python 在图片上画线。我们将主要使用两个强大的库:OpenCVPillow (PIL)


一、 准备工作:安装依赖库

在开始之前,请确保你已经安装了必要的库。打开终端(Terminal 或 CMD),运行以下命令:

# 安装 OpenCV (推荐用于计算机视觉任务)pipinstallopencv-python numpy# 安装 Pillow (推荐用于简单的图像处理)pipinstallPillow

二、 核心概念:坐标系与颜色

在画线之前,有两个概念必须搞懂,否则你画出的线可能会“消失”或者颜色不对。

  1. 坐标系
    • 在计算机视觉中,图像的左上角是原点(0, 0)
    • X 轴向右增长,Y 轴向下增长。
    • 坐标格式通常是(x, y)或者(列, 行)
  2. 颜色通道
    • OpenCV使用的是BGR格式(蓝、绿、红),而不是常见的 RGB。
    • Pillow使用的是RGB格式。
    • 颜色值通常是 0-255 的整数元组,例如红色在 OpenCV 中是(0, 0, 255),在 Pillow 中是(255, 0, 0)

三、 方法一:使用 OpenCV (cv2) —— 专业且强大

OpenCV 是计算机视觉领域的行业标准,功能极其丰富。

1. 基础画线:cv2.line()

这是最直接的方法。

importcv2importnumpyasnp# 1. 创建一张黑色的空白图片 (高500, 宽500, 3通道)# 注意:OpenCV 的 shape 顺序是 (高度, 宽度, 通道数)image=np.zeros((500,500,3),dtype=np.uint8)# 2. 定义起点和终点start_point=(50,50)# (x, y)end_point=(450,450)# 3. 定义颜色 (BGR格式:蓝色)color=(255,0,0)# 4. 定义线宽thickness=5# 5. 画线cv2.line(image,start_point,end_point,color,thickness)# 6. 显示图片cv2.imshow("OpenCV Line",image)cv2.waitKey(0)# 等待按键cv2.destroyAllWindows()# 7. 保存图片cv2.imwrite("opencv_line.jpg",image)

2. 进阶玩法

A. 画带箭头的线

OpenCV 甚至提供了现成的箭头函数:

# 在上面的代码基础上替换 cv2.line 为:cv2.arrowedLine(image,(50,100),(450,100),(0,255,0),5,tipLength=0.1)
B. 画虚线/抗锯齿线

cv2.line默认可能会有锯齿。如果要更平滑的线(抗锯齿),可以使用cv2.LINE_AA标志(但在较新版本中,line_type 参数已被整合,通常高分辨率下直接画即可,或者使用更复杂的绘制方法)。

如果你想画虚线,OpenCV 没有直接函数,需要自己写个小逻辑:

defdraw_dashed_line(img,start,end,color,thickness=1,dash_len=10):x1,y1=start x2,y2=end dx,dy=x2-x1,y2-y1 steps=max(abs(dx),abs(dy))//dash_lenifsteps==0:steps=1foriinrange(0,steps,2):# 每隔一段画一段t1=i/steps t2=(i+1)/stepsif(i+1)<stepselse1.0p1=(int(x1+t1*dx),int(y1+t1*dy))p2=(int(x1+t2*dx),int(y1+t2*dy))cv2.line(img,p1,p2,color,thickness)# 使用draw_dashed_line(image,(50,200),(450,200),(0,255,255),3)
C. 画半透明线

OpenCV 画半透明线稍微麻烦一点,需要使用cv2.addWeighted进行图像混合:

overlay=image.copy()cv2.line(overlay,(50,300),(450,300),(0,0,255),10)# 红色粗线# 混合原图和覆盖层cv2.addWeighted(overlay,0.5,image,0.5,0,image)

四、 方法二:使用 Pillow (PIL) —— 轻量且直观

如果你只是做简单的图片编辑(如加水印、画装饰线),Pillow 的 API 更加 Pythonic,更容易上手。

fromPILimportImage,ImageDraw# 1. 创建一张白色背景的图片img=Image.new('RGB',(500,500),color='white')# 2. 创建一个可以在上面绘制的对象draw=ImageDraw.Draw(img)# 3. 定义坐标 [(x1, y1), (x2, y2)]xy=[50,50,450,450]# 4. 定义颜色 (RGB格式:红色) 和线宽fill_color=(255,0,0)width=5# 5. 画线draw.line(xy,fill=fill_color,width=width)# 也可以连续画多条线段draw.line([(50,100),(200,100),(200,200),(350,200)],fill='blue',width=3,joint='curve')# 6. 显示图片 (会调用系统默认图片查看器)img.show()# 7. 保存img.save("pillow_line.jpg")

Pillow 的优势

  • 坐标可以直接用列表[(x1,y1), (x2,y2)],也支持连续点。
  • 颜色可以直接用英文单词'red','blue'
  • 支持joint参数让折线拐角处变圆滑。

五、 实战案例:给图片打马赛克(画粗线覆盖)

有时候我们需要遮挡图片中的敏感信息(如车牌、人脸),最简单的方法就是在上面画粗线或者矩形覆盖。

需求:在图片上画一条黑色的粗横线遮挡文字。

importcv2# 读取图片img=cv2.imread("test_image.jpg")# 替换成你的图片路径# 定义遮挡区域的Y坐标范围y_top=100y_bottom=150# 在这个区域内画黑色的粗线(实际上画矩形更合适,但画线也能模拟)# 这里我们用循环画多条线模拟粗线带,或者直接用 rectanglestart_point=(0,y_top)end_point=(img.shape[1],y_bottom)# img.shape[1] 是宽度# 画一个填充的矩形来遮挡cv2.rectangle(img,start_point,end_point,(0,0,0),-1)# -1 表示填充cv2.imshow("Censored",img)cv2.waitKey(0)

六、 总结与建议

特性OpenCV (cv2)Pillow (PIL)
主要用途计算机视觉、视频分析、复杂图像算法基础图像处理、Web后端图片生成、格式转换
画线函数cv2.line()ImageDraw.line()
颜色格式BGR(容易踩坑)RGB(符合直觉)
坐标系(x, y) / (列, 行)(x, y)
性能极高 (C++底层)中等 (Python底层)
易用性稍复杂,参数多非常简单,API友好

我的建议

  • 如果你在做目标检测、人脸识别、视频流处理,请无脑选择OpenCV
  • 如果你只是想给照片加个水印、生成验证码、简单的裁剪缩放Pillow会让你写得更开心。
http://www.jsqmd.com/news/662861/

相关文章:

  • 学Simulink——基于Simulink的感应电机间接转子磁场定向控制​
  • SAP运维实战 - 番号范围缺失引发的NR751错误:从RF_BELEG R100到FBN1的修复之旅
  • 从抛硬币到投资组合:独立随机变量‘可加性’在现实世界中的3个妙用
  • 从哈勃到韦伯:J2000坐标系在太空望远镜观测中的关键作用与实战案例
  • 从.nii文件到发表级配图:我的fMRI脑图(ROI)美化全流程(附Mango调色技巧)
  • 不止于烧录:用J-Flash深度调试你的HC32L110程序(从下载到在线调试全流程)
  • 16. C++17新特性-std::filesystem (文件系统库)
  • 终极Sketch Measure插件教程:如何彻底终结设计开发沟通难题
  • 从RAM到FLASH:DSP28335工程中printf串口打印的两种内存配置实战
  • 保姆级教程:在Ubuntu 20.04上搭建高通Camx源码阅读与调试环境(含Source Insight配置)
  • 如何让AirPods在Windows上获得完整功能体验:AirPodsDesktop全面指南
  • 强化学习论文(A3C)
  • 终极指南:2026 年最值得关注的 10 个 AI Agent Harness Engineering 开源项目
  • STM32 HAL库驱动MAX31855:从SPI配置到负温度精准读取的实战解析
  • 更加现代的Deep Learning接入SLAM的方法
  • Arduino随机数探秘:从random()到randomSeed()的实战指南
  • 20252817 2025-2026-2 《网络攻防实践》实践五报告
  • music21节奏与时长管理:精确控制音乐时间要素
  • 从入门到精通:stress-ng全方位系统压力测试实战指南
  • 2026届最火的六大AI论文神器推荐
  • SCI 1区新范式:基于GADF+SwinTransformer-CBAM+BiLSTM的多模态时序图像诊断模型
  • 从删库到跑路?不,先搞懂Linux文件系统怎么找回你的数据
  • Windows上运行Android应用的3种革命性方法:告别模拟器的时代已来
  • Redis 持久化策略对性能的影响
  • AtCoder Beginner Contest 454 ABCDE 题目解析
  • Spoon连接ClickHouse实战:从驱动缺失到稳定配置的完整指南
  • 避坑指南:libmodbus从机开发中,modbus_receive阻塞与多线程处理的正确姿势
  • mdcat与mdless:如何通过符号链接实现智能分页功能
  • 如何在Zotero中为PDF文档添加可搜索文本层:Zotero-OCR插件完全指南
  • EDUSRC一个文档到十八万条sfz泄露和命令执行