第2章 OpenCV基础操作(上):图像的读取与显示、色彩空间转换、缩放裁剪与绘制
各位同学,欢迎来到第二章。上一章我们把开发环境搭好了,今天开始真正动手操作OpenCV。
我个人习惯把图像处理比作「厨师做菜」——读取图像是「备菜」,色彩转换是「调味」,缩放裁剪是「切菜」,绘制图形是「摆盘」。听起来是不是挺有意思?那我们直接开干。
2.1 图像的读取与显示
OpenCV读取图像用 cv2.imread(),显示用 cv2.imshow()。这两个函数是入门第一关。
import cv2
# 读取图像
img = cv2.imread('cat.jpg')
# 显示图像
cv2.imshow('My Cat', img)
cv2.waitKey(0) # 等待按键
cv2.destroyAllWindows() # 关闭所有窗口
这里有个坑,我刚开始学的时候踩过——cv2.imread() 默认以 BGR 格式读取,不是我们熟悉的 RGB。你想想看,如果直接用 matplotlib 显示,颜色会偏蓝偏怪。为什么?因为 OpenCV 当年设计时沿用了 BGR 顺序,一直保留到现在。
cv2.imread() 的第二个参数控制读取方式,常用三种:
| 参数值 | 含义 | 使用场景 |
|---|---|---|
cv2.IMREAD_COLOR (1) |
彩色图像,忽略透明度 | 日常处理,默认值 |
cv2.IMREAD_GRAYSCALE (0) |
灰度图像 | 边缘检测、特征提取前 |
cv2.IMREAD_UNCHANGED (-1) |
包含 Alpha 通道 | 处理 PNG 透明图 |
显示时,cv2.waitKey(0) 表示无限等待按键。如果填 cv2.waitKey(30),窗口会在 30 毫秒后自动关闭——这个参数在视频流里特别有用,后面章节会频繁用到。
2.2 图像色彩空间转换
色彩空间转换是图像处理的基础操作。说白了,就是把图像从一种颜色表示方式变成另一种。
OpenCV 提供了 cv2.cvtColor() 函数,用法很简单:
# BGR 转灰度
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# BGR 转 RGB
rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# BGR 转 HSV
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
三种常用转换的对比:
| 转换类型 | 输出通道 | 典型用途 |
|---|---|---|
| BGR → 灰度 | 单通道 (0-255) | 减少计算量,二值化前处理 |
| BGR → RGB | 三通道 | 配合 matplotlib 显示 |
| BGR → HSV | 三通道 (H:0-179, S:0-255, V:0-255) | 颜色分割、物体跟踪 |
2.3 图像缩放与裁剪
缩放用 cv2.resize(),裁剪用数组切片。这两个操作在实时检测中几乎每帧都会用到。
# 缩放:指定目标尺寸
resized = cv2.resize(img, (640, 480))
# 缩放:按比例缩放
scale_percent = 50
width = int(img.shape[1] * scale_percent / 100)
height = int(img.shape[0] * scale_percent / 100)
resized = cv2.resize(img, (width, height))
# 裁剪:数组切片
cropped = img[100:400, 200:500] # [y_start:y_end, x_start:x_end]
缩放时有个参数值得注意——interpolation(插值方式):
| 插值方法 | 适用场景 | 速度 |
|---|---|---|
cv2.INTER_NEAREST |
缩小图像,速度最快 | 快 |
cv2.INTER_LINEAR |
放大图像,默认值 | 中等 |
cv2.INTER_CUBIC |
高质量放大 | 慢 |
cv2.INTER_AREA |
缩小图像,避免锯齿 | 中等 |
INTER_LINEAR,速度提升明显,画质损失肉眼看不出来。实时场景下,别追求最高质量,够用就行。
裁剪时注意坐标顺序:[y1:y2, x1:x2]。我见过不少新手写成 [x1:x2, y1:y2],结果图像变形了。记住:OpenCV 里图像是 行(高度)在前,列(宽度)在后。
2.4 图像绘制:矩形、圆形、文字
绘制操作在目标检测中用来画边界框、标注关键点、显示置信度。说白了,就是给检测结果「画出来」。
# 画矩形
cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
# 画圆形
cv2.circle(img, (cx, cy), radius, (0, 0, 255), -1)
# 写文字
cv2.putText(img, 'Cat', (x1, y1-10),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 255, 255), 2)
参数说明:
| 函数 | 关键参数 | 说明 |
|---|---|---|
cv2.rectangle |
左上角、右下角、颜色、线宽 | 线宽为 -1 时填充矩形 |
cv2.circle |
圆心、半径、颜色、线宽 | 线宽为 -1 时填充圆形 |
cv2.putText |
文字内容、左下角坐标、字体、字号、颜色、线宽 | 中文需要特殊处理,默认不支持 |
(0, 255, 0) 是绿色,(0, 0, 255) 是红色。我刚开始总写成 RGB 顺序,画出来的框颜色不对,调试了半天才发现问题。
字体方面,cv2.FONT_HERSHEY_SIMPLEX 是最常用的,支持英文和数字。如果要显示中文,需要用 PIL 库先把中文渲染到图像上,再转回 OpenCV 格式。这个技巧在后面的课程里会专门讲。
2.5 本章知识体系
下面这张图把本章的核心操作串起来了,你可以对照着复习:
2.6 综合示例:把今天学的串起来
最后,我写一个综合示例,把今天学的四个知识点串在一起。你可以在自己的电脑上跑一下:
import cv2
# 1. 读取图像
img = cv2.imread('cat.jpg')
# 2. 缩放图像
resized = cv2.resize(img, (600, 400))
# 3. 裁剪出猫脸区域(假设坐标)
face = resized[50:250, 100:300]
# 4. 转灰度
gray_face = cv2.cvtColor(face, cv2.COLOR_BGR2GRAY)
# 5. 在原始图上画框和文字
cv2.rectangle(resized, (100, 50), (300, 250), (0, 255, 0), 2)
cv2.putText(resized, 'Cat Face', (100, 40),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)
# 6. 显示结果
cv2.imshow('Result', resized)
cv2.imshow('Gray Face', gray_face)
cv2.waitKey(0)
cv2.destroyAllWindows()
这段代码把读取、缩放、裁剪、色彩转换、绘制全部用上了。你想想看,如果把这个流程套在视频流的每一帧上,不就是实时目标检测的雏形了吗?