2. OpenCV 基础操作:图像读取与显示、视频捕获与保存、色彩空间转换、图像缩放与裁剪

好,咱们正式开始动手。这一章全是基本功,但也是我平时用得最频繁的操作。说白了,你后面做目标检测、跟踪,每一步都离不开这些基础操作。我个人习惯是把它们练成肌肉记忆,这样写代码时才不会卡壳。

2.1 图像读取与显示

OpenCV 读取图像用 cv2.imread(),显示用 cv2.imshow()。听起来简单,但有几个坑我一开始也踩过。

核心函数速查

  • cv2.imread(path, flag) — 读取图像,flag 控制颜色通道
  • cv2.imshow(winname, img) — 显示图像窗口
  • cv2.waitKey(delay) — 等待键盘输入,单位毫秒
  • cv2.destroyAllWindows() — 关闭所有窗口
import cv2

# 读取图像 — 默认是彩色 BGR 格式
img = cv2.imread('cat.jpg')
print(img.shape)   # (高度, 宽度, 通道数)

# 显示图像
cv2.imshow('My Cat', img)
cv2.waitKey(0)      # 0 表示无限等待,按任意键继续
cv2.destroyAllWindows()

我曾经犯过的错: 路径里有中文或空格,imread 返回 None,但程序不报错。你后面用 img.shape 直接崩。所以读取后一定要加一句 if img is None 的判断。

2.2 视频捕获与保存

视频其实就是一帧一帧的图像。OpenCV 用 VideoCapture 读视频或摄像头,用 VideoWriter 写视频。

2.2.1 读取摄像头或视频文件

cap = cv2.VideoCapture(0)          # 0 表示默认摄像头
# cap = cv2.VideoCapture('video.mp4')  # 或者读视频文件

while True:
    ret, frame = cap.read()
    if not ret:
        break
    cv2.imshow('Frame', frame)
    if cv2.waitKey(25) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

这里有个细节:waitKey(25) 里的 25 毫秒,对应大约 40 FPS。你想想看,如果视频是 30 FPS,你设成 10 毫秒,播放速度就变快了。我在做实时检测时,经常根据实际帧率动态调整这个值。

2.2.2 保存视频

保存视频需要指定编码器。我常用的组合是 cv2.VideoWriter_fourcc(*'mp4v') 输出 MP4 文件。

fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter('output.mp4', fourcc, 20.0, (640, 480))

while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        break
    out.write(frame)   # 写入每一帧

out.release()

小技巧: 如果你保存的视频打不开,八成是编码器问题。试试把 'mp4v' 换成 'XVID',文件后缀改成 .avi。我在 Windows 上遇到过好几次这种兼容性问题。

2.3 色彩空间转换

OpenCV 默认读进来的图像是 BGR 格式,不是我们熟悉的 RGB。这一点太容易搞混了。我记得第一次用 Matplotlib 显示 OpenCV 图像,颜色全不对,找了半天 bug。

色彩空间 特点 常用场景
BGR OpenCV 默认格式,通道顺序 B→G→R 图像读写、显示
RGB 人眼习惯的通道顺序 R→G→B Matplotlib 显示、网页应用
HSV 色调(H)、饱和度(S)、明度(V) 颜色分割、物体跟踪
GRAY 单通道灰度图 特征检测、降维处理
# BGR → RGB
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)

# BGR → HSV
img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)

# BGR → GRAY
img_gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)

为什么 HSV 在目标跟踪里这么重要?

因为 HSV 把颜色信息(色调)和亮度信息(明度)分开了。你在做颜色检测时,光照变化会影响 BGR 值,但对 HSV 的 H 通道影响小很多。我做过一个红色小球跟踪项目,用 BGR 阈值调了半天,换成 HSV 十分钟搞定。

2.4 图像缩放与裁剪

缩放用 cv2.resize(),裁剪用 NumPy 的切片操作。这两个操作在预处理阶段几乎必用。

2.4.1 缩放

# 指定目标尺寸
img_resized = cv2.resize(img, (300, 200))

# 按比例缩放 — 我更喜欢这种方式,不会变形
h, w = img.shape[:2]
scale = 0.5
img_half = cv2.resize(img, (int(w * scale), int(h * scale)))

# 插值方法的选择
# cv2.INTER_LINEAR — 默认,适合放大
# cv2.INTER_AREA — 适合缩小,能减少锯齿
img_shrink = cv2.resize(img, (100, 100), interpolation=cv2.INTER_AREA)

我的经验: 缩小图像用 INTER_AREA,放大用 INTER_LINEAR 或 INTER_CUBIC。如果你追求速度(比如实时视频),INTER_LINEAR 是最稳妥的选择。

2.4.2 裁剪

裁剪其实就是数组切片。OpenCV 的图像是 NumPy 数组,所以直接切就行。

# 裁剪 ROI(感兴趣区域)
# 语法:img[y_start:y_end, x_start:x_end]
roi = img[100:300, 200:400]   # 高度从 100 到 300,宽度从 200 到 400

cv2.imshow('ROI', roi)

嗯,这里要注意:切片顺序是 行(高度)在前,列(宽度)在后。我刚开始总写成 [x1:x2, y1:y2],结果图像是歪的。你记住 img[y, x] 这个顺序就不会错。

2.5 本章知识体系

下面这张图把本章的核心操作串起来了。你可以把它当作一个快速参考。

OpenCV 基础操作知识体系 OpenCV 基础操作 图像读取与显示 视频捕获与保存 色彩空间转换 缩放与裁剪 imread() imshow() waitKey() VideoCapture VideoWriter fourcc 编码 BGR ↔ RGB BGR ↔ HSV BGR ↔ GRAY resize() 切片裁剪 ROI 插值方法 💡 学习建议 • 每个函数都动手敲一遍,不要复制粘贴 • 试试不同的插值方法,观察缩放效果差异 • 用摄像头实时捕获,再保存成视频文件,走通全流程

这一章的内容就这些。别觉得简单就跳过,我建议你打开 IDE,把每个例子都跑一遍。尤其是色彩空间转换和视频读写,后面做 YOLO 检测时几乎每一帧都要用到。等你把这些操作练熟了,咱们再往下走。