2014-03-24 7 views
6

OpenCV의 (OSX) 파이썬 2.7.5를 사용하는 경우, 나는 일련의 이미지에 PCA를 실행 (COLS 픽셀은 행은 프레임 this answer에 따라 있습니다.파이썬 OpenCV의 PCACompute 고유치

나는 고유은 해당 얻는 방법 그것은 C++에서 PCA 개체의 속성은, 그러나 동등한 파이썬 PCACompute() 간단한 기능처럼 고유 벡터에? 같습니다.

는 PCA의 이러한 중요한 부분을 생략하는 이상한 것 같다.

+0

나는 당신의 코드를 시도해 보았고 어떤 이미지 데이터에서 비슷한 결과를 얻었지만, 두 방법 모두에 대한 고유 벡터 간의 차이는 꽤 낮은 고유 값을 얻은 마지막 것들 외에 1e-9의 순서이다. 수치 정밀도 일 수 있습니다 ... –

+0

나는 동의하고 싶습니다.이 질문은 수치 계산과 행렬 분해에 익숙하지 않은 채 게시되었습니다. – benxyzzy

답변

2

matmul.cppPCA::Operator()가되고있는 확인 PCACompute()에 의해 사용되었지만, eigenv 경고는 무시됩니다.

거의 작품;

# 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 = 변수 가정을 단순화 :) 그래서 이런 짓을 . 출력의 단부를 향해 표시 정밀도의 손실의 일종이있다

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) 

(비록 절대 차의 사실 빠른 묘화가 부정확에 어떤 패턴을 보여준다 없음) : 이하, old_eVeccv2.PCACompute()의 결과이다.

요소의 57 %가 0이 아닌 절대 차를 갖습니다.
이들 중 95 %는 2e-16 미만이고 평균 AD는 5.3e-4입니다. 그러나 AD는 0.059로 높을 수 있습니다. 모든 고유 벡터 값이 -0.048 ~ 0.045.

PCA::Operator()에는 가장 큰 ctype로 변환되는 코드가 있습니다. 반면에 old_eVec은 float32를 생성하는 내 코드와 비교하여 float32였습니다. numpy를 컴파일 할 때 몇 가지 정밀도 관련 오류가 있다는 것을 언급 할 가치가 있습니다.

전반적으로 정밀도의 손실은 반올림 오류 등을 다시 지적하는 고유치가 낮은 고유 벡터와 관련이있는 것으로 보입니다. 위의 구현은 PCACompute()와 유사한 결과를 생성하여 동작을 복제했습니다.

+0

Great Answer :) 그러나 코드에 필요한 몇 가지 관련 업데이트를 발견했습니다. 'calcCovarMatrix()'에 전달 된 플래그는 이제'cv2.COVAR_NORMAL'의 형태 여야합니다 (예 : cv와 CV_를 버림). 또한,'eigen()'메소드는 더 이상'computeEigenvectors' 매개 변수를 수신하지 않습니다; 실제로 매개 변수를 추가하지 않고도 covar 행렬을 사용하면 저에게 효과적이었습니다. 그 업데이트로 나는 이것을 성취 할 수있었습니다. 고마워요. – DarkCygnus