1. 多种增强方式概述
下列尺度大小可以调整,用示例的数据进行说明:
- 尺度缩放:将图像的较短边随机缩放到 [256, 480] 像素范围内的一个值(长边按比例调整)。
- 随机裁剪:从缩放后的图像中随机裁剪224×224区域。
- 颜色抖动:80%的概率进行颜色抖动(如下面详细说明的PCA抖动)
- 转灰度图:20%概率将图像转换为灰度图。
- 图像模糊:50%的概率进行模糊操作。(如下面详细说明的高斯模糊)
- 水平翻转:以50%概率对图像进行水平翻转。
- 归一化:将图像的值缩放到[0,1]范围后归一化,减去均值,除以标准差。
参考代码:
# Pytorch中图像预处理的标准归一化操作,将图像的每个像素通道从[0,255]或[0,1]的原始范围,转换为零均值,单位方差的分布
# mean=[0.485, 0.456, 0.406]是ImageNet的RGB三通道均值
normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406],std=[0.229, 0.224, 0.225])
augmentation = [
# 从输入图像中在0.2到1.0之间随机选择一个面积占比裁剪一张224*224的图像
transforms.RandomResizedCrop(224, scale=(0.2, 1.0)),
transforms.RandomApply( # 0.8的概率会执行括号中的所有变换
# 对整张图片同时应用以下随机扰动:
# 亮度在[1-0.4, 1+0.4]范围内随机缩放, 对比度在[1-0.4, 1+0.4]范围内随机缩放,
# 饱和度在[1-0.4, 1+0.4]范围内随机缩放, 色相在[-0.1, 0.1]范围内随机偏移
[transforms.ColorJitter(0.4, 0.4, 0.4, 0.1)],
p=0.8
),
transforms.RandomGrayscale(p=0.2), # 0.2的概率整张图片变为灰度图
transforms.RandomApply( # 0.5的概率会执行括号中的所有变换
[moco.loader.GaussianBlur([0.1, 2.0])], # 进行高斯模糊处理
p=0.5
),
transforms.RandomHorizontalFlip(), # 以默认值0.5的概率发生水平翻转
# 将图像从PIL.Image或numpy.ndarray转换为torch.Tensor,并自动归一化到[0,1]范围,这是执行下面normalize的前提
transforms.ToTensor(),
normalize
]
2. 高斯模糊增强[4]
通常,图像处理软件会提供”模糊”(blur)滤镜,使图片产生模糊的效果。”模糊”的算法有很多种,其中有一种叫做”高斯模糊”(Gaussian Blur)。它将正态分布(又名”高斯分布”)用于图像处理。本质上,它是一种数据平滑技术(data smoothing),适用于多个场合,图像处理恰好提供了一个直观的应用实例。
2.1 高斯模糊原理
所谓”模糊”,可以理解成每一个像素都取周边像素的平均值,下图中,2是中间点,周边点都是1。
“中间点”取”周围点”的平均值,就会变成1。在数值上,这是一种”平滑化”。在图形上,就相当于产生”模糊”效果,”中间点”失去细节。
计算平均值时,取值范围越大,”模糊效果”越强烈。如下图所示,下面分别是原图、模糊半径3像素、模糊半径10像素的效果。模糊半径越大,图像就越模糊。从数值角度看,就是数值越平滑。
既然每个点都要取周边像素的平均值,那么应该如何分配权重呢?如果使用简单平均,显然不是很合理,因为图像都是连续的,越靠近的点关系越密切,越远离的点关系越疏远。因此,加权平均更合理,距离越近的点权重越大,距离越远的点权重越小。
2.2 高斯分布(正态分布)的权重
正态分布显然是一种可取的权重分配模式。在图形上,正态分布是一种钟形曲线,越接近中心,取值越大,越远离中心,取值越小。计算平均值的时候,只需要将”中心点”作为原点,其他点按照其在正态曲线上的位置,分配权重,就可以得到一个加权平均值。
2.3 高斯分布及其概率密度函数
2.3.1 高斯分布及其概率密度函数定义
正态分布(Normal distribution)又名高斯分布(Gaussian distribution),是一个在数学、物理及工程等领域都非常重要的概率分布,在统计学的许多方面有着重大的影响力。
若一个随机变量x服从一个数学期望为\(\mu\),标准方差为\(\sigma^2\)的高斯分布,记为:
\(x \sim N(\mu, \sigma^2)\)
其概率密度函数为:
\(f(x)=\frac{1}{\sigma \sqrt{2 \pi}} e^{-\frac{(x-\mu)^2}{2\sigma^2}}\)
其概率密度函数又称为“高斯函数”。 如果只有一个变量,称之为一维高斯分布,其概率密度函数称为一维高斯函数。
2.3.2 高斯函数各部分的意义
这里将能够对曲线产生影响的3个部分指代为a,b,c。
\(f(x) = ae^{- \frac{(x-b)^2}{2c^2}}\)
a具体公式为\(\frac{1}{\sigma \sqrt{2 \pi}}\),b公式为\(\mu\),c表示\(\sigma\)即标准差。
a表示得到曲线的高度,b是指曲线在x轴的中心,c指width(与半峰全宽有关),图形如下:
2.3.3 sigma的引入
再次回到这张图,这张图的横轴的0.5,1.5,2,2.5表示有几个标准差的大小,0.5即0.5个标准差大小,具体数值等于0.5sigma。1即1个标准差大小,具体数值为sigma,以此类推。其中19.1%表示分布在0-0.5sigma区间内占整个分布的19.1%,15%表示分布在0.5-1sigma区间内占整个分布的15%,以此类推。
这个分布可以一直取值,不停地向两边延伸,但是分了方便计算以及精度的考量,当取-3sigma到3sigma区间内时,此时该段区间内占整个分布的99.8%,大致认为该段分布已经包含了所有的情况。
2.3.4 二维高斯函数的引入
一维高斯函数只能在一个方向上,而图像是二维的,此时引入二维高斯函数是一个很好地解决方案。一维高斯函数的公式如下所示:
\(f(x)=\frac{1}{\sigma \sqrt{2 \pi}} e^{-\frac{(x-\mu)^2}{2\sigma^2}}\)
其中,μ是x的均值,σ是x的方差。因为计算平均值的时候,中心点就是原点,所以μ默认等于0。得到以下公式:
\(f(x)=\frac{1}{\sigma \sqrt{2 \pi}} e^{-\frac{x^2}{2\sigma^2}}\)
根据一维高斯函数,可以推导得到二维高斯函数(就是两个一维的高斯函数相乘,因为两个变量之间互不相关,因此联合概率密度等于各自的概率密度的乘积):
\(G(x,y)=\frac{1}{2 \pi \sigma^2} e^{-\frac{x^2 + y^2}{2\sigma^2}}\)
有了这个函数 ,就可以计算每个点的权重了。
2.4 高斯函数运用模糊的基本认识
将高斯核函数得出的卷积核模板称之为高斯核。
有了高斯核后,那么怎么将它运用到图像中呢?假设一个高斯函数的卷积和模板大小是5*5尺寸的,那么他这25个点的x,y具体取值为,原点的x, y值为(0, 0):
此时只需要假定一个sigma值,即可确定一个高斯核。但是这个高斯核不完整,因为求出的5*5的卷积核进行卷积操作时,改变了图像原始的0-255的范围。为解决该问题只需要将卷积核归一化即可,也就是卷积核中每一个值除以卷积的总和,即可回到0-255的范围。具体的高斯核例如:
2.4.1 实际使用的例子
假定中心点的坐标是(0,0),那么距离它最近的8个点的坐标如下。远的点以此类推。
为了计算权重矩阵,需要设定σ的值。假定σ=1.5,则根据公式\(G(x,y)=\frac{1}{2 \pi \sigma^2} e^{-\frac{x^2 + y^2}{2\sigma^2}}\)和上面的(x, y)坐标图得到模糊半径为1的权重矩阵如下(我感觉他有一点没有算准确,大致是准的):
这9个点的权重总和等于0.4787147,如果只计算这9个点的加权平均,还必须让它们的权重之和等于1,因此上面9个值还要分别除以0.4787147,得到最终的权重矩阵。
有了权重矩阵,就可以计算高斯模糊的值了。假设现有9个像素点,灰度值(0-255)如下:
每个点乘以自己的权重值:
得到:
将这9个值加起来,就是中心点的高斯模糊的值。对所有点重复这个过程,就得到了高斯模糊后的图像。如果原图是彩色图片,可以对RGB三个通道分别做高斯模糊。
原始的卷积过程为:
3. PCA Jittering图像增强[1]
PCA Jittering[2]可以找出图像 RGB 通道中的主要色系,并大幅改变主要色系的值,而图像的整体色调不发生改变。简言之,PCA Jittering 通过扰动颜色通道,在不过度扭曲图像语义的前提下,提升了模型对颜色变化的鲁棒性,因此也是一种有效的图像增强方法。效果图如下
3.1 具体流程
PCA Jittering的具体流程[3]:首先,对整个训练集图像的 RGB 三通道进行主成分分析,得到协方差矩阵,并计算特征值和特征向量;其次,在特征值中添加高斯抖动(Jittering),并将特征值与特征向量相乘;最后,将相乘后的结果添加到原图像中,从而改变原图像 RGB 三通道的强度,并将通过 PCA Jittering 处理过的图像添加到训练集中进行训练,从而增加训练集的数量,具体流程图如下:
3.2 具体步骤
1.获取原图像\(I_{xy}\),拆分原图像\(I_{xy}\)的RGB三通道,得到三通道的值。
\(I_{xy}^R、I_{xy}^G、I_{xy}^R\)
2.以\(I_{xy}^R\)为例,为了消除奇异数据的影响,对\(I_{xy}^R\)进行归一化。归一化的公式如下。
\(I_{xy}^R=\frac{I_{xy}^R}{255.0}\)
3.为消除不同量纲的影响,对\(I_{xy}^R\)进行标准化,标准化公式如下。
\(g_{ij}^R=\frac{x_{ij}^R- \mu^R}{\sigma^R}\)
其中,\(x_{ij}^R\)表示原图R通道图像的第i行、第j列的灰度值;\(g_{ij}^R\)表示原图R通道图像第i行,第j列标准化后的灰度值;\(\mu^R\)表示R通道的算术平均值,由下式表示:
\(\mu^R=\frac{1}{n \times m}\sum_{i=1}^n \sum_{i=1}^m x_{ij}^R\)
上式中,n表示图像的行数,m表示图像的列数;\(\sigma^R\)表示R通道的标准差,公式如下:
\(\sigma^R = \sqrt{\frac{1}{n-1} \sum_{i=1}^n(x_{ij}^R- \mu^R)^2}\)
4.将标准化后的\(g_{ij}^R\)展开成一列向量\(g^R=[g_1^R g_2^R \cdots g_{m \times n}^R]^T\)。
5.\(I_{xy}^G、I_{xy}^B\)的处理方法与\(I_{xy}^R\)相同,处理完后会得到G通道和B通道标准化后的向量\(g^G、g^B\)。接着将\(g^R、g^G、g^B\)向量组成矩阵T。矩阵T的公式如下所示:
\(T = \begin{bmatrix} g_1^R & g_1^G & g_1^B \\ g_2^R & g_2^G & g_2^B \\ \vdots & \vdots & \vdots \\ g_{m \times n}^R & g_{m \times n}^G & g_{m \times n}^B \end{bmatrix} = \begin{bmatrix} g^R & g^G & g^B \end{bmatrix}\)
6.创建T的协方差矩阵:
\(S=\begin{bmatrix} cov(g^R,g^R) & cov(g^R,g^G) & cov(g^R,g^B) \\ cov(g^G,g^R) & cov(g^G, g^G) & cov(g^G,g^B) \\ cov(g^B,g^R) & cov(g^B,g^G) & cov(g^B,g^B) \end{bmatrix}\)
其中,\(cov(g^w,g^v)=\frac{1}{n-1} \sum_{i=1}^{m \times n}(g_i^w- \overline{g^w})(g_i^v-\overline{g^v}), w,v \in [R,G,B]\)。而\(\overline{g^w},\overline{g^v}\)表示w,v列的平均值。
7.求协方差矩阵S的特征向量\(p_i\)和特征值\(\lambda_i\),其中\(i \in [1,2,3]\)
8.将特征值\(\lambda_i\)乘以一个以 0 为均值,0.1 为方差的高斯扰动\(a_i\),将添加扰动后的特征值与特征向量相乘,并将结果乘以 255 后添加到原有像素值\(I_{xy}=[I_{xy}^R,I_{xy}^G,I_{xy}^B]\)中,使用PCA Jittering 图像增强后的图像像素值如下式所示:
\(I_{xy}^{\prime}=[I_{xy}^R,I_{xy}^G,I_{xy}^B]+255 \times [p_1,p_2,p_3][\alpha_1 \lambda_1,\alpha_2 \lambda_2,\alpha_3 \lambda_3]^T\)
3.3 代码
实现示例图:
这是本人写的,特别笨拙,不太灵活,但是易懂的代码:
import cv2
import numpy as np
import matplotlib.pyplot as plt
image_path=r'E:\image\other\cat1.jpg'
# 步骤1
image=cv2.imread(image_path)
# 步骤2
image_norm=image/255
# 步骤3
r_channel = image_norm[:, :, 2]
r_mean=np.mean(r_channel,axis=(0,1))
r_std=np.std(r_channel,axis=(0,1))
r_norm=(r_channel-r_mean)/r_std
g_channel = image_norm[:, :, 1]
g_mean=np.mean(g_channel,axis=(0,1))
g_std=np.std(g_channel,axis=(0,1))
g_norm=(g_channel-g_mean)/g_std
b_channel = image_norm[:, :, 0]
b_mean=np.mean(b_channel,axis=(0,1))
b_std=np.std(b_channel,axis=(0,1))
b_norm=(b_channel-b_mean)/r_std
# 步骤4
r_norm_column=r_norm.reshape(-1,1)
g_norm_column=g_norm.reshape(-1,1)
b_norm_column=b_norm.reshape(-1,1)
# 步骤5
g=np.column_stack([r_norm_column,g_norm_column,b_norm_column])
# 步骤6
cov_matrix=np.cov(g,rowvar=False)
# 步骤7
eigenvalues,eigenvectors=np.linalg.eig(cov_matrix)
print(eigenvectors.shape)
# 步骤8
rgb_image=cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
vector_noise = np.random.normal(0, np.sqrt(0.1), size=3)
print(vector_noise)
# vector_noise=np.array([0.1,0.1,0.1],np.float32)
image_change=255*np.dot(eigenvectors,vector_noise.T*eigenvalues)
print(image_change)
image_PCA_RGB=rgb_image.astype(np.int16)+image_change
image_PCA_RGB=np.clip(image_PCA_RGB, 0, 255).astype(np.uint8)
plt.figure(figsize=(10,10))
plt.subplot(1,2,1)
plt.imshow(rgb_image)
plt.title('Original Image')
plt.axis('off')
plt.subplot(1,2,2)
plt.imshow(image_PCA_RGB)
plt.title('PCA Jittering Image')
plt.axis('off')
plt.show()
这是亲爱的deepseek把我的代码经过优化后的高端写法:
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取图像并归一化
image = cv2.imread(r'E:\image\other\cat1.jpg')
image_norm = image / 255.0
# 标准化各通道
channels = [image_norm[:, :, i] for i in [2, 1, 0]] # R, G, B
norm_channels = [(c - np.mean(c)) / np.std(c) for c in channels]
# 合并为矩阵并计算PCA
g = np.column_stack([c.ravel() for c in norm_channels])
cov_matrix = np.cov(g, rowvar=False)
eigenvalues, eigenvectors = np.linalg.eig(cov_matrix)
# 生成PCA噪声并应用
vector_noise = np.random.normal(0, np.sqrt(0.1), 3)
image_change = 255 * (eigenvectors @ (vector_noise * eigenvalues))
image_PCA_RGB = np.clip(cv2.cvtColor(image, cv2.COLOR_BGR2RGB).astype(np.int16) + image_change, 0, 255).astype(np.uint8)
# 可视化
plt.figure(figsize=(10, 5))
plt.subplot(121), plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)), plt.title('Original')
plt.subplot(122), plt.imshow(image_PCA_RGB), plt.title('PCA Jittering')
plt.show()
参考
- Curz酥. 原文链接:https://blog.csdn.net/m0_56494923/article/details/146438076. CSDN.
- Krizhevsky A, Sutskever I, Hinton G E. Imagenet classification with deep convolutional neural networks[J]. Advances in neural information processing systems, 2012, 25.
- 陈刚.基于卷积神经网络的森林火灾识别系统的研究与设计[D].南京林业大学,2023.DOI:10.27242/d.cnki.gnjlu.2023.000651.
- 生活需要深度.【图像处理】高斯模糊、高斯函数、高斯核、高斯卷积操作. CSDN.