1.blobFromImage
blobFromImage
是 OpenCV 的深度神經網絡(DNN)模塊中的一個函數,它用于將圖像轉換為深度學習模型所需的輸入格式,主要是對傳入的圖像進行的轉換包括圖像尺寸調整、均值減法、縮放等預處理步驟,以便圖像數據能夠適配深度學習模型的輸入要求。
以下是 blobFromImage
函數的一些關鍵點:
- 圖像尺寸調整:函數可以根據需要調整圖像的尺寸,以匹配神經網絡的輸入尺寸。
- 均值減法:可以指定一個均值(mean),該函數會從圖像的每個通道中減去這個均值。這通常用于數據中心化,以提高模型的訓練和推理性能。
- 縮放:通過
scalefactor
參數,可以對圖像數據進行縮放,通常用于數據歸一化。 - 通道交換:如果
swapRB
參數設置為true
,則會交換圖像的紅色(R)和藍色(B)通道,因為 OpenCV 默認使用 BGR 格式,而某些神經網絡框架使用 RGB 格式。 - 裁剪:如果
crop
參數設置為true
,則在調整圖像大小時進行中心裁剪,以確保輸出尺寸與指定的尺寸精確匹配。 - 數據類型:通過
ddepth
參數可以指定輸出 blob 的深度,通常選擇CV_32F
(32位浮點數)。 - 批量處理:還有一個對應的函數
blobFromImages
,用于將一系列圖像轉換為一個批量的 blob,這在處理圖像批次時更為高效。
這個函數是 OpenCV DNN 模塊中進行圖像預處理的關鍵步驟,它使得 OpenCV 能夠與多種深度學習框架無縫集成,進行圖像分類、目標檢測、語義分割等任務。
例如,在進行圖像分類時,可以使用blobFromImage
對輸入圖像進行預處理,然后通過神經網絡模型進行推理,得到預測結果。在 OpenCV 的示例和相關博客文章中,提供了如何使用這個函數的詳細說明和示例代碼。
函數原型
Mat cv::dnn::blobFromImage ( InputArray image,double scalefactor = 1.0,const Size & size = Size(),const Scalar & mean = Scalar(),bool swapRB = false,bool crop = false,int ddepth = CV_32F
)
OpenCV
中的DNN
模塊包含blobFromImage
方法對輸入神經網絡的圖像進行處理,blobFromImage
函數執行的操作及順序為:
- 先相對于原圖像中心resize,crop
- 再減均值
- 像素值縮放0-255 -> 0-1
- 圖像數據通道轉換,RGB->BGR
- 返回一個NCHW 數組
2.torchvision
在torchvision
庫中,transforms
模塊提供了一系列用于數據增強和預處理的函數,這些函數可以在數據加載后、模型訓練前對圖像數據進行操作,以適配深度學習模型的輸入要求。ToTensor
和Normalize
是兩個常用的轉換方法,它們通常聯合使用來實現圖像數據的標準化。
ToTensor
轉換的作用是將圖像數據轉換為PyTorch模型可以接受的格式。具體來說,它執行以下操作:
- 轉換數據類型:將輸入圖像的數據類型從
uint8
轉換為浮點數(通常是float32
)。 - 維度變換:將圖像的維度從
HWC
(高度、寬度、通道數)變換為CHW
(通道數、高度、寬度)。這是因為PyTorch模型通常期望輸入數據遵循這種維度順序。 - 縮放像素值:將像素值從范圍
0-255
線性縮放到0-1
。這是通過將每個像素值除以255來實現的。
Normalize
Normalize
轉換用于對圖像數據進行標準化處理,通常在ToTensor
之后使用。它主要執行以下操作:
- 減去均值:從圖像的每個通道中減去指定的均值。均值通常是根據整個數據集的每個通道的像素值計算得到的。
- 除以標準差:將減去均值后的圖像數據除以對應通道的標準差。這有助于進一步規范化數據,使其具有單位方差。
標準化公式是: x ? mean std \frac{x - \text{mean}}{\text{std}} stdx?mean?,其中x
是原始像素值,mean
是像素值的均值,std
是標準差。
這兩個轉換方法的聯合使用可以有效地對輸入圖像進行預處理,使其格式和數值范圍適應深度學習模型的需要。這樣做不僅有助于模型的訓練過程,還可以提高模型的泛化能力。在實際應用中,這些轉換通常被組合在一起作為一個預處理管道,可以方便地應用于數據集中的每個圖像。
3.示例
通過一段簡單的程序介紹cv2.dnn.blobFromImage
執行的操作與torchvision
中的ToTensor
+Normalize
效果等同
import cv2
import torch
import torchvision
from torchvision import transforms
import numpy as np
from PIL import Image# 生成一個隨機顏色的4x4圖像,形狀為 (高度, 寬度, 通道數)
dd = np.random.randint(0, 255, (5, 5, 3), dtype=np.uint8)
print(f"原始圖像 dd: {dd}")print("===>>> 使用 PyTorch 的 torchvision 進行預處理")# 將 NumPy 數組轉換為 PyTorch 張量
tt = torch.tensor(dd)
print(f"轉換后的張量 tt: {tt}")# 將 NumPy 數組轉換為 PIL 圖像
tp = Image.fromarray(dd)# 使用 torchvision 的 Compose 來串聯多個轉換操作
trans = transforms.Compose([transforms.ToTensor(), # 將 PIL 圖像轉換為張量,執行 HWC 到 CHW 的維度變換,并將像素值從 0-255 轉換為 0-1transforms.Normalize((.5, .5, .5), (1., 1., 1.)) # 標準化張量,減去均值 (.5, .5, .5) 并除以標準差 (1., 1., 1.)
])# 應用轉換操作
trans_tt = trans(tp)
print(trans_tt)
print(f"轉換后的張量形狀 trans_tt.shape: {trans_tt.shape}")print("===>>> 使用 OpenCV 的 cv2.dnn.blobFromImage 進行預處理")# 使用 OpenCV 的 blobFromImage 函數進行預處理
# 參數說明:
# dd: 輸入圖像
# 1/255: 縮放比例,將像素值從 0-255 轉換為 0-1
# (4, 4): 目標圖像尺寸,由于輸入圖像已經是 4x4,所以這里不執行尺寸變換
# (127.5, 127.5, 127.5): 用于減去的均值
# False, False: 分別表示不交換 R 和 B 通道,不進行裁剪
blob = cv2.dnn.blobFromImage(dd, 1/255, (5, 5), (127.5, 127.5, 127.5), False, False)
print(f"OpenCV blobFromImage 輸出的 blob: {blob}")
print(f"blob 的形狀 blog.shape: {blob.shape}")
上述代碼的輸出為:
原始圖像 dd: [[[ 24 53 15][ 4 172 202][133 72 98][128 19 201][174 141 57]][[ 71 176 174][242 166 134][139 157 153][160 104 222][208 71 191]][[ 21 104 241][173 199 116][222 97 19][ 76 222 237][220 41 78]][[175 254 71][106 44 23][ 1 142 205][157 236 211][214 235 128]][[246 104 169][186 112 187][176 181 251][108 232 173][203 25 55]]]
===>>> 使用 PyTorch 的 torchvision 進行預處理
轉換后的張量 tt: tensor([[[ 24, 53, 15],[ 4, 172, 202],[133, 72, 98],[128, 19, 201],[174, 141, 57]],[[ 71, 176, 174],[242, 166, 134],[139, 157, 153],[160, 104, 222],[208, 71, 191]],[[ 21, 104, 241],[173, 199, 116],[222, 97, 19],[ 76, 222, 237],[220, 41, 78]],[[175, 254, 71],[106, 44, 23],[ 1, 142, 205],[157, 236, 211],[214, 235, 128]],[[246, 104, 169],[186, 112, 187],[176, 181, 251],[108, 232, 173],[203, 25, 55]]], dtype=torch.uint8)
tensor([[[-0.4059, -0.4843, 0.0216, 0.0020, 0.1824],[-0.2216, 0.4490, 0.0451, 0.1275, 0.3157],[-0.4176, 0.1784, 0.3706, -0.2020, 0.3627],[ 0.1863, -0.0843, -0.4961, 0.1157, 0.3392],[ 0.4647, 0.2294, 0.1902, -0.0765, 0.2961]],[[-0.2922, 0.1745, -0.2176, -0.4255, 0.0529],[ 0.1902, 0.1510, 0.1157, -0.0922, -0.2216],[-0.0922, 0.2804, -0.1196, 0.3706, -0.3392],[ 0.4961, -0.3275, 0.0569, 0.4255, 0.4216],[-0.0922, -0.0608, 0.2098, 0.4098, -0.4020]],[[-0.4412, 0.2922, -0.1157, 0.2882, -0.2765],[ 0.1824, 0.0255, 0.1000, 0.3706, 0.2490],[ 0.4451, -0.0451, -0.4255, 0.4294, -0.1941],[-0.2216, -0.4098, 0.3039, 0.3275, 0.0020],[ 0.1627, 0.2333, 0.4843, 0.1784, -0.2843]]])
轉換后的張量形狀 trans_tt.shape: torch.Size([3, 5, 5])
===>>> 使用 OpenCV 的 cv2.dnn.blobFromImage 進行預處理
OpenCV blobFromImage 輸出的 blob: [[[[-0.40588236 -0.48431373 0.02156863 0.00196078 0.18235295][-0.22156863 0.4490196 0.04509804 0.12745099 0.3156863 ][-0.41764706 0.17843138 0.37058824 -0.20196079 0.3627451 ][ 0.18627451 -0.08431373 -0.49607843 0.11568628 0.3392157 ][ 0.46470588 0.22941177 0.19019608 -0.07647059 0.29607844]][[-0.29215688 0.17450981 -0.21764706 -0.4254902 0.05294118][ 0.19019608 0.1509804 0.11568628 -0.09215686 -0.22156863][-0.09215686 0.28039217 -0.11960784 0.37058824 -0.3392157 ][ 0.49607843 -0.327451 0.05686275 0.4254902 0.42156863][-0.09215686 -0.06078431 0.20980392 0.40980393 -0.4019608 ]][[-0.44117647 0.29215688 -0.11568628 0.2882353 -0.2764706 ][ 0.18235295 0.0254902 0.1 0.37058824 0.24901961][ 0.44509804 -0.04509804 -0.4254902 0.42941177 -0.19411765][-0.22156863 -0.40980393 0.30392158 0.327451 0.00196078][ 0.1627451 0.23333333 0.48431373 0.17843138 -0.28431374]]]]
blob 的形狀 blog.shape: (1, 3, 5, 5)