计算机视觉——Opencv blobFromImage与torchvision实现数据标准化
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-1
transforms.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)
更多推荐
所有评论(0)