第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 顺序,一直保留到现在。

我曾经在项目里用 OpenCV 读图,然后用 matplotlib 显示,结果猫变成蓝猫了。排查了半天才发现是通道顺序的问题。记住:OpenCV 读图 = BGR,matplotlib 显示 = RGB。

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) 颜色分割、物体跟踪
我个人经验:做颜色检测时,HSV 空间比 BGR 好用得多。比如检测红色物体,在 BGR 里红色分布在三个通道,很难设定阈值;但在 HSV 里,只需要调 H 通道的范围就行。我做过一个交通灯识别项目,就是用 HSV 分割红色和绿色区域,效果很稳定。

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 缩小图像,避免锯齿 中等
我曾经在实时检测项目里直接用默认插值缩放 1080p 到 416x416,结果每帧处理时间多了 15 毫秒。后来换成 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 文字内容、左下角坐标、字体、字号、颜色、线宽 中文需要特殊处理,默认不支持
颜色顺序注意:OpenCV 绘制函数的颜色参数也是 BGR 顺序。(0, 255, 0) 是绿色,(0, 0, 255) 是红色。我刚开始总写成 RGB 顺序,画出来的框颜色不对,调试了半天才发现问题。

字体方面,cv2.FONT_HERSHEY_SIMPLEX 是最常用的,支持英文和数字。如果要显示中文,需要用 PIL 库先把中文渲染到图像上,再转回 OpenCV 格式。这个技巧在后面的课程里会专门讲。

2.5 本章知识体系

下面这张图把本章的核心操作串起来了,你可以对照着复习:

OpenCV基础操作知识体系 OpenCV基础操作(上)知识体系 图像处理基础 读取与显示 色彩空间转换 缩放与裁剪 图像绘制 imread() imshow() BGR→灰度 BGR→HSV resize() 切片裁剪 rectangle() circle() putText() 所有操作都基于 BGR 格式,注意与 RGB 的区别

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

这段代码把读取、缩放、裁剪、色彩转换、绘制全部用上了。你想想看,如果把这个流程套在视频流的每一帧上,不就是实时目标检测的雏形了吗?

我建议你动手改改参数:换一张自己的照片,调整裁剪区域,试试不同的颜色画框。只有亲手敲过代码,这些函数才会变成你的肌肉记忆。