2014-04-05 38 views
1

我執行臉部識別Principal Component AnalysisPython未做的已使用numpyOpenCV定義PCA方法。但我的結果是字面上的垃圾。主成分分析在Python:解析錯誤

我在OpenCVdoc上閱讀文檔和算法描述。但有些事情並不清楚。

  • 如果X = {x1, x2, ..., xn}那麼我相信它不是計算協方差矩陣時使用的X矩陣嗎?但是,你必須減去平均值等,如前兩步所述。
  • 特徵向量必須按照降序排列的特徵值排序。您是否需要在查看相應特徵值的絕對值時進行排序?無論如何,順序不是主要問題,因爲我繪製了所有的特徵向量,所以我可以相應地重新排列它們。我想我犯了一個分析錯誤。

我實現了以下內容:

MU = X.mean(axis=0) 
for i in range(n): 
    X[i,:] -= MU 

S = (np.dot(X, X.T)/float(n)) 
#Hermitian (or symmetric) matrix. 
eigenvalues, eigenvectors = numpy.linalg.eigh(S) 
eigenvectors = numpy.dot(X.T, eigenvectors) 
for i in range(n): 
    eigenvectors[:,i] = normalize_vector(eigenvectors[:,i]) 

注意,採樣值存儲在行而不是列。所以X的形狀nxdn樣本的數量和d樣本的尺寸。

enter image description here

上述圖像爲基準。首先是平均值,以下三個是最大的特徵向量。 下面的圖片是我的結果。首先是平均值,以下是所有特徵向量的順序。但他們似乎不符合結果。

cv2.PCACompute(X, 6)仍然會產生更好的結果。

回答

1

第一個問題很好回答here

對於第二個答案是你需要根據它們相應的特徵值的值來排序特徵向量。對於這一點,你可以使用Python np.argsort(),然後(從較小argsort以更大的)順序相反:

indexes = np.argsort(eigenvalues)[::-1] 
eigval = eigenvalues[indexes] 
eigvec = eigenvectors[:,indexes] 

檢查你的代碼,我只是發現了幾個問題:

  1. 現在,你得到所有的特徵向量,你忽略了nb_components參數,你應該只採取你所要求的向量。這與

    eigenvectors = eigenvectors[:,indexes][0:nb_components]

  2. 專爲,您使用的for循環,從0到n標準化矢量(PCA函數內),但如果你只要求,讓說,3個特徵向量,你只將有3列。爲了解決它,從0到nb_components迭代。

除此之外,您的代碼完美無缺。我試了一下,只拿到了3個Principals組件,我得到了6/6作爲最終結果。在我看來,顯示特徵向量時的差異僅僅是從float到uint8以使用imshow時的表示問題。

關於負特徵值,它只是eigh的問題。由於特徵值顯示方向上的變化,我們關心絕對值,但如果我們改變符號,我們也必須改變「方向」(特徵向量)。您可以將此乘以負本徵值及其對應的特徵向量與-1.0(見this):

s = np.where(eigenvalues < 0) 
eigenvalues[s] = eigenvalues[s] * -1.0 
eigenvectors[:,s] = eigenvectors[:,s] * -1.0 

您也可以解決這個使用numpy.linalg.svddocs),但應該比numpy.linalg.eigh慢。

綜上所述,這是我從你想出的代碼(應對這裏的時候,把它縮短我刪除所有評論):

def pca(X, nb_components=0): 
    [n,d] = X.shape 
    if (nb_components <= 0) or (nb_components>6): 
     nb_components = n 

    MU = X.mean(axis=0) 
    for i in range(n): 
     X[i,:] -= MU 

    S = (np.dot(X, X.T)/float(n)) 

    eigenvalues, eigenvectors = np.linalg.eigh(S) 

    s = np.where(eigenvalues < 0) 
    eigenvalues[s] = eigenvalues[s] * -1.0 
    eigenvectors[:,s] = eigenvectors[:,s] * -1.0 

    indexes = np.argsort(eigenvalues)[::-1] 
    eigenvalues = eigenvalues[indexes] 
    eigenvectors = eigenvectors[:,indexes][:,0:nb_components] 

    eigenvectors = np.dot(X.T, eigenvectors) 

    for i in range(nb_components): 
     eigenvectors[:,i] = normalize_vector(eigenvectors[:,i]) 

    return (eigenvalues, eigenvectors, MU) 
+0

確定的第一個問題是很好的解釋,但現在我對n或n-1的劃分有點困惑,因爲它們似乎都在某些站點上使用。對於排序,我仍然有負特徵值的問題。我認爲300,-100和1是按300,-100,1排序的,還是按300,1,-100排序?我將嘗試用X.T乘以後得到的特徵向量。 – Matthias

+1

協方差矩陣的計算除以'n',我也看到了一些使用'n-1'的實現,但我無法說出一個理由(我一直使用'n'很長一段時間,結果很好) 。關於負特徵值,你不應該有任何協方差矩陣[Positive Semi-defined](http://en.wikipedia.org/wiki/Covariance_matrix#Properties),那些矩陣只有[positive eigenvalues](http:///www.math.ucsd.edu/~njw/Teaching/Math271C/Lecture_03.pdf)。如果你找不到原因發佈鏈接到你的測試img,我可以嘗試找到更多的東西。 –

+0

https://dl.dropboxusercontent.com/u/69633291/face_recognition.zip你必須把數據文件夾放在你的用戶文件夾中 – Matthias