2、OpenCV基础(一):图像读取与显示、视频捕获与保存、色彩空间转换、图像缩放与裁剪
各位同学,欢迎来到OpenCV实战的第一课。说实话,很多初学者一上来就急着调YOLO模型,结果连图像都读不出来,卡在第一步。我个人习惯是,先把地基打牢——图像和视频的读写操作,这是所有视觉任务的起点。
今天这一章,我们就把OpenCV最核心的四个基础操作讲透。你想想看,无论是做目标检测还是人脸识别,本质上都是在跟像素打交道。掌握了这些,后面的路就好走了。
2.1 图像读取与显示
先聊聊最基础的操作——读图。OpenCV里用 cv2.imread() 这个函数。它有两个参数:文件路径和读取模式。
读取模式有三种常用选项:
cv2.IMREAD_COLOR(默认值):加载彩色图像,忽略透明度通道。说白了就是BGR三通道。cv2.IMREAD_GRAYSCALE:以灰度模式加载,单通道。cv2.IMREAD_UNCHANGED:保留所有通道,包括Alpha通道。
我在项目中遇到过一个问题:用默认模式读了一张PNG图片,结果透明背景变成了黑色。嗯,这里要注意——如果你需要保留透明度,记得用 cv2.IMREAD_UNCHANGED。
import cv2
# 读取彩色图像
img_color = cv2.imread('cat.jpg', cv2.IMREAD_COLOR)
# 读取灰度图像
img_gray = cv2.imread('cat.jpg', cv2.IMREAD_GRAYSCALE)
# 显示图像
cv2.imshow('Color Image', img_color)
cv2.imshow('Gray Image', img_gray)
# 等待按键,参数0表示无限等待
cv2.waitKey(0)
# 关闭所有窗口
cv2.destroyAllWindows()
显示图像用的是 cv2.imshow(),第一个参数是窗口名称,第二个是图像数据。这里有个小细节:cv2.waitKey(0) 如果不写,窗口会一闪而过。我曾经调试了半天才发现是忘了加这行代码。
小技巧: 如果你想让窗口自动关闭,可以设置等待时间,比如 cv2.waitKey(1000) 表示等待1秒后自动关闭。
2.2 视频捕获与保存
视频处理其实没那么神秘。说白了,视频就是一帧一帧的图像快速播放。OpenCV用 VideoCapture 来读取视频,用 VideoWriter 来保存视频。
2.2.1 从摄像头捕获视频
import cv2
# 打开摄像头,参数0表示第一个摄像头
cap = cv2.VideoCapture(0)
while True:
# 读取一帧
ret, frame = cap.read()
if not ret:
print("无法获取视频帧")
break
# 显示当前帧
cv2.imshow('Camera', frame)
# 按 'q' 键退出
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放资源
cap.release()
cv2.destroyAllWindows()
我建议你在读取视频帧时,一定要检查 ret 的返回值。为什么?因为摄像头可能被占用,或者视频文件读到末尾了。如果不检查,程序会直接崩溃。
2.2.2 保存视频到文件
保存视频需要指定编码器。OpenCV用的是FourCC编码格式。常见的编码器有:
| 编码器 | 说明 |
|---|---|
cv2.VideoWriter_fourcc(*'XVID') |
XVID编码,生成.avi文件 |
cv2.VideoWriter_fourcc(*'MJPG') |
Motion JPEG编码,生成.avi文件 |
cv2.VideoWriter_fourcc(*'H264') |
H.264编码,生成.mp4文件(需要系统支持) |
import cv2
cap = cv2.VideoCapture(0)
# 定义编码器和VideoWriter对象
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)
cv2.imshow('Recording', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
out.release()
cv2.destroyAllWindows()
避坑指南: 我曾经在保存视频时,发现生成的视频打不开。排查了半天,原来是 VideoWriter 的尺寸参数跟实际帧尺寸不一致。记住:写入的帧尺寸必须跟初始化时设置的尺寸完全一致。
2.3 色彩空间转换
OpenCV默认读取的图像是BGR格式,不是我们熟悉的RGB。这一点坑了不少人。我刚开始学的时候,用matplotlib显示图像,结果颜色全乱了——因为matplotlib用的是RGB。
常用的色彩空间转换函数是 cv2.cvtColor()。
import cv2
img = cv2.imread('cat.jpg')
# 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)
cv2.imshow('Gray', gray)
cv2.imshow('HSV', hsv)
cv2.waitKey(0)
cv2.destroyAllWindows()
你可能会问:为什么要转HSV?因为HSV在颜色分割任务中特别好用。比如做车牌识别时,用HSV可以轻松提取蓝色或绿色的车牌区域。而BGR对光照变化很敏感,说白了就是不好用。
HSV各通道含义:
- H(色调): 0-180,表示颜色种类
- S(饱和度): 0-255,颜色纯度
- V(明度): 0-255,亮度
2.4 图像缩放与裁剪
图像缩放用 cv2.resize()。这个函数有两个关键参数:目标尺寸和插值方法。
import cv2
img = cv2.imread('cat.jpg')
height, width = img.shape[:2]
# 方法1:指定固定尺寸
resized = cv2.resize(img, (300, 300))
# 方法2:按比例缩放
scale_percent = 50 # 缩小到50%
new_width = int(width * scale_percent / 100)
new_height = int(height * scale_percent / 100)
resized_ratio = cv2.resize(img, (new_width, new_height))
# 方法3:使用fx/fy参数(推荐)
resized_fx = cv2.resize(img, None, fx=0.5, fy=0.5)
cv2.imshow('Original', img)
cv2.imshow('Resized', resized_fx)
cv2.waitKey(0)
cv2.destroyAllWindows()
我个人习惯用 fx 和 fy 参数,因为不用手动计算尺寸,代码更简洁。
插值方法的选择也有讲究:
| 插值方法 | 适用场景 |
|---|---|
cv2.INTER_NEAREST |
速度最快,但效果粗糙,适合实时处理 |
cv2.INTER_LINEAR |
默认方法,速度与质量平衡 |
cv2.INTER_CUBIC |
放大图像时效果更好,但速度慢 |
cv2.INTER_AREA |
缩小图像时效果最好,避免锯齿 |
裁剪就简单多了。OpenCV的图像本质上是NumPy数组,直接用切片操作就行。
import cv2
img = cv2.imread('cat.jpg')
# 裁剪:从y=50到y=200,从x=100到x=300
cropped = img[50:200, 100:300]
cv2.imshow('Cropped', cropped)
cv2.waitKey(0)
cv2.destroyAllWindows()
注意:切片顺序是 [y_start:y_end, x_start:x_end]。我刚开始总搞反,把x和y写颠倒了。你想想看,图像数组的第一维是行(y方向),第二维是列(x方向),跟数学坐标系不一样。
实战建议: 在做YOLO目标检测时,我们经常需要把检测到的目标区域裁剪出来,然后单独处理。比如检测到车牌后,裁剪出车牌区域再做字符识别。这个操作在OpenCV里就是一行切片代码的事。
好了,这一章的内容就到这里。图像读取与显示、视频捕获与保存、色彩空间转换、图像缩放与裁剪——这四个基础操作,你每天都会用到。下一章我们会继续深入,聊聊图像滤波、边缘检测和形态学操作,这些都是为YOLO预处理打基础的内容。
记住:基础不牢,地动山摇。把这些练熟了,后面跑YOLO模型的时候你会感谢自己的。