在計算機視覺任務中,顏色空間轉換和圖像幾何變換是兩大基礎且高頻的操作 —— 前者用于精準分割特定顏色目標(如交通信號燈、物體追蹤),后者用于調整圖像的尺寸、位置和視角(如文檔矯正、圖像拼接)。本文將通過 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。