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()
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。我刚开始总搞反,裁出来的图完全不对。
好了,这一章的内容就这些。下一章我们会讲图像预处理,包括滤波、边缘检测、形态学操作,这些都是 YOLO 训练前的重要步骤。到时候见。