OpenCV  4.10.0
开源计算机视觉库
加载中...
搜索中...
无匹配结果
主成分分析 (PCA) 简介

上一教程: 用于非线性可分离数据的支持向量机

原作者Theodore Tsesmelis
兼容性OpenCV >= 3.0

目标

在本教程中,您将学习如何

  • 使用 OpenCV 类 cv::PCA 计算物体的方向。

什么是 PCA?

主成分分析 (PCA) 是一种统计程序,用于提取数据集的最重要特征。

假设您有一组 2D 点,如上图所示。每个维度对应于您感兴趣的特征。这里有人可能会争辩说这些点是随机排列的。但是,如果您仔细观察,您会看到一条线性模式(由蓝线表示),很难忽视。PCA 的一个关键点是降维。降维是减少给定数据集维数的过程。例如,在上面的情况下,可以将点集近似为一条直线,因此将给定点的维数从 2D 降低到 1D。

此外,您还可以看到,与沿着特征 1 或特征 2 轴的变化相比,点沿着蓝线变化更大。这意味着如果您知道点沿着蓝线的坐标,那么您将获得比仅知道它在特征 1 轴或特征 2 轴上的位置更多的信息。

因此,PCA 使我们能够找到数据变化最大的方向。事实上,在点集图中运行 PCA 的结果包含两个称为特征向量的向量,它们是数据集的主成分

每个特征向量的尺寸在相应的特征值中编码,并表示数据沿着主成分变化的程度。特征向量的起点是数据集中所有点的中心。将 PCA 应用于 N 维数据集会产生 N 个 N 维特征向量、N 个特征值和 1 个 N 维中心点。理论足够了,让我们看看如何将这些想法应用到代码中。

如何计算特征向量和特征值?

目标是将给定维度为p的数据集X转换为维度为L的替代数据集Y。等效地,我们正在寻找矩阵Y,其中Y是矩阵X卡尔洪-洛夫变换 (KLT)

\[ \mathbf{Y} = \mathbb{K} \mathbb{L} \mathbb{T} \{\mathbf{X}\} \]

组织数据集

假设您的数据包含一组对p个变量的观测结果,并且您希望减少数据,以便每个观测结果可以用L个变量来描述,L < p。进一步假设,数据排列成一组n个数据向量\( x_1...x_n \),每个\( x_i \)代表p个变量的单个分组观测结果。

  • 将\( x_1...x_n \)写成行向量,每个向量都有p列。
  • 将行向量放入一个尺寸为\( n\times p \)的矩阵X中。

计算经验均值

  • 找到每个维度\( j = 1, ..., p \)的经验均值。
  • 将计算出的均值放入一个尺寸为\( p\times 1 \)的经验均值向量u中。

    \[ \mathbf{u[j]} = \frac{1}{n}\sum_{i=1}^{n}\mathbf{X[i,j]} \]

计算与均值的偏差

均值减法是找到最小化数据近似均方误差的主成分基的解决方案中不可或缺的一部分。因此,我们通过以下方式对数据进行中心化

  • 从数据矩阵X的每一行中减去经验均值向量u
  • 将均值减去的数据存储在\( n\times p \)矩阵B中。

    \[ \mathbf{B} = \mathbf{X} - \mathbf{h}\mathbf{u^{T}} \]

    其中h是一个所有元素均为 1 的\( n\times 1 \)列向量

    \[ h[i] = 1, i = 1, ..., n \]

找到协方差矩阵

  • 从矩阵B与其自身的外部积中找到\( p\times p \)经验协方差矩阵C

    \[ \mathbf{C} = \frac{1}{n-1} \mathbf{B^{*}} \cdot \mathbf{B} \]

    其中 * 是共轭转置运算符。请注意,如果 B 完全由实数构成,这在许多应用中都是这种情况,则“共轭转置”与常规转置相同。

找到协方差矩阵的特征向量和特征值

  • 计算特征向量矩阵V,它可以对协方差矩阵C进行对角化

    \[ \mathbf{V^{-1}} \mathbf{C} \mathbf{V} = \mathbf{D} \]

    其中DC的特征值的对角矩阵。

  • 矩阵D将采用一个\( p \times p \)对角矩阵的形式

    \[ D[k,l] = \left\{\begin{matrix} \lambda_k, k = l \\ 0, k \neq l \end{matrix}\right. \]

    这里,\( \lambda_j \)是协方差矩阵C的第j个特征值

  • 矩阵V,也为p x p维,包含p个列向量,每个向量长度为p,它们代表协方差矩阵Cp个特征向量。
  • 特征值和特征向量是有序且配对的。第j个特征值对应于第j个特征向量。
注意
来源 [1][2],特别感谢 Svetlin Penkov 提供的原始教程。

源代码

注意
另一个使用 PCA 进行降维,同时保持一定方差的例子可以在 opencv_source_code/samples/cpp/pca.cpp 中找到。

解释

  • 读取图像并将其转换为二进制

这里我们应用必要的预处理过程,以便能够检测感兴趣的目标。

  • 提取感兴趣的目标

然后找到并按大小过滤轮廓,并获得剩余轮廓的方向。

  • 提取方向

方向是通过调用 getOrientation() 函数提取的,该函数执行所有 PCA 程序。

首先,需要将数据排列在一个大小为 n x 2 的矩阵中,其中 n 是我们拥有的数据点的数量。然后我们可以执行 PCA 分析。计算的平均值(即质心)存储在 cntr 变量中,特征向量和特征值存储在相应的 std::vector 中。

  • 可视化结果

最终结果通过 drawAxis() 函数可视化,其中主成分用线条绘制,每个特征向量乘以其特征值并平移到平均位置。

结果

代码打开图像,找到检测到的感兴趣对象的方位,然后通过绘制检测到的感兴趣对象的轮廓、中心点以及提取方位后的 x 轴、y 轴来可视化结果。