第二章 OpenCV基础(一):图像读取与显示、图像属性、色彩空间转换、图像保存
好,咱们正式开始动手了。
OpenCV 就像一把瑞士军刀,功能很全。但再厉害的刀,也得先学会怎么拿、怎么看、怎么放回去。这一章,我们就搞定图像最基本的四个操作:读、看、改、存。
别小看这些基础。我见过不少新手,上来就调模型,结果图像路径写错了、色彩空间搞混了,折腾半天。基础打牢,后面才稳。
2.1 图像读取:imread() 的玄机
读取图像,用的是 cv2.imread()。语法很简单:
import cv2
# 读取图像
img = cv2.imread('cat.jpg')
嗯,这里要注意。OpenCV 默认读取的是 BGR 格式,不是我们常见的 RGB。这一点特别容易踩坑。
imread() 还有第二个参数,控制读取方式:
| 参数值 | 含义 | 常用场景 |
|---|---|---|
cv2.IMREAD_COLOR (1) |
彩色图像,忽略透明度 | 默认值,日常使用 |
cv2.IMREAD_GRAYSCALE (0) |
灰度图像 | 减少计算量,很多检测算法输入 |
cv2.IMREAD_UNCHANGED (-1) |
包含 Alpha 通道 | 处理 PNG 透明图 |
我个人习惯,做 YOLO 检测时,如果不需要颜色信息,直接读成灰度图。速度能快不少。
2.2 图像显示:imshow() 与窗口管理
读进来,总得看一眼吧?用 cv2.imshow()。
cv2.imshow('窗口标题', img)
cv2.waitKey(0) # 等待按键
cv2.destroyAllWindows()
这里有个关键点:waitKey() 不能省。它有两个作用:
- 保持窗口显示,直到你按键盘
- 返回按键的 ASCII 码,可以用来做交互
cv2.waitKey(3000),表示等待 3 秒后自动关闭。我调试时经常用这个,省得一直按键盘。
另外,destroyAllWindows() 是关闭所有窗口。如果你只关一个,用 cv2.destroyWindow('窗口标题')。
2.3 图像属性:shape、dtype、size
图像在 OpenCV 里其实就是一个 NumPy 数组。所以它的属性,就是数组的属性。
print(img.shape) # (高度, 宽度, 通道数)
print(img.dtype) # uint8
print(img.size) # 总像素数 = 高 × 宽 × 通道数
举个例子:一张 640×480 的彩色图,shape 返回 (480, 640, 3)。size 就是 480×640×3 = 921600。
为什么是 uint8?因为每个像素值范围是 0-255,刚好 8 位无符号整数。这个后面做图像处理时很重要——你如果做加减法,一不小心就会溢出。
2.4 色彩空间转换:BGR ↔ RGB ↔ 灰度
这是本章的重头戏。色彩空间转换用 cv2.cvtColor()。
2.4.1 BGR 转 RGB
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
为什么转?因为 matplotlib、PIL 这些库用的是 RGB。你不转,显示出来就是蓝汪汪一片。
2.4.2 BGR 转灰度
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
灰度图只有一个通道,shape 变成 (高, 宽)。YOLO 检测时,很多轻量模型输入就是灰度图,能省三分之一的计算量。
2.4.3 其他常见转换
| 转换代码 | 说明 | 应用场景 |
|---|---|---|
COLOR_BGR2HSV |
BGR → HSV | 颜色分割、物体跟踪 |
COLOR_BGR2LAB |
BGR → Lab | 颜色距离计算 |
COLOR_BGR2YUV |
BGR → YUV | 视频编码、YOLO 输入 |
我个人在项目中用得最多的是 BGR2RGB 和 BGR2GRAY。HSV 在做颜色过滤时很管用,比如提取红色区域。
cvtColor,结果帧率掉到 10 帧以下。后来发现,每帧只转一次,而且尽量用灰度图,性能提升很明显。
2.5 图像保存:imwrite()
处理完了,得存下来。用 cv2.imwrite()。
cv2.imwrite('output.jpg', img)
它支持多种格式:jpg、png、bmp、tiff 等。保存时还可以指定参数:
# 保存为高质量 JPEG
cv2.imwrite('output.jpg', img, [cv2.IMWRITE_JPEG_QUALITY, 95])
# 保存为 PNG 压缩级别
cv2.imwrite('output.png', img, [cv2.IMWRITE_PNG_COMPRESSION, 3])
JPEG 质量范围是 0-100,默认 95。PNG 压缩级别是 0-9,0 表示不压缩,9 表示最大压缩。我一般用 3,平衡速度和大小。
2.6 本章知识结构图
下面这张图,把本章的核心流程串起来了:
2.7 完整示例:一条龙操作
把上面所有知识点串起来,写一个完整的例子:
import cv2
# 1. 读取图像
img = cv2.imread('cat.jpg', cv2.IMREAD_COLOR)
# 2. 查看属性
print(f"图像尺寸: {img.shape}")
print(f"数据类型: {img.dtype}")
print(f"总像素数: {img.size}")
# 3. 转灰度
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 4. 显示原图和灰度图
cv2.imshow('Original', img)
cv2.imshow('Gray', gray)
# 5. 等待按键后保存
key = cv2.waitKey(0)
if key == ord('s'): # 按 s 键保存
cv2.imwrite('gray_cat.jpg', gray)
print("保存成功!")
else:
print("未保存")
cv2.destroyAllWindows()
这个例子,你跑一遍,基本就掌握了本章所有内容。我建议你换几张自己的图片试试,感受一下不同格式、不同尺寸的差异。
- imread() 默认 BGR,不是 RGB
- 图像本质是 NumPy 数组,shape 是 (高, 宽, 通道)
- cvtColor() 是色彩空间转换的唯一入口
- imwrite() 保存时注意格式和质量参数
- 灰度图能显著提升处理速度