2014-03-24 106 views
6

当使用Python 2.7.5与OpenCV的(OSX),我的图像序列运行PCA(COLS是像素,行是帧按this answerPython的OpenCV的PCACompute特征值

如何获得相应的特征值该特征向量?看起来像它在C++中PCA对象的属性,但是Python的等价PCACompute()是一个简单的函数。

觉得奇怪,省略PCA的这样一个重要组成部分。

+0

我曾尝试过您的代码,并且在某些图像数据上得到了类似的结果,但这两种方法的特征向量之间的差异大约为1e-9,除了那些最后得到的特征值非常低的特征向量之外。可能是数值精度... –

+0

我倾向于同意 - 这个问题是在我熟悉数值计算和矩阵分解之前发布的。 – benxyzzy

回答

2

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_eVeccv2.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()的结果,重复了这种行为。

+0

伟大的答案:)但是我发现你的代码需要一些相关的更新。传递给'calcCovarMatrix()'的标志现在应该是'cv2.COVAR_NORMAL'形式(丢弃cv和CV_)。此外,方法'eigen()'不再接收'computeEigenvectors'参数;事实上,它对我而言没有添加任何参数,只有covar矩阵。有了这些更新,我能够实现这一点,谢谢。 – DarkCygnus