在计算机视觉任务中,颜色空间转换和图像几何变换是两大基础且高频的操作 —— 前者用于精准分割特定颜色目标(如交通信号灯、物体追踪),后者用于调整图像的尺寸、位置和视角(如文档矫正、图像拼接)。本文将通过 6 段实战代码,系统解析 HSV 颜色检测、图像缩放、平移、旋转、仿射变换和透视变换的原理与应用。
一、HSV 颜色空间:精准检测特定颜色(以蓝色为例)
RGB(或 BGR)颜色空间虽直观,但受光照影响大(如亮度变化会导致像素值剧烈波动),而HSV 颜色空间(色相 H、饱和度 S、明度 V)更符合人眼对颜色的感知,且能有效分离颜色信息与亮度信息,是颜色分割的首选。
1. 代码实现:实时检测摄像头中的蓝色物体
import cv2
import numpy as np# 打开默认摄像头
cap = cv2.VideoCapture(0)while True:# 读取一帧图像ret, frame = cap.read()if not ret: # 防止摄像头读取失败break# 1. 将BGR图像转换为HSV图像(OpenCV默认BGR格式)hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)# 2. 定义HSV空间中蓝色的范围(需根据实际场景调试)# H:色相(0-179),S:饱和度(0-255),V:明度(0-255)lower_blue = np.array([110, 50, 50]) # 蓝色下限upper_blue = np.array([130, 255, 255]) # 蓝色上限# 3. 生成颜色掩码:在范围內的像素设为255(白色),否则为0(黑色)mask = cv2.inRange(hsv, lower_blue, upper_blue)# 4. 掩码与原图像进行按位与:只保留原图像中蓝色区域res = cv2.bitwise_and(frame, frame, mask=mask)# 显示结果cv2.imshow('Original Frame', frame) # 原图像cv2.imshow('Blue Mask', mask) # 颜色掩码cv2.imshow('Detected Blue', res) # 检测结果# 按q键退出循环if cv2.waitKey(1) & 0xFF == ord('q'):break# 释放资源
cap.release()
cv2.destroyAllWindows()
2. 关键技术解析
函数 / 操作 | 作用与原理 |
---|---|
cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) | 将 BGR 格式转换为 HSV 格式,分离颜色(H)、纯度(S)、亮度(V)信息,避免光照干扰。 |
cv2.inRange(hsv, lower, upper) | 生成二值掩码:筛选出 HSV 值在[lower, upper] 范围内的像素,实现颜色分割。 |
cv2.bitwise_and(frame, frame, mask=mask) | 按位与操作:仅保留原图像中掩码为 255(白色)的区域,即目标颜色区域。 |
3. 实用技巧
- HSV 范围调试:不同场景下颜色的 HSV 范围不同,可通过「先获取目标颜色的 HSV 值」再微调范围(如用
cv2.cvtColor
转换单个像素的 BGR 到 HSV)。 - 抗干扰优化:可对掩码进行形态学操作(如
cv2.erode
腐蚀、cv2.dilate
膨胀),去除小噪声点。
二、图像缩放:调整图像尺寸
图像缩放是预处理的基础操作,用于统一图像尺寸(如神经网络输入要求固定大小)或优化显示效果。OpenCV 提供两种缩放方式:按比例缩放和指定目标尺寸缩放。
1. 代码实现:两种缩放方式
import cv2
import numpy as np# 读取图像
img = cv2.imread('ocv01.jpg')
if img is None: # 防止图像读取失败print("无法读取图像")exit()# 方式1:按比例缩放(fx=水平比例,fy=垂直比例)
# interpolation=INTER_CUBIC:双三次插值(放大时效果最优,速度较慢)
res1 = cv2.resize(img, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC)# 方式2:指定目标尺寸(宽,高)
height, width = img.shape[:2] # 获取原图像尺寸(高,宽)
res2 = cv2.resize(img, (2*width, 2*height), interpolation=cv2.INTER_CUBIC)# 显示对比
while True:cv2.imshow('Original (640x480)', img) # 原图像cv2.imshow('Scaled by Ratio (1280x960)', res1) # 按比例放大2倍cv2.imshow('Scaled by Size (1280x960)', res2) # 按指定尺寸放大2倍if cv2.waitKey(1) & 0xFF == ord('q'):breakcv2.destroyAllWindows()
2. 插值方法选择
缩放的核心是「插值算法」(通过已有像素计算新像素值),需根据缩放方向选择:
插值方法 | 适用场景 | 特点 |
---|---|---|
cv2.INTER_NEAREST | 快速预览、对精度要求低 | 速度最快,效果最差(锯齿) |
cv2.INTER_LINEAR | 默认选项 | 速度与效果平衡 |
cv2.INTER_CUBIC | 图像放大(如 4K 放大到 8K) | 效果最优,速度较慢 |
cv2.INTER_AREA | 图像缩小(如 1080P 缩到 720P) | 保留细节,避免模糊 |
三、图像几何变换:改变位置与视角
几何变换通过矩阵运算改变图像像素的空间位置,包括平移、旋转、仿射变换、透视变换,适用于图像矫正、视角转换等场景。
1. 平移:沿 x/y 轴移动图像
平移是最简单的几何变换,通过「平移矩阵」实现像素位置偏移。
代码实现:
import cv2
import numpy as npcap = cv2.VideoCapture(0)while True:ret, frame = cap.read()if not ret:break# 1. 定义平移矩阵:[[1,0,dx], [0,1,dy]],dx=水平偏移,dy=垂直偏移# 示例:向右偏移100像素,向下偏移50像素dx, dy = 100, 50M = np.float32([[1, 0, dx], [0, 1, dy]])# 2. 应用平移变换:warpAffine(输入图,矩阵,输出尺寸)# 输出尺寸需与原图像一致(宽,高)shifted_frame = cv2.warpAffine(frame, M, (frame.shape[1], frame.shape[0]))# 显示结果(对比原图像与平移后图像)cv2.imshow('Original Frame', frame)cv2.imshow('Shifted Frame (dx=100, dy=50)', shifted_frame)if cv2.waitKey(1) & 0xFF == ord('q'):breakcap.release()
cv2.destroyAllWindows()
2. 旋转:绕指定点旋转图像
旋转需指定「旋转中心、旋转角度、缩放因子」,通过cv2.getRotationMatrix2D
自动生成旋转矩阵,避免手动构造复杂矩阵。
代码实现:
import cv2
import numpy as np# 读取图像
img = cv2.imread('ocv01.jpg')
if img is None:print("无法读取图像")exit()# 获取图像尺寸(高,宽)
rows, cols = img.shape[:2]# 1. 生成旋转矩阵
# getRotationMatrix2D(旋转中心,旋转角度,缩放因子)
# 示例:绕图像中心旋转45°,缩放为原尺寸的0.6倍
center = (cols / 2, rows / 2) # 旋转中心(x=宽/2,y=高/2)
angle = 45 # 旋转角度(正数=逆时针,负数=顺时针)
scale = 0.6 # 旋转后图像的缩放因子
M = cv2.getRotationMatrix2D(center, angle, scale)# 2. 应用旋转变换:输出尺寸设为2*cols、2*rows,避免旋转后图像被裁剪
rotated_img = cv2.warpAffine(img, M, (2 * cols, 2 * rows))# 显示结果
cv2.imshow('Original', img)
cv2.imshow('Rotated (45° CCW, scale=0.6)', rotated_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
3. 仿射变换:保持平行线不变的变换
仿射变换通过3 对对应点确定变换(需保证 3 点不共线),核心是「保持平行线不变」,适用于图像倾斜矫正(如倾斜的文档)。
代码实现:
import cv2
import numpy as np
from matplotlib import pyplot as plt# 读取图像(注意:matplotlib显示需转换为RGB格式)
img = cv2.imread('ocv01.jpg')
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # BGR转RGB
rows, cols = img.shape[:2]# 1. 定义3对对应点(原图像点 → 目标图像点)
# 原图像中3个不共线的点
pts1 = np.float32([[50, 50], [200, 50], [50, 200]])
# 目标图像中对应的3个点(可根据需求调整,实现倾斜矫正)
pts2 = np.float32([[10, 100], [200, 50], [100, 250]])# 2. 生成仿射变换矩阵
M = cv2.getAffineTransform(pts1, pts2)# 3. 应用仿射变换
affine_img = cv2.warpAffine(img_rgb, M, (cols, rows))# 用matplotlib显示对比
plt.subplot(121), plt.imshow(img_rgb), plt.title('Original')
plt.subplot(122), plt.imshow(affine_img), plt.title('Affine Transformed')
plt.show()
4. 透视变换:改变投影视角(如鸟瞰图)
透视变换通过4 对对应点确定变换(需保证 4 点构成凸四边形),核心是「打破平行线约束」,可将倾斜视角转换为正视角(如将斜拍的文档转为正拍效果)。
代码实现:
import cv2
import numpy as np
from matplotlib import pyplot as plt# 读取图像并转换为RGB
img = cv2.imread('ocv01.jpg')
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
rows, cols = img.shape[:2]# 1. 定义4对对应点(原图像中的四边形顶点 → 目标图像中的矩形顶点)
# 原图像中4个凸四边形顶点(如斜拍文档的四个角)
pts1 = np.float32([[56, 65], [368, 52], [28, 387], [389, 390]])
# 目标图像中对应的矩形顶点(如300x300的正方形)
pts2 = np.float32([[0, 0], [300, 0], [0, 300], [300, 300]])# 2. 生成透视变换矩阵
M = cv2.getPerspectiveTransform(pts1, pts2)# 3. 应用透视变换:输出尺寸设为300x300(与目标矩形匹配)
perspective_img = cv2.warpPerspective(img_rgb, M, (300, 300))# 显示对比
plt.subplot(121), plt.imshow(img_rgb), plt.title('Original (Tilted)')
plt.subplot(122), plt.imshow(perspective_img), plt.title('Perspective (Top-Down)')
plt.show()
5. 仿射变换 vs 透视变换
对比维度 | 仿射变换(Affine) | 透视变换(Perspective) |
---|---|---|
对应点数 | 3 对(不共线) | 4 对(凸四边形) |
核心特性 | 保持平行线不变 | 打破平行线约束(如近大远小) |
变换矩阵维度 | 2x3 矩阵 | 3x3 矩阵 |
适用场景 | 图像倾斜矫正、平移 + 旋转组合 | 鸟瞰图生成、文档矫正、3D 视角转换 |
总结
本文覆盖的 OpenCV 核心技术,是计算机视觉任务的基石:
- HSV 颜色检测:解决 RGB 颜色分割受光照干扰的问题,适用于目标追踪、颜色筛选。
- 图像缩放:通过插值算法调整尺寸,满足统一输入、优化显示的需求。
- 几何变换:
- 平移 / 旋转:简单位置调整,适用于图像对齐。
- 仿射变换:保持平行线,适用于倾斜矫正。
- 透视变换:改变投影视角,适用于文档扫描、鸟瞰图生成。
这些技术的灵活组合,可实现更复杂的任务(如「透视矫正 + 颜色检测」实现文档中特定颜色文字的提取)。实际应用中,需注意「图像读取失败处理」「坐标与尺寸的一致性」「插值方法选择」等细节,避免常见 bug。