2、读取与显示图像:使用OpenCV读取图片,显示检测结果的基础窗口
好,咱们正式开始动手了。
上一章我们聊了YOLO检测的整体流程,说白了就是「模型推理 + 结果可视化」这两步。那第一步是什么?你得先把图片读进来吧?
这一章我就带你搞定最基础的操作——用OpenCV读取一张图片,然后把它显示在屏幕上。别小看这一步,我在项目里见过太多人栽在「图片读不出来」或者「显示窗口卡死」这种小坑上。
2.1 为什么选择OpenCV?
你可能会问:Python里能读图片的库多了去了,PIL、matplotlib、skimage……为什么我偏偏推荐OpenCV?
原因有三:
- 速度快:OpenCV底层是C++写的,处理图像效率极高。YOLO检测本身就很吃性能,读取环节不能拖后腿。
- 格式统一:OpenCV读进来的图像默认是NumPy数组,形状是 (height, width, channels),通道顺序是BGR。这个格式跟YOLO的输入要求天然匹配。
- 生态成熟:后续画框、写文字、做视频流,全都能用OpenCV一条龙搞定。你想想看,何必再引入一堆库互相转换?
核心认知:OpenCV读取的图像是BGR格式,不是RGB。这一点非常重要,后面画框时颜色会受影响。
2.2 读取图片:cv2.imread()
用法极其简单,一行代码的事:
import cv2
# 读取图片
img = cv2.imread('dog.jpg')
# 检查是否读取成功
if img is None:
print("图片读取失败,请检查路径")
else:
print(f"图片尺寸:{img.shape}")
嗯,这里要注意:cv2.imread() 如果读取失败,不会抛异常,而是返回 None。我刚开始用的时候就被这个坑过——代码没报错,但后面处理全崩了。所以一定要加判空检查。
imread() 还有第二个参数,控制读取方式:
| 参数值 | 含义 | 适用场景 |
|---|---|---|
cv2.IMREAD_COLOR (默认) |
加载彩色图像,忽略透明度 | 绝大多数YOLO检测场景 |
cv2.IMREAD_GRAYSCALE |
加载为灰度图 | 某些预处理或轻量模型 |
cv2.IMREAD_UNCHANGED |
加载所有通道(含Alpha) | 需要透明通道时 |
我个人习惯直接用默认值,除非有特殊需求。YOLO模型输入一般都是三通道彩色图,没必要折腾。
2.3 显示图像:cv2.imshow()
读进来之后,总得看一眼吧?用 imshow() 开个窗口:
cv2.imshow('YOLO Detection Result', img)
cv2.waitKey(0) # 等待按键
cv2.destroyAllWindows()
这里有个关键点:waitKey(0) 表示无限等待,直到你按下任意键。如果不加这一行,窗口会一闪而过,你根本看不到图片。
避坑指南:我曾经在Jupyter Notebook里直接跑 imshow(),结果窗口卡死,内核都重启了。后来才发现,OpenCV的GUI窗口不能在Notebook的交互环境里正常运作。解决办法有两个:要么用 plt.imshow() 替代,要么把代码写成脚本运行。
waitKey() 的参数还可以传一个毫秒数,比如 waitKey(1000) 表示显示1秒后自动关闭。这在视频流处理中很常用。
2.4 完整示例:读取并显示
把上面几段拼起来,就是一个完整的读取显示流程:
import cv2
# 1. 读取图片
img = cv2.imread('test.jpg')
if img is None:
print("错误:找不到图片文件")
exit()
# 2. 显示图片
cv2.imshow('YOLO Detection - Original Image', img)
# 3. 等待按键
print("按任意键关闭窗口...")
cv2.waitKey(0)
# 4. 清理资源
cv2.destroyAllWindows()
运行这段代码,你会看到一个窗口弹出,里面就是你的图片。窗口标题可以随便起,我一般用「项目名 + 当前操作」来命名,方便调试时区分多个窗口。
2.5 关于窗口的一些小技巧
显示窗口时,OpenCV默认会自适应图片大小。如果图片太大,窗口可能超出屏幕边界。你可以用 cv2.namedWindow() 提前设置窗口属性:
cv2.namedWindow('YOLO Detection', cv2.WINDOW_NORMAL)
cv2.resizeWindow('YOLO Detection', 800, 600)
cv2.imshow('YOLO Detection', img)
WINDOW_NORMAL 允许你手动调整窗口大小,WINDOW_AUTOSIZE 则固定为图片原始尺寸。我个人偏好 WINDOW_NORMAL,因为有时候图片太大,缩放下看着更舒服。
小提示:如果你在调试阶段想同时看原图和检测结果,可以开两个窗口,分别命名。比如 cv2.imshow('Original', img) 和 cv2.imshow('Detection', result)。这样对比着看,效果一目了然。
2.6 常见问题与排查
我总结了几条新手最容易踩的坑:
- 图片路径错误:
imread()不会报错,只返回None。建议用绝对路径,或者用os.path.exists()先检查文件是否存在。 - 窗口无响应:多半是忘了写
waitKey()。记住,imshow()必须配合waitKey()才能正常显示。 - 中文路径乱码:OpenCV 不支持中文路径。解决办法是用
cv2.imdecode()配合np.fromfile()读取。
说到中文路径,我曾经在一个项目里被折腾了半小时。客户给的图片文件名全是中文,直接 imread() 返回 None。后来改用 imdecode 才搞定。代码长这样:
import numpy as np
img_array = np.fromfile('测试图片.jpg', dtype=np.uint8)
img = cv2.imdecode(img_array, cv2.IMREAD_COLOR)
嗯,这个技巧你记一下,说不定哪天就用上了。
2.7 本章小结
这一章的内容其实很简单,但它是整个可视化调试流程的基石。你想想看,如果连图片都读不进来、显示不出来,后面画框、标置信度全都无从谈起。
核心就三件事:
- 用
cv2.imread()读取图片,记得判空 - 用
cv2.imshow()+waitKey()显示窗口 - 注意BGR通道顺序,以及中文路径的兼容处理
下一章,我们会在读取图片的基础上,开始画检测框——也就是把YOLO输出的坐标信息可视化到图像上。那才是真正「看得见」的检测结果。