我们来分析一下这两个算法的各自特点:
1、PCA(principal component analysis)是一种数据降维的方式,能够有效的将高维数据转换为低维数据,进而降低模型训练所需要的计算资源。
##自适应求K值
import numpy as np
import cv2 as cv
# 数据中心化
def Z_centered(dataMat):
rows, cols = dataMat.shape
meanVal = np.mean(dataMat, axis=0) # 按列求均值,即求各个特征的均值
meanVal = np.tile(meanVal, (rows, 1))
newdata = dataMat - meanVal
return newdata, meanVal
# 最小化降维造成的损失,确定k
def Percentage2n(eigVals, percentage):
sortArray = np.sort(eigVals) # 升序
sortArray = sortArray[-1::-1] # 逆转,即降序
arraySum = sum(sortArray)
tmpSum = 0
num = 0
for i in sortArray:
tmpSum += i
num += 1
if tmpSum >= arraySum * percentage:
return num
# 得到最大的k个特征值和特征向量
def EigDV(covMat, p):
D, V = np.linalg.eig(covMat) # 得到特征值和特征向量
k = Percentage2n(D, p) # 确定k值
print("保留99%信息,降维后的特征个数:" + str(k) + "\n")
eigenvalue = np.argsort(D)
K_eigenValue = eigenvalue[-1:-(k + 1):-1]
K_eigenVector = V[:, K_eigenValue]
return K_eigenValue, K_eigenVector
# 得到降维后的数据
def getlowDataMat(DataMat, K_eigenVector):
return DataMat * K_eigenVector
# 重构数据
def Reconstruction(lowDataMat, K_eigenVector, meanVal):
reconDataMat = lowDataMat * K_eigenVector.T + meanVal
return reconDataMat
# PCA算法
def PCA(data, p):
dataMat = np.float32(np.mat(data))
# 数据中心化
dataMat, meanVal = Z_centered(dataMat)
# 计算协方差矩阵
# covMat = Cov(dataMat)
covMat = np.cov(dataMat, rowvar=0)
# 得到最大的k个特征值和特征向量
D, V = EigDV(covMat, p)
# 得到降维后的数据
lowDataMat = getlowDataMat(dataMat, V)
# 重构数据
reconDataMat = Reconstruction(lowDataMat, V, meanVal)
return reconDataMat
def main():
imagePath = 'photo4.png'
image = cv.imread(imagePath)
image = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
rows, cols = image.shape
print("降维前的特征个数:" + str(cols) + "\n")
print(image)
print('----------------------------------------')
reconImage = PCA(image, 0.6) # 通过改变保留信息的程度来看这个图片的特征值
reconImage = reconImage.astype(np.uint8)
print(reconImage)
cv.imshow('test', reconImage)
cv.waitKey(0)
cv.destroyAllWindows()
if __name__ == '__main__':
main()
运行结果:
保留信息的程度 | 运行结果 |
---|---|
降维前的原图特征个数为:374 | ![]() |
保留90%信息,降维后的特征个数:3 | ![]() |
保留99%信息,降维后的特征个数:35 | ![]() |
保留99.9%信息,降维后的特征个数:109 | ![]() |
我们可以看到:
需要保留的信息程度越高,那么需要的特征值也就越多,图像就越清晰
优缺点:
import numpy as np
import os
from PIL import Image
import matplotlib.pyplot as plt
import matplotlib as mpl
from pprint import pprint
def restore1(sigma, u, v, K): # 奇异值、左特征向量、右特征向量
m = len(u)
n = len(v[0])
a = np.zeros((m, n))
for k in range(K):
uk = u[:, k].reshape(m, 1)
vk = v[k].reshape(1, n)
a += sigma[k] * np.dot(uk, vk)
a[a < 0] = 0
a[a > 255] = 255
return np.rint(a).astype('uint8')
def restore2(sigma, u, v, K): # 奇异值、左特征向量、右特征向量
m = len(u)
n = len(v[0])
a = np.zeros((m, n))
for k in range(K+1):
for i in range(m):
a[i] += sigma[k] * u[i][k] * v[k]
a[a < 0] = 0
a[a > 255] = 255
return np.rint(a).astype('uint8')
if __name__ == "__main__":
A = Image.open("photo4.png", 'r')
print(A)
output_path = r'.\SVD_Output'
if not os.path.exists(output_path):
os.mkdir(output_path)
a = np.array(A)
print(a.shape)
K = 50
u_r, sigma_r, v_r = np.linalg.svd(a[:, :, 0])
u_g, sigma_g, v_g = np.linalg.svd(a[:, :, 1])
u_b, sigma_b, v_b = np.linalg.svd(a[:, :, 2])
plt.figure(figsize=(11, 9), facecolor='w')
mpl.rcParams['font.sans-serif'] = ['simHei']
mpl.rcParams['axes.unicode_minus'] = False
for k in range(1, K+1):
print(k)
R = restore1(sigma_r, u_r, v_r, k)
G = restore1(sigma_g, u_g, v_g, k)
B = restore1(sigma_b, u_b, v_b, k)
I = np.stack((R, G, B), axis=2)
Image.fromarray(I).save('%s\\svd_%d.png' % (output_path, k))
if k <= 12:
plt.subplot(3, 4, k)
plt.imshow(I)
plt.axis('off')
plt.title('奇异值个数:%d' % k)
plt.suptitle('SVD与图像分解', fontsize=20)
plt.tight_layout(0.3, rect=(0, 0, 1, 0.92))
plt.show()
我们可以看到:
使用SVD算法对图片进行降维,随着奇异值个数的增加,很显然图片会越来越清晰。
优缺点: