2014-03-24 31 views
6

Wenn Python 2.7.5 mit OpenCV (OSX), ich laufe PCA auf einer Folge von Bildern (cols sind Pixel, Zeilen sind Frames per this answer.Python OpenCV PCACompute Eigenwert

Wie erhalte ich die Eigenwerte entsprechen zu den Eigenvektoren? Sieht aus wie es eine Eigenschaft des PCA-Objekts in C++ ist, aber der Python äquivalent PCACompute() ist eine einfache Funktion.

seltsam scheinen solch einen wichtigen Teil der PCA zu verzichten.

+0

Ich habe Ihren Code versucht und ähnliche Ergebnisse für einige Bilddaten erhalten, aber der Unterschied zwischen den Eigenvektoren für beide Methoden liegt in der Größenordnung von 1e-9, neben den letzten, für die ich ziemlich niedrige Eigenwerte bekomme. Könnte numerische Präzision sein ... –

+0

Ich bin geneigt zuzustimmen - diese Frage wurde geschrieben, bevor ich mit numerischer Berechnung und Matrixzerlegung vertraut war. – benxyzzy

Antwort

2

matmul.cpp bestätigt PCA::Operator() sein wird verwendet von PCACompute(), aber die Eigenv Werte werden verworfen. Also tat ich dies:

# 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) 

(vereinfachende Annahmen:.. Rows = Beobachtungen, cols = Variablen, und es gibt viel mehr Variablen als Beobachtungen Beide wahr sind in meinem Fall)

Diese ziemlich Werke . Im Folgenden ist old_eVec das Ergebnis von 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) 

Es gibt eine Art von Verlust an Präzision, sichtbar gegen Ende der Ausgänge (obwohl in der Tat schnell Plotten der absoluten Differenz zeigen kein Muster die Ungenauigkeit).

57% der Elemente haben eine absolute Differenz ungleich Null.
Davon unterscheiden sich 95% um weniger als 2e-16 und der mittlere AD um 5,3e-4 - jedoch kann der AD so hoch wie 0,059 sein, was sehr viel ist, wenn man alle Eigenvektorwerte zwischen -0,048 betrachtet bis 0,045.

Es gibt einen Code in PCA::Operator(), der zum größten ctype konvertiert; Auf der anderen Seite old_eVec war float32 im Vergleich zu meinem eigenen Code produziert float64. Es ist erwähnenswert, dass ich beim Kompilieren von numpy einige fehlerbezogene Fehler bekommen habe. Der Verlust der Genauigkeit scheint mit niedrigen Eigenvektoren zu korrelieren, was wiederum auf Rundungsfehler usw. hinweist. Die obige Implementierung erzeugt ähnliche Ergebnisse wie PCACompute(), nachdem sie das Verhalten dupliziert hat.

+0

Große Antwort :) Ich habe jedoch einige relevante Updates gefunden, die Ihr Code benötigt. Flags, die an 'calcCovarMatrix()' übergeben werden, sollten jetzt zum Beispiel die Form 'cv2.COVAR_NORMAL' haben (das cv und CV_ fallen lassen). Außerdem erhält die Methode 'eigen()' nicht länger den Parameter 'computeEigenvectors'; Tatsächlich funktionierte es für mich, ohne irgendwelche Parameter außer der Covar-Matrix hinzuzufügen. Mit diesen Updates konnte ich das erreichen, danke. – DarkCygnus