Python OpenCV PCACompute特征值

ben*_*zzy 6 python opencv eigenvalue pca

当使用带有OpenCV(OSX)的Python 2.7.5时,我在一系列图像上运行PCA(cols是像素,行是按照这个答案的帧.

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

省略PCA这样一个关键部分似乎很奇怪.

ben*_*zzy 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)
Run Code Online (Sandbox Code Playgroud)

(简化假设:行 = 观察值,列 = 变量;并且变量比观察值多得多。在我的情况下,两者都是正确的。)

非常有效。下面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)
Run Code Online (Sandbox Code Playgroud)

在输出结束时可以看到某种精度损失(尽管实际上快速绘制绝对差值并没有显示出不精确的模式)。

57% 的元素具有非零绝对差。
其中,95% 的差异小于 2e-16,平均 AD 为 5.3e-4 - 然而,AD 可能高达 0.059,当您考虑所有特征向量值都在 -0.048 到 0.045 之间时,这个数字很大。 。

有代码PCA::Operator()转换为最大的ctype;另一方面old_eVec是 float32 与我自己生成 float64 的代码相比。值得一提的是,在编译 numpy 时,我遇到了一些与精度相关的错误。

总的来说,精度的损失似乎与低特征值特征向量有关,这又指向舍入误差等。上述实现产生与 PCACompute() 类似的结果,重复了该行为。