當使用Python 2.7.5與OpenCV的(OSX),我的圖像序列運行PCA(COLS是像素,行是幀按this answer。Python的OpenCV的PCACompute特徵值
如何獲得相應的特徵值該特徵向量?看起來像它在C++中PCA對象的屬性,但是Python的等價PCACompute()
是一個簡單的函數。
覺得奇怪,省略PCA的這樣一個重要組成部分。
當使用Python 2.7.5與OpenCV的(OSX),我的圖像序列運行PCA(COLS是像素,行是幀按this answer。Python的OpenCV的PCACompute特徵值
如何獲得相應的特徵值該特徵向量?看起來像它在C++中PCA對象的屬性,但是Python的等價PCACompute()
是一個簡單的函數。
覺得奇怪,省略PCA的這樣一個重要組成部分。
matmul.cpp證實PCA::Operator()
正在使用PCACompute()
,但特徵線索被丟棄。所以我這樣做:
# The following mimics PCA::operator() implementation from OpenCV's
# matmul.cpp() which is wrapped by Python cv2.PCACompute(). We can't
# use PCACompute() though as it discards the eigenvalues.
# Scrambled is faster for nVariables >> nObservations. Bitmask is 0 and
# therefore default/redundant, but included to abide by online docs.
covar, mean = cv2.calcCovarMatrix(PCAInput, cv2.cv.CV_COVAR_SCALE |
cv2.cv.CV_COVAR_ROWS |
cv2.cv.CV_COVAR_SCRAMBLED)
eVal, eVec = cv2.eigen(covar, computeEigenvectors=True)[1:]
# Conversion + normalisation required due to 'scrambled' mode
eVec = cv2.gemm(eVec, PCAInput - mean, 1, None, 0)
# apply_along_axis() slices 1D rows, but normalize() returns 4x1 vectors
eVec = numpy.apply_along_axis(lambda n: cv2.normalize(n).flat, 1, eVec)
(簡化的假設:。行數=觀測的cols =變量,並有更多的變數比觀察兩者都是在我的情況屬實)
這非常作品。在下文中,old_eVec
是cv2.PCACompute()
結果:
In [101]: eVec
Out[101]:
array([[ 3.69396088e-05, 1.66745325e-05, 4.97117583e-05, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
[ -7.23531536e-06, -3.07411122e-06, -9.58259793e-06, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
[ 1.01496237e-05, 4.60048715e-06, 1.33919606e-05, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
...,
[ -1.42024751e-04, 5.21386198e-05, 3.59923394e-04, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
[ -5.28685812e-05, 8.50139472e-05, -3.13278542e-04, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
[ 2.96546917e-04, 1.23437674e-04, 4.98598461e-04, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00]])
In [102]: old_eVec
Out[102]:
array([[ 3.69395821e-05, 1.66745194e-05, 4.97117981e-05, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
[ -7.23533140e-06, -3.07411415e-06, -9.58260534e-06, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
[ 1.01496662e-05, 4.60050160e-06, 1.33920075e-05, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
...,
[ -1.42029530e-04, 5.21366564e-05, 3.60067672e-04, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
[ -5.29163444e-05, 8.50261567e-05, -3.13150231e-04, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
[ -7.13724992e-04, -8.52700090e-04, 1.57953508e-03, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00]], dtype=float32)
有某種精密的損失,向產出的最終可見的(雖然實際上絕對差的快速繪製顯示無圖案的不精確)。
57%的元素具有非零絕對差異。
其中,95%相差小於2e-16,平均AD值爲5.3e-4 - 然而,AD可高達0.059,當您考慮所有特徵向量值介於-0.048到0.045。
代碼PCA::Operator()
轉換爲最大的ctype;另一方面old_eVec
是float32與我自己的代碼生成float64比較。值得一提的是,在編譯numpy時,我得到了一些與精度有關的錯誤。
總的來說,精度的損失似乎與低特徵值特徵向量有關,它們又指向舍入誤差等。上述實現產生類似於PCACompute()的結果,重複了這種行爲。
偉大的答案:)但是我發現你的代碼需要一些相關的更新。傳遞給'calcCovarMatrix()'的標誌現在應該是'cv2.COVAR_NORMAL'形式(丟棄cv和CV_)。此外,方法'eigen()'不再接收'computeEigenvectors'參數;事實上,它對我而言沒有添加任何參數,只有covar矩陣。有了這些更新,我能夠實現這一點,謝謝。 – DarkCygnus
我曾嘗試過您的代碼,並且在某些圖像數據上得到了類似的結果,但這兩種方法的特徵向量之間的差異大約爲1e-9,除了那些最後得到的特徵值非常低的特徵向量之外。可能是數值精度... –
我傾向於同意 - 這個問題是在我熟悉數值計算和矩陣分解之前發佈的。 – benxyzzy