3、OpenCV基础操作(一):图像的读取、显示、保存与属性

好,咱们正式开始动手写代码了。这一章的内容,说白了就是OpenCV的"Hello World"——图像的读取、显示、保存,外加几个最常用的属性查看。别小看这几步,我见过不少新手在这上面翻车,尤其是路径和颜色通道的问题。

我个人习惯,每开始一个新项目,第一件事就是先跑通图像的读写流程。这就像盖房子先打地基,地基稳了,后面做检测、训练模型才踏实。

本章核心知识点速览

  • 读取图像:cv2.imread() 的三种模式
  • 显示图像:cv2.imshow() + 窗口管理
  • 保存图像:cv2.imwrite() 的格式与质量
  • 图像属性:shape、dtype、size 的含义与用途
OpenCV 图像基础操作知识结构 图像基础操作 读取 imread() 显示 imshow() 保存 imwrite() 属性查看 彩色/灰度/不变 窗口/按键/销毁 格式/质量/路径 shape/dtype/size ⚠️ 注意BGR与RGB顺序

3.1 读取图像:cv2.imread()

读取图像是第一步。OpenCV 用 cv2.imread() 这个函数,传入文件路径就行。但这里有个坑——颜色通道顺序是 BGR,不是 RGB。我第一次用 OpenCV 显示图片时,发现颜色偏蓝,查了半天才发现是通道顺序搞反了。

import cv2

# 彩色模式读取(默认)
img_color = cv2.imread('cat.jpg', cv2.IMREAD_COLOR)

# 灰度模式读取
img_gray = cv2.imread('cat.jpg', cv2.IMREAD_GRAYSCALE)

# 原样读取(包含alpha通道等)
img_unchanged = cv2.imread('cat.jpg', cv2.IMREAD_UNCHANGED)
标志 数值 说明
cv2.IMREAD_COLOR 1 默认值,加载彩色图像,忽略透明度
cv2.IMREAD_GRAYSCALE 0 以灰度模式加载,单通道
cv2.IMREAD_UNCHANGED -1 包含alpha通道,原样加载

路径问题要小心

我曾经因为路径里带了中文,结果图像读不出来,排查了半天。OpenCV 的 imread 不支持中文路径,建议全部用英文路径。如果图像读出来是 None,先检查路径对不对。

3.2 显示图像:cv2.imshow()

读进来之后,总得看一眼吧?cv2.imshow() 负责把图像显示在窗口中。配合 cv2.waitKey() 和 cv2.destroyAllWindows() 一起用,才能正常关闭窗口。

cv2.imshow('My Image', img_color)  # 第一个参数是窗口名
cv2.waitKey(0)                      # 等待按键,0表示无限等待
cv2.destroyAllWindows()             # 关闭所有窗口

你想想看,如果不加 waitKey(),窗口会一闪而过,根本看不到。我个人习惯用 waitKey(0),按任意键再关闭,调试时很方便。

小技巧

如果想按特定键退出,可以判断返回值:

if cv2.waitKey(0) == ord('q'):
    cv2.destroyAllWindows()

这样按 'q' 键才会关闭窗口,其他键没反应。

3.3 保存图像:cv2.imwrite()

处理完图像,得保存下来。cv2.imwrite() 根据文件扩展名自动选择保存格式。支持 .jpg、.png、.bmp 等常见格式。

# 保存为PNG
cv2.imwrite('output.png', img_color)

# 保存为JPEG,指定质量(0-100)
cv2.imwrite('output.jpg', img_color, [cv2.IMWRITE_JPEG_QUALITY, 95])

# 保存为PNG,指定压缩级别(0-9)
cv2.imwrite('output.png', img_color, [cv2.IMWRITE_PNG_COMPRESSION, 3])
格式 参数 说明
JPEG cv2.IMWRITE_JPEG_QUALITY 质量值 0-100,默认 95,值越高文件越大
PNG cv2.IMWRITE_PNG_COMPRESSION 压缩级别 0-9,默认 3,值越高文件越小
WebP cv2.IMWRITE_WEBP_QUALITY 质量值 0-100,适合网络传输

保存路径同样不支持中文

和读取一样,保存路径也最好用英文。如果保存失败,返回 False,记得检查返回值。

3.4 图像属性:shape、dtype、size

图像读进来之后,我们得知道它长什么样。三个最常用的属性:shape、dtype、size。

print('图像形状:', img_color.shape)   # (高度, 宽度, 通道数)
print('数据类型:', img_color.dtype)   # uint8
print('像素总数:', img_color.size)    # 高 * 宽 * 通道数

举个例子,一张 640x480 的彩色图像:

  • shape 返回 (480, 640, 3) —— 注意顺序是 高、宽、通道
  • dtype 返回 uint8 —— 每个像素值范围 0-255
  • size 返回 921600 —— 480 * 640 * 3

为什么 shape 是 (高, 宽, 通道)?

OpenCV 用 NumPy 数组存储图像,而 NumPy 数组的第一个维度是行(高度),第二个维度是列(宽度)。所以 shape 的顺序是 (height, width, channels)。刚开始容易搞反,我建议你每次读图后都打印一下 shape 确认。

3.5 完整示例:读取→显示→查看属性→保存

把上面所有操作串起来,写一个完整的流程:

import cv2

# 1. 读取图像
img = cv2.imread('cat.jpg')
if img is None:
    print('图像读取失败,请检查路径')
    exit()

# 2. 查看属性
print('shape:', img.shape)
print('dtype:', img.dtype)
print('size:', img.size)

# 3. 显示图像
cv2.imshow('Cat Image', img)
cv2.waitKey(0)

# 4. 保存灰度版本
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imwrite('cat_gray.jpg', img_gray)

cv2.destroyAllWindows()

嗯,这里要注意:cv2.cvtColor() 是颜色空间转换函数,后面章节会详细讲。这里只是演示一下保存处理后的结果。

调试小习惯

我每次写图像处理代码,都会先打印 shape 和 dtype,确认数据没问题再往下走。这能省掉很多莫名其妙的 bug。

3.6 常见问题与避坑

  • 图像读出来是 None:路径不对、文件名有中文、文件损坏。先检查文件是否存在。
  • 颜色不对:OpenCV 是 BGR 顺序,用 matplotlib 显示时记得转换:cv2.cvtColor(img, cv2.COLOR_BGR2RGB)。
  • 窗口卡死:忘了加 waitKey() 或者 destroyAllWindows()。
  • 保存失败:路径无写入权限、磁盘空间不足、扩展名不支持。

好了,这一章的内容就这些。图像读取、显示、保存、属性查看,这四个操作是后续所有图像处理的基础。你可以在自己的电脑上找一张图片,把上面的代码跑一遍,感受一下 OpenCV 的工作方式。