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 本章知识体系
下面这张图把本章的核心操作串起来了。你可以把它当作一个快速参考。
这一章的内容就这些。别觉得简单就跳过,我建议你打开 IDE,把每个例子都跑一遍。尤其是色彩空间转换和视频读写,后面做 YOLO 检测时几乎每一帧都要用到。等你把这些操作练熟了,咱们再往下走。