PCA 实践 利用 PCA 算法对人脸数据集内所有人进行降维和特征提取 PCA原理解析+代码
數據集
實驗所用到的數據集在下面的鏈接中, 這些數據是來自劍橋大學提供的 AT&T 人臉數據
集,有 40 個人的人臉圖像, 每個人有 10 張不同光照和姿態的照片。
樣例:
地址: http://www.cl.cam.ac.uk/Research/DTG/attarchive/pub/data/att_faces.tar.Z
實驗內容
加載數據集,利用 PCA 算法對數據集內所有人進行降維和特征提取,然后將得到的主
成分特征向量還原成圖像進行觀察。這里可以嘗試采用不同的降維維度 K 進行操作,分別觀
察不同 K 下的特征圖像。
實驗拓展
嘗試對剛降維的特征圖像進行 PCA 逆變換,觀察變換前后的圖像差異
?
數據集中包含了40個文件夾,對應了40個志愿者人臉,每個文件夾中有一個志愿者的人臉的多種狀態。
??????
此處使用相對目錄,依次訪問每個子文件夾,通過在中間過程中輸出圖像的維度,我們觀察到圖像是112x92x3即,長寬分別為112,93,通道數為3。首先,我們先對圖像進行灰度化處理,然后將圖像維度展開成為一列,存入列表。
圖像的height,width=112,92,X代表我們的數據集,是一個400x10304的向量;之所以是400x10304,是因為總共400幅圖像,每個圖像是一個112x92的image,將圖像展開成一個一維向量,維度為1x10304,將400幅圖像組合得到一個400x10304的矩陣。其中Y是數據的標簽。
此處,我們展示試著顯示一組圖像,在文件夾中選取每個子文件夾下的第一個圖像拼合顯示如下:
因為窗口大小限制,此處并沒有顯示完全40副圖像。
其中,對10304個列向量做平均,即對400個人臉圖像的每一個對應像素值做平均,計算均值,得到一個1x10304的向量。并將該向量重新轉化為和原圖像同樣大小的維度,然后顯示出來,如下:
注意,計算協方差矩陣之前,需要先將每個變量減去均值,得到中心化的向量,然后通過使用sklearn中的奇異值分解函數,得到前K個特征向量。
不需要計算協方差矩陣S,同時,在數值上更加精確,因為在計算機存儲中,可能會產生累計誤差。
我們設定閾值為0.95,計算保留的主成分數量。計算代碼如下:
計算得到的K值為111,也就是說,前111個奇異值得到的結果已經能代表90%的情況了,為方便處理,我們此處選取K=100.通過奇異值分解得到Kx10304的變換矩陣,我們可以得到如下十張主成分圖像:
注意:如果使用OpenCV中的imshow函數進行顯示,需要先將數據轉換為np.unit8格式,同時范圍規范化到0-255的范圍(此處使用最大最小值歸一化),而使用matplotlib則不用進行如此操作。
?
規范化及使用OpenCV顯示相關代碼
使用matplotlib顯示相關代碼:
當完成主成分提取之后,我們對圖像進行還原:
其中,U是變換矩陣,還原方式如下:
?????
????? 并輸出30張還原之后的圖像;如下:
???????? 我們可以看到,以上30張圖像分別對應了原始數據集中的3個人的圖像,相比于原來的30張,如今還原得到的圖像丟失了一部分信息,不過不是非常明顯。
源代碼
1. import cv2 2. import tensorflow as tf 3. import numpy as np 4. import matplotlib.pyplot as plt 5. from sklearn.decomposition import TruncatedSVD 6. 7. FACE_PATH = "orl_faces" 8. PERSON_NUM = 40 9. PERSON_FACE_NUM = 10 10. K = 10 # Number of principle components 11. 12. raw_img = [] 13. data_set = [] 14. data_set_label = [] 15. 16. 17. def read_data(): 18. height = 0 19. width = 0 20. for i in range(1, PERSON_NUM + 1): 21. person_path = FACE_PATH + '/s' + str(i) 22. 23. for j in range(1, PERSON_FACE_NUM + 1): 24. img = cv2.imread(person_path + '/' + str(j) + '.pgm') 25. #print(img.shape) 112,92,3 26. if j == 1: 27. raw_img.append(img) 28. img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 29. height, width = img_gray.shape 30. #print(height,width) 31. img_col = img_gray.reshape(height * width) 32. data_set.append(img_col) 33. data_set_label.append(i) 34. 35. return height, width 36. 37. 38. # Import Data 39. height, width = read_data() 40. print(height,width) 41. X = np.array(data_set) 42. #print(X.shape) # 400*10304 43. Y = np.array(data_set_label) 44. #print(Y.shape) 45. n_sample, n_feature = X.shape 46. 47. # Print some samples 48. raw_img = np.hstack(raw_img) 49. cv2.namedWindow("Image") 50. cv2.imshow('Image', raw_img) 51. cv2.waitKey(1) 52. cv2.destroyAllWindows() 53. 54. # 計算均值 A preview of average_face 55. average_face = np.mean(X, axis=0) #對10304個列向量做平均 56. # for i in average_face: 57. # print(i) 58. #num+=1 59. fig = plt.figure() 60. plt.imshow(average_face.reshape((height, width)), cmap=plt.cm.gray) 61. plt.title("Average Face", size=12) 62. plt.xticks(()) 63. plt.yticks(())#不顯示橫縱坐標 64. #plt.savefig("average_face.png") 65. plt.show() 66. 67. # Calculate 68. equalization_X = X - average_face #差值400*10304 69. #計算協方差矩陣 70. 71. covariance_X = np.cov(equalization_X.transpose()) 72. print(covariance_X.shape) 73. print(equalization_X.shape) 74. #特征值分解 使用sklearn中的SVD函數分解 75. svd = TruncatedSVD(n_components=K, random_state=44) 76. svd.fit(equalization_X) 77. 78. # total_variance, n_components = 0.0, 0 79. # for variance in svd.explained_variance_ratio_: 80. # total_variance += variance 81. # n_components += 1 82. # if total_variance > 0.95: break 83. 84. #print(n_components) 9 85. #print(svd.components_.shape) 10*10304 86. print(svd.components_.shape) 87. topk=np.zeros(svd.components_.shape) 88. # for i in range(K): 89. # #print(svd.components_[i]) 90. # topk[i]=255.0*(svd.components_[i]-np.min(svd.components_[i]))/\ 91. # (np.max(svd.components_[i])-np.min(svd.components_[i])) 92. #print(topk[i]) 93. # img=topk[1].reshape(height, width) 94. # img=img.astype(np.uint8) 95. # #print(img.shape) 96. # cv2.imshow('1',img) 97. # cv2.waitKey(0) 98. # cv2.destroyAllWindows() 99. #np.matmul(equalization_X,) 100. # topk=svd.components_+average_face 101. 102. 103. # 打印輸出前K個主成分臉 104. 105. plt.figure() 106. for i in range(1, K + 1): 107. plt.subplot(2, K/2, i) 108. #print(svd.components_[i-1].shape) 109. plt.imshow((svd.components_[i - 1]).reshape(height, width), cmap=plt.cm.gray) 110. #print(svd.components_[i - 1].reshape(height, width)) 111. plt.xticks(()) 112. plt.yticks(()) 113. plt.show() 114. 115. topk=average_face+np.matmul(equalization_X,np.matmul(svd.components_.T,svd.components_)) 116. print(topk.shape) 117. K=30 118. plt.figure() 119. for i in range(1, K + 1): 120. plt.subplot(5, K/5, i) 121. #print(svd.components_[i-1].shape) 122. plt.imshow((topk[i - 1]).reshape(height, width), cmap=plt.cm.gray) 123. #print(svd.components_[i - 1].reshape(height, width)) 124. plt.xticks(()) 125. plt.yticks(()) 126. plt.show()如不知道如何去掉行號,參考個人博文中的解決方案。
總結
以上是生活随笔為你收集整理的PCA 实践 利用 PCA 算法对人脸数据集内所有人进行降维和特征提取 PCA原理解析+代码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: chm文件打不开的问题
- 下一篇: 人脸识别算法一:特征脸方法(Eigenf