我正在尝试在没有任何图像降维库的情况下实现 PCA。我尝试了 O'Reilly 计算机视觉书中的代码,并在示例 lenna 图片上实现了它:
from PIL import Image
from numpy import *
def pca(X):
num_data, dim = X.shape
mean_X = X.mean(axis=0)
X = X - mean_X
if dim > num_data:
# PCA compact trick
M = np.dot(X, X.T) # covariance matrix
e, U = np.linalg.eigh(M) # calculate eigenvalues an deigenvectors
tmp = np.dot(X.T, U).T
V = tmp[::-1] # reverse since the last eigenvectors are the ones we want
S = np.sqrt(e)[::-1] #reverse since the last eigenvalues are in increasing order
for i in range(V.shape[1]):
V[:,i] /= S
else:
# normal PCA, SVD method
U,S,V = np.linalg.svd(X)
V = V[:num_data] # only makes sense to return the first num_data
return V, S, mean_X
img=color.rgb2gray(io.imread('D:\lenna.png'))
x,y,z=pca(img)
plt.imshow(x)
但是 PCA 的图像图看起来根本不像原始图像。 据我所知,PCA 有点减少图像尺寸,但它仍然会在某种程度上类似于原始图像,但细节较低。代码有什么问题吗?
嗯,你的代码本身没有任何问题,但是如果我确实理解你真正想要做什么,你就不会显示right的东西!
我会为您的问题写下以下内容:
def pca(X, number_of_pcs):
num_data, dim = X.shape
mean_X = X.mean(axis=0)
X = X - mean_X
if dim > num_data:
# PCA compact trick
M = np.dot(X, X.T) # covariance matrix
e, U = np.linalg.eigh(M) # calculate eigenvalues an deigenvectors
tmp = np.dot(X.T, U).T
V = tmp[::-1] # reverse since the last eigenvectors are the ones we want
S = np.sqrt(e)[::-1] #reverse since the last eigenvalues are in increasing order
for i in range(V.shape[1]):
V[:,i] /= S
return V, S, mean_X
else:
# normal PCA, SVD method
U, S, V = np.linalg.svd(X, full_matrices=False)
# reconstruct the image using U, S and V
# otherwise you're just outputting the eigenvectors of X*X^T
V = V.T
S = np.diag(S)
X_hat = np.dot(U[:, :number_of_pcs], np.dot(S[:number_of_pcs, :number_of_pcs], V[:,:number_of_pcs].T))
return X_hat, S, mean_X
这里的变化在于我们想要使用给定数量的特征向量(由
决定)来重建图像。number_of_pcs
要记住的是,在
np.linalg.svd
中,U 的列是 X.X^T 的特征向量。
这样做时,我们获得以下结果(此处使用 1 和 10 主成分显示):
X_hat, S, mean_X = pca(img, 1)
plt.imshow(X_hat)
X_hat, S, mean_X = pca(img, 10)
plt.imshow(X_hat)
PS:请注意,由于 matplotlib.pyplot,图片不会以灰度显示,但这是一个非常小的问题。
锋利的边缘。这就是为什么。如果图像具有锐利边缘或高对比度,则 PCA 无法很好地进行图像压缩。尝试一下咖啡图像,您会看到类似的东西。 将 numpy 导入为 np 将 matplotlib.pyplot 导入为 plt 从skimage导入数据 从 sklearn.decomposition 导入 PCA
灰度图像 = data.coffee()