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

好,咱们正式开始动手了。

这一章,我会带你过一遍 OpenCV 最核心的几个基础操作。说白了,就是那些你以后写每个视觉程序都会用到的“肌肉记忆”。我个人习惯是,拿到一个新环境,先跑一遍这些代码,确认摄像头、读写路径都没问题,心里才踏实。

2.1 图像读取与显示

先来最简单的——读一张图片,然后把它显示出来。

import cv2

# 读取图像
img = cv2.imread('test.jpg')

# 显示图像
cv2.imshow('My Window', img)

# 等待按键
cv2.waitKey(0)

# 关闭所有窗口
cv2.destroyAllWindows()

嗯,这里要注意几个坑。

第一,路径问题。 我刚开始学的时候,经常图片读不出来,程序也不报错,就是显示个 None。后来才发现,要么是路径写错了,要么是文件名里有中文。OpenCV 的 imread 对中文路径支持不太好,我建议你养成习惯,路径里只用英文和数字。

第二,imread 的第二个参数。 默认是 cv2.IMREAD_COLOR,也就是彩色图。如果你想要灰度图,可以传 cv2.IMREAD_GRAYSCALE。我在项目中遇到过,有人读灰度图忘了加参数,结果后面做二值化时发现通道数不对,排查了半天。

小技巧:img.shape 查看图像的尺寸和通道数。彩色图返回 (高, 宽, 3),灰度图返回 (高, 宽)。

2.2 视频捕获与保存

视频处理,说白了就是快速处理一帧一帧的图片。

捕获摄像头视频:

cap = cv2.VideoCapture(0)  # 0 代表默认摄像头

while True:
    ret, frame = cap.read()
    if not ret:
        break
    
    cv2.imshow('Camera', frame)
    
    # 按 q 键退出
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

这里有个细节:waitKey(1) 里的参数是毫秒。1 毫秒意味着每帧只等 1ms,这样视频才能流畅播放。如果你设成 0,那就卡死了,只能显示第一帧。

保存视频:

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

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

out.release()
我曾经踩过的坑: fourcc 编码格式选不对,保存的视频打不开。Windows 上推荐 'XVID' 或 'MJPG',macOS 上推荐 'mp4v'。另外,写入的尺寸必须和帧的尺寸一致,否则会报错。

2.3 色彩空间转换

为什么需要转换色彩空间?你想想看,在 RGB 空间里,颜色受光照影响很大。但换成 HSV 空间,色调(H)基本不受光照影响,这就方便做颜色识别了。

常用的转换:

# BGR 转灰度
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# BGR 转 HSV
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

# BGR 转 RGB(matplotlib 显示用)
rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

注意,OpenCV 默认是 BGR 顺序,不是 RGB。我刚开始用 matplotlib 显示图像时,发现颜色全不对,红蓝颠倒。后来才反应过来,得先转一下。

转换类型 OpenCV 常量 常见用途
BGR → 灰度 COLOR_BGR2GRAY 边缘检测、二值化
BGR → HSV COLOR_BGR2HSV 颜色识别、物体跟踪
BGR → RGB COLOR_BGR2RGB matplotlib 显示

2.4 图像缩放与裁剪

这两个操作,在 YOLO 预处理中会频繁用到。

缩放:

# 指定目标尺寸
resized = cv2.resize(img, (416, 416))

# 按比例缩放
scale_percent = 50  # 缩小到 50%
width = int(img.shape[1] * scale_percent / 100)
height = int(img.shape[0] * scale_percent / 100)
resized = cv2.resize(img, (width, height))

我个人习惯用 cv2.INTER_AREA 做缩小,用 cv2.INTER_LINEAR 做放大。效果会好一些。

裁剪:

# 裁剪 ROI 区域 [y1:y2, x1:x2]
roi = img[100:300, 200:400]

裁剪其实就是 NumPy 的切片操作。嗯,这里要注意,坐标顺序是先高后宽,也就是先 y 后 x。我刚开始总搞反,裁出来的图完全不对。

核心总结: 图像读取用 imread,视频捕获用 VideoCapture,色彩转换用 cvtColor,缩放用 resize,裁剪用切片。这五个操作,你练熟了,后面学 YOLO 就轻松多了。

好了,这一章的内容就这些。下一章我们会讲图像预处理,包括滤波、边缘检测、形态学操作,这些都是 YOLO 训练前的重要步骤。到时候见。