OpenCV 从零学习 · 第 1 讲:图像的读取、显示与保存
Python OpenCV 从零到精通 · 函数:cv2.imread / cv2.imshow / cv2.imwrite
本讲介绍 OpenCV 处理图像最基础的三个函数:cv2.imread 读取、cv2.imshow 显示、cv2.imwrite 保存,逐一说明它们的参数、返回值与常见注意事项。在 OpenCV 中,所有图像都以 NumPy 数组形式存在,这一点贯穿后续全部内容。
0. 环境准备
pip install opencv-python
import cv2
print(cv2.__version__) # 例如 4.9.0
| 包名 | opencv-python(核心功能);需要 SIFT/SURF 等扩展模块时用 opencv-contrib-python。注意 PyPI 上的 opencv 是无关废弃包,不要装错。 |
| 依赖 | numpy 会随包自动安装,图像读写、运算都基于它。 |
1. cv2.imread — 读取图像
函数签名
cv2.imread(filename, flags=cv2.IMREAD_COLOR) -> ndarray | None
| 参数 | 类型 | 含义 |
filename |
str | 图像文件路径 |
flags |
int | 读取模式,决定通道数与色彩,见下表 |
flags 常用取值
| 取值 | 值 | 说明 |
IMREAD_COLOR |
1 | 彩色,3 通道 BGR,忽略透明通道(默认) |
IMREAD_GRAYSCALE |
0 | 单通道灰度图 |
IMREAD_UNCHANGED |
-1 | 原样读入,保留 alpha 透明通道 |
返回值:成功返回 ndarray,形状为 (高度, 宽度, 通道数);失败(路径错误、文件损坏)时返回 None,且不抛异常。
import cv2
img = cv2.imread("photo.jpg")
if img is None: # 必须判空,否则后续对 None 操作会抛 'NoneType' 错误
raise FileNotFoundError("图片读取失败,检查路径")
print(img.shape) # (高度, 宽度, 通道数),例如 (480, 640, 3)
注意
img.shape 的顺序是 (高, 宽, 通道),与日常"宽 × 高"的直觉相反;做坐标、裁剪运算时要对齐,避免把行列搞反。
2. cv2.imshow / cv2.waitKey / cv2.destroyAllWindows — 显示图像
函数签名
cv2.imshow(winname, mat) -> None
cv2.waitKey(delay=0) -> int
cv2.destroyAllWindows() -> None
| 参数 | 类型 | 含义 |
winname |
str | 窗口名;同名窗口会被复用 / 覆盖 |
mat |
ndarray | 要显示的图像(BGR 顺序) |
delay |
int | 等待毫秒数;0 = 无限等待按键,>0 = 等待该毫秒数(常用于视频逐帧) |
返回值:waitKey 返回按下的键的 ASCII 码(int),超时未按键返回 -1。
cv2.imshow("demo", img)
key = cv2.waitKey(0) # 0:无限等待,按任意键继续
cv2.destroyAllWindows() # 关闭所有窗口;也可用 cv2.destroyWindow("demo") 关指定窗口
注意
imshow 之后必须调用 waitKey 窗口才会渲染——它同时驱动 GUI 事件循环;不调用窗口会一闪而过或空白。即便不想等待,也至少要 waitKey(1) 配一个短暂延时。
3. 颜色通道顺序:OpenCV 用 BGR,不是 RGB
OpenCV 载入的彩色图像通道顺序是 BGR(蓝-绿-红),而非多数库(PIL、matplotlib)使用的 RGB。若直接把 OpenCV 图像交给以 RGB 解读的库显示,会出现红蓝互换。
函数签名
cv2.cvtColor(src, code[, dst]) -> ndarray
| 参数 | 含义 |
src |
输入图像 |
code |
颜色空间转换码,见下表 |
常用转换码
| code | 作用 |
COLOR_BGR2RGB |
BGR → RGB(给 matplotlib / 人眼查看用) |
COLOR_BGR2GRAY |
BGR → 灰度 |
COLOR_BGR2HSV |
BGR → HSV(后续色彩分割常用) |
import matplotlib.pyplot as plt
rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 转成 RGB 再交给 matplotlib
plt.imshow(rgb)
plt.show()
注意
OpenCV 内部处理全程使用 BGR,仅在"用其他库显示或导出给人看"时才转 RGB;算法处理阶段不必反复转换,转来转去反而容易出错。
OpenCV 内部处理全程使用 BGR,仅在"用其他库显示或导出给人看"时才转 RGB;算法处理阶段不必反复转换,转来转去反而容易出错。
4. cv2.imwrite — 保存图像
函数签名
cv2.imwrite(filename, img[, params]) -> bool
| 参数 | 类型 | 含义 |
filename |
str | 保存路径,扩展名决定格式(.jpg / .png 等) |
img |
ndarray | 要保存的图像(BGR,直接存,无需转 RGB) |
params |
list | 可选,格式相关参数,如 JPEG 质量 [int(cv2.IMWRITE_JPEG_QUALITY), 95] |
返回值:保存成功返回 True,失败返回 False。
ok = cv2.imwrite("out.jpg", img) # 直接存 BGR
ok = cv2.imwrite("out.jpg", img, [int(cv2.IMWRITE_JPEG_QUALITY), 95])
5. 中文路径的处理
cv2.imread 对含中文的路径在部分环境下会返回 None。改用 NumPy 读取文件字节、再经 cv2.imdecode 解码可规避。
函数签名
cv2.imdecode(buf, flags) -> ndarray | None
| 参数 | 类型 | 含义 |
buf |
ndarray | 图像字节的一维 uint8 数组(由 np.fromfile 读取) |
flags |
int | 同 imread 的读取模式 |
import numpy as np
def imread_zh(path):
buf = np.fromfile(path, dtype=np.uint8) # 按字节读文件,绕开中文路径
img = cv2.imdecode(buf, cv2.IMREAD_COLOR)
if img is None:
raise FileNotFoundError(f"解码失败: {path}")
return img
6. 完整示例
import cv2
# 读取并判空
img = cv2.imread("photo.jpg")
if img is None:
raise SystemExit("读取失败,检查路径")
# 提取灰度图并保存
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imwrite("photo_gray.jpg", gray)
# 显示原图(BGR 直接交给 OpenCV,无需转换)
cv2.imshow("原图", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
print("原图尺寸:", img.shape, "| 灰度图尺寸:", gray.shape)
本讲要点
cv2.imread(path, flags):彩色默认 BGR;失败返回None,务必判空。img.shape顺序为 (高, 宽, 通道)。imshow之后必须waitKey才能渲染窗口。- OpenCV 用 BGR;交给 matplotlib / 人眼查看时用
cvtColor(..., COLOR_BGR2RGB)转换。 - 中文路径用
np.fromfile+cv2.imdecode规避。
