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()

我个人习惯用 fxfy 参数,因为不用手动计算尺寸,代码更简洁。

插值方法的选择也有讲究:

插值方法 适用场景
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模型的时候你会感谢自己的。