AlexNet中的图片增强--基于PCA的RGB三通道色彩抖动
在阅读完AlexNet的论文之后有感而发。
这篇论文开创性地使用了很多卷积神经网络中结构,小技巧,非常建议大家去精读一遍,这篇神经网络奠基级别的论文。
概要
在AlexNet中介绍了一种基于PCA的色彩增强的方法,效果就是图片的明度(明亮程度)会发生整体的变化,并且没有发生图片结构的改变或色差的明显变化。
效果如下图:
- 图像的亮度发生了明显的变化,有的暗,有的亮,而且图片的主要事物的轮廓还是十分清晰,没有发生改变;
- 事物的主导颜色没有发生变化(上面树叶的主导色绿色没有发生变化);
- 图片的相对色差没有发生改变,(原来图片暗的地方和亮的地方的对比度仍然存在)
论文中的实现方法
这里我简要地说一下论文中的实现方法: 实现步骤:
- 将图片按照
RGB 三通道进行normalization 处理,均值为0,方差为1。 值得一提的是,按照RGB 三通道进行处理,因为我们进行的是色彩增强,在RGB 三通道的图片中,决定图像色彩的是RGB 之间的相对关系,我们不能改变三通道内部的像素值分布。 - 将图片按照channel展平成大小为(?, 3)的array
- 求上述array的协方差矩阵
- 对协方差矩阵进行特征分解
- 下式的
p
\mathbf{p}
p 是特征向量,
λ
\lambda
λ是特征值,
α
\alpha
α即为我们添加的抖动系数
[
p
1
p
2
p
3
]
[
α
1
λ
1
α
2
λ
2
α
3
λ
3
]
T
\begin{bmatrix}\mathbf{p}_1 & \mathbf{p}_2 & \mathbf{p}_3\end{bmatrix} \begin{bmatrix}\alpha_1\lambda_1 & \alpha_2\lambda_2 & \alpha_3\lambda_3 \end{bmatrix}^T
[p1??p2??p3??][α1?λ1??α2?λ2??α3?λ3??]T 特征向量组成的矩阵是3x3的,特征值乘以抖动系数组成的array是3x1的,所以点乘得到的array 正好是3x1大小的,三个值分别加到原图像的R,G,B三通道上,就是最后得到的增强的图像。
我的理解
因为论文中没有明确解释为什么要这么做,所以我大致说一下我的理解.
- 为什么要使用PCA主成分分析??
因为要保持原图像的相对色差、主要色系和轮廓,我们不能在增强完数据之后让图像本身表达的事物发生改变。 我们是对三通道进行PCA的,协方差矩阵的特征向量表达的是R、G、B三个channel之间的相对关系,比如上面的叶子的图片,绿色占主导地位,色差主要是由绿色体现出来,绿色的色系相对丰富,所以主成分是偏绿色系的。 下面是8次增强中抖动的幅度(R,G,B三通道)
我们可以很明显地看到每一行第二个值的绝对值最大,也就是在绿色通道上抖动的幅度最大,这个就是PCA主成分的作用,找出图片中的主要色系,大幅改动主要色系的值,使得整张图像的整体的色调不发生改变。
举一个极端的例子,如果图像的像素点仅有G通道有值,R,B通道值为0,那么整张图像就是一张明暗不一的绿色图像,通过PCA主成分分析得到的扰动值,仅仅只有G通道有值,R,B通道的值仍然会是0,因为原图像中没有R、B图像的信息,PCA并不会得到这两个通道的主成分值,就不会向图片中加入原本图像中就没有的值。
PCA主成分分析会按照原图像中三各通道内数据的信息量进行权重的划分(即协方差矩阵的特征值大小)
Code
from numpy import linalg
import numpy as np
from PIL import Image
import random
import matplotlib.pyplot as plt
plt.style.use('seaborn')
def pca_color_augmention(image_array):
'''
image augmention: PCA jitter
:param image_array: 图像array
:return img2: 经过PCA-jitter增强的图像array
'''
assert image_array.dtype == 'uint8'
assert image_array.ndim == 3
img1 = image_array.astype('float32') / 255.0
mean = img1.mean(axis = 0).mean(axis = 0)
std = img1.reshape((-1, 3)).std()
img1 = (img1 - mean) / (std)
img1 = img1.reshape((-1, 3))
cov = np.cov(img1, rowvar = False)
eigValue, eigVector = linalg.eig(cov)
rand = np.array([random.normalvariate(0, 0.2) for i in range(3)])
jitter = np.dot(eigVector, eigValue * rand)
jitter = (jitter * 255).astype(np.int32)[np.newaxis, np.newaxis, :]
img2 = np.clip(image_array + jitter, 0, 255)
return img2
def show_image(image_array):
for _ in range(8):
ax = plt.subplot(241 + _)
ax.imshow(pca_color_augmention(image_array))
ax.axis('off')
plt.show()
img_tensor = np.array(Image.open('./images/leaf.jpg'))
show_image(img_tensor)
参考
下面文章的代码部分写得非常详实,我的代码在他的基础上做了些许改动 让我们使用PCA色彩增强
附
附上leaf.jpg
|