这是在python中美白图像的正确方法吗?

Rik*_*ika 4 python image-preprocessing image-whitening

我正在尝试zero-centerwhiten CIFAR10数据集,但我得到的结果看起来像随机噪音!
Cifar10数据集包含60,000大小的彩色图像32x32.训练集包含50,000和测试集10,000分别包含图像.
以下代码片段显示了我为使数据集变白而执行的过程:

# zero-center
mean = np.mean(data_train, axis = (0,2,3)) 
for i in range(data_train.shape[0]):
    for j in range(data_train.shape[1]):
        data_train[i,j,:,:] -= mean[j]

first_dim = data_train.shape[0] #50,000
second_dim = data_train.shape[1] * data_train.shape[2] * data_train.shape[3] # 3*32*32
shape = (first_dim, second_dim) # (50000, 3072) 

# compute the covariance matrix
cov = np.dot(data_train.reshape(shape).T, data_train.reshape(shape)) / data_train.shape[0] 
# compute the SVD factorization of the data covariance matrix
U,S,V = np.linalg.svd(cov)

print 'cov.shape = ',cov.shape
print U.shape, S.shape, V.shape

Xrot = np.dot(data_train.reshape(shape), U) # decorrelate the data
Xwhite = Xrot / np.sqrt(S + 1e-5)

print Xwhite.shape
data_whitened = Xwhite.reshape(-1,32,32,3)
print data_whitened.shape
Run Code Online (Sandbox Code Playgroud)

输出:

cov.shape =  (3072L, 3072L)
(3072L, 3072L) (3072L,) (3072L, 3072L)
(50000L, 3072L)
(50000L, 32L, 32L, 3L)
(32L, 32L, 3L)
Run Code Online (Sandbox Code Playgroud)

并尝试显示生成的图像:

import matplotlib.pyplot as plt
%matplotlib inline
from scipy.misc import imshow
print data_whitened[0].shape
fig = plt.figure()
plt.subplot(221)
plt.imshow(data_whitened[0])
plt.subplot(222)
plt.imshow(data_whitened[100])
plt.show()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

顺便说的data_train[0].shape就是(3,32,32),但如果我重塑whittened图像根据我得到

TypeError: Invalid dimensions for image data
Run Code Online (Sandbox Code Playgroud)

这可能只是一个可视化问题吗?如果是这样我怎么能确定这种情况呢?

更新:
感谢@AndrasDeak,我以这种方式修复了可视化代码,但输出仍然是随机的:

data_whitened = Xwhite.reshape(-1,3,32,32).transpose(0,2,3,1)
print data_whitened.shape
fig = plt.figure()
plt.subplot(221)
plt.imshow(data_whitened[0])
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

更新2:
这是我在运行下面给出的一些命令时得到的结果:正如下面所示,toimage可以很好地显示图像,但是尝试重塑它,会弄乱图像. 在此输入图像描述

# output is of shape (N, 3, 32, 32)
X = X.reshape((-1,3,32,32))
# output is of shape (N, 32, 32, 3)
X = X.transpose(0,2,3,1)
# put data back into a design matrix (N, 3072)
X = X.reshape(-1, 3072)

plt.imshow(X[6].reshape(32,32,3))
plt.show()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

出于一些奇怪的原因,这是我最初得到的,但经过几次尝试后,它改为上一张图片. 在此输入图像描述

wil*_*elm 12

让我们来看看这个.正如您所指出的,CIFAR包含存储在矩阵中的图像; 每个图像都是一行,每行有3072列uint8数字(0-255).图像为32x32像素,像素为RGB(三通道颜色).

# https://www.cs.toronto.edu/~kriz/cifar.html
# wget https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
# tar xf cifar-10-python.tar.gz
import numpy as np
import cPickle
with open('cifar-10-batches-py/data_batch_1') as input_file: 
    X = cPickle.load(input_file)
X = X['data']   # shape is (N, 3072)
Run Code Online (Sandbox Code Playgroud)

事实证明,列的排序有点滑稽:所有红色像素值首先出现,然后是所有绿色像素,然后是所有蓝色像素.这使得查看图像变得棘手.这个:

import matplotlib.pyplot as plt
plt.imshow(X[6].reshape(32,32,3))
plt.show()
Run Code Online (Sandbox Code Playgroud)

给出这个:

混色的色彩通道

所以,仅仅为了便于观看,让我们的洗牌矩阵的尺寸与周围reshapetranspose:

# output is of shape (N, 3, 32, 32)
X = X.reshape((-1,3,32,32))
# output is of shape (N, 32, 32, 3)
X = X.transpose(0,2,3,1)
# put data back into a design matrix (N, 3072)
X = X.reshape(-1, 3072)
Run Code Online (Sandbox Code Playgroud)

现在:

plt.imshow(X[6].reshape(32,32,3))
plt.show()
Run Code Online (Sandbox Code Playgroud)

得到:

一只孔雀

好的,ZCA美白.我们经常被提醒,在对数据进行白化之前对数据进行零中心是非常重要的.此时,观察您包含的代码.据我所知,计算机视觉将色彩通道视为另一个特征维度; 图像中的单独RGB值没有什么特别之处,就像单独的像素值没有什么特别之处.它们都只是数字功能.因此,当你计算平均像素值时,尊重颜色通道(即,你mean是一个r,g,b值的元组),我们只计算平均图像值.请注意,这X是一个包含N行和3072列的大矩阵.我们将每列都视为与其他列相同的"同类事物".

# zero-centre the data (this calculates the mean separately across
# pixels and colour channels)
X = X - X.mean(axis=0)
Run Code Online (Sandbox Code Playgroud)

此时,我们还要进行全局对比度标准化,这通常应用于图像数据.我将使用L2规范,这使得每个图像都具有矢量幅度1:

X = X / np.sqrt((X ** 2).sum(axis=1))[:,None]
Run Code Online (Sandbox Code Playgroud)

人们可以很容易地使用其他东西,比如标准偏差(X = X / np.std(X, axis=0))或最小 - 最大缩放到某个区间,如[-1,1].

就快到了.在这一点上,我们没有对数据进行过大的修改,因为我们只是对它进行了移位和缩放(线性变换).要显示它,我们需要将图像数据恢复到范围[0,1],所以让我们使用辅助函数:

def show(i):
    i = i.reshape((32,32,3))
    m,M = i.min(), i.max()
    plt.imshow((i - m) / (M - m))
    plt.show()

show(X[6])
Run Code Online (Sandbox Code Playgroud)

孔雀在这里看起来稍微亮一点,但这只是因为我们已经拉伸其像素值来填充区间[0,1]:

稍微明亮的孔雀

ZCA美白:

# compute the covariance of the image data
cov = np.cov(X, rowvar=True)   # cov is (N, N)
# singular value decomposition
U,S,V = np.linalg.svd(cov)     # U is (N, N), S is (N,)
# build the ZCA matrix
epsilon = 1e-5
zca_matrix = np.dot(U, np.dot(np.diag(1.0/np.sqrt(S + epsilon)), U.T))
# transform the image data       zca_matrix is (N,N)
zca = np.dot(zca_matrix, X)    # zca is (N, 3072)
Run Code Online (Sandbox Code Playgroud)

看一下(show(zca[6])):

现在孔雀看起来肯定不同了.您可以看到ZCA已经通过色彩空间旋转了图像,因此它看起来像旧电视上的图片,而Tone设置不正常.但仍然可以识别.

大概是因为epsilon我使用的价值,我转换的数据的协方差不完全是同一性,但它相当接近:

>>> (np.cov(zca, rowvar=True).argmax(axis=1) == np.arange(zca.shape[0])).all()
True
Run Code Online (Sandbox Code Playgroud)

1月29日更新

我不完全确定如何解决你所遇到的问题; 你的麻烦似乎在于你原始数据的形状,所以我建议你在尝试转向零中心和ZCA之前先对其进行排序.

一方面,您的更新中的四个图的第一个图表看起来很好,这表明您已经以正确的方式加载了CIFAR数据.toimage我认为,第二个图是由哪个维度自动确定哪个维度有颜色数据,这是一个很好的技巧.另一方面,之后出现的东西看起来很奇怪,所以似乎某些地方出了问题.我承认我不能完全遵循你的脚本状态,因为我怀疑你正在以交互方式工作(笔记本),当他们不工作时重试一些事情(更多关于这一点),并且你正在使用代码您没有在问题中显示.特别是,我不确定你是如何加载CIFAR数据的; 您的屏幕截图显示了一些输出print语句(Reading training data...等),然后当你复制train_dataX和打印shapeX,形状已经被重塑成(N, 3, 32, 32).就像我说的,更新情节1会倾向于表明重塑已经正确发生.从图3和图4可以看出,我认为你在某处有关于矩阵尺寸的混淆,所以我不确定你是如何进行重塑和转置的.

请注意,由于以下原因,请务必小心重塑和转置.的X = X.reshape(...)X = X.transpose(...)代码修改矩阵到位.如果你多次这样做(比如jupyter笔记本中的意外),你会一遍又一遍地对矩阵的轴进行洗牌,并且绘制数据将开始看起来非常奇怪.这个图像显示了进展,因为我们迭代重塑和转置操作:

增加重塑和转置的迭代次数

这种进展不会循环,或者至少不会快速循环.由于数据中的周期性规律(如图像的32像素行结构),您倾向于在这些不正确的重塑转换图像中进行条带化.我想知道你的更新中的四个图中的第三个是否会发生这种情况,这看起来比你问题的原始版本中的图像更随机.

你的更新的第四个图是孔雀的颜色底片.我不确定你是怎么做到的,但我可以用以下方式重现你的输出:

plt.imshow(255 - X[6].reshape(32,32,3))
plt.show()
Run Code Online (Sandbox Code Playgroud)

这使:

孔雀的颜色否定

你可以得到一个方法是,如果你用我的show助手功能,你混了mM,就像这样:

def show(i):
    i = i.reshape((32,32,3))
    m,M = i.min(), i.max()
    plt.imshow((i - M) / (m - M))  # this will produce a negative img
    plt.show()
Run Code Online (Sandbox Code Playgroud)

  • 嗯.也许做一个更好的主意是`cov = np.cov(X,rowvar = False)`和`zca = np.dot(X,zca_matrix)`.然后`zca_matrix`将具有形状(3072,3072)并且也可以在测试集上使用.[pylearn2](https://github.com/lisa-lab/pylearn2/blob/master/pylearn2/datasets/preprocessing.py#L1391)有一个ZCA美白的工作实现,我认为他们这样做. (2认同)