奇异值分解的理解与oepncv代码

特征分解的缺点

特征分解的推导与意义与opencv代码在上一篇博客中介绍了特征分解的原理和推导,特征分解在一定的情况下可以很好的分解(实对称矩阵),但是也有很大的局限性

1. 只能对可对角化的方阵使用
2. 在可以对角化的情况下,特征向量之间也不一定相互正交

为了克服这些缺点,我们便在寻找对一个任意的M*N的矩阵都能找到一个类似特征分解的公式(以下的是我的理解,如果有错欢迎指出):

1.特征分解所干的事情:将在以I为基底的情况下,转换到以特征向量为基底的表示方法,并且将之在特征向量的方向上进行特征值倍的拉伸,最终再转换回以I为基底的表示方法。换一个说法就是一个可以对角化的矩阵A的作用便是:对一个基底进行拉伸,即 A P = P Λ AP=P\Lambda AP=PΛ
2.我们在寻找的对任意矩阵都适用的类似的方法:由于不是所有矩阵都可以找到一个基底,并且对这个基底进行拉伸一定倍数便等于A的效果,例如,P不存在逆的情况。此时我们的目标变成将在以I为正交基底的情况下,转换到另一个正交基底,再拉伸一定倍数再旋转一定的角度(在特征分解里映射到原来的基底I可以看成是旋转一个比较特殊的角度),所产生的效果和与矩阵A直接相乘的效果是一样的。换一个说法就是将一个单位正交基底经过A的映射到另一个正交基底,将拉伸的倍数提取出来,使新基底仍然是单位基底。

  • PS:第一种说法是我根据特征分解的思路去理解svd分解每个矩阵代表的意义,第二种说法是根据另一篇博客的证明思路去理解的。我不知道两种思路是否都正确,欢迎指出错误
  1. 第一种思路 A = U Σ V T A=U\Sigma V^T A=UΣVT:从右到左,第一个矩阵代表将从基底I转换到基底V,第二个矩阵代表在V基底下的一定的拉伸,U是一个单位正交矩阵(因为旋转矩阵一定是单位正交矩阵,但是单位正交矩阵是否是旋转矩阵我不确定,假设是吧),那么U的作用便是一个旋转。
    举个例子来验证我的思路(如果不知道SVD具体的公式的话,可以先看下面的推导再回来看这部分的验证),不认识旋转矩阵可以戳这里,假设我将在I基底下的一个变量 x ⃗ \vec{x} x 在x方向拉伸a倍,在y方向拉伸b倍,再绕着z轴旋转 θ \theta θ,那么对应的变换应该是
    [ c o s θ − s i n θ s i n θ c o s θ ] [ a 0 0 b ] [ x   y ] T \begin{bmatrix} cos\theta & -sin\theta \\ sin\theta & cos\theta \\ \end{bmatrix} \begin{bmatrix} a & 0 \\ 0 & b \\ \end{bmatrix}[x \ y]^T [cosθsinθsinθcosθ][a00b][x y]T
    将左侧的矩阵合成一个变换
    T = [ c o s θ − s i n θ s i n θ c o s θ ] [ a 0 0 b ] = [ a c o s θ − b s i n θ a s i n θ b c o s θ ] T=\begin{bmatrix} cos\theta & -sin\theta \\ sin\theta & cos\theta \\ \end{bmatrix} \begin{bmatrix} a & 0 \\ 0 & b \\ \end{bmatrix}= \begin{bmatrix} acos\theta & -bsin\theta \\ asin\theta & bcos\theta \\ \end{bmatrix} T=[cosθsinθsinθcosθ][a00b]=[acosθasinθbsinθbcosθ]
    如果我们的理解是正确的化,那么对T矩阵进行SVD分解,得到的结果应该是
    T = U Σ V T = [ c o s θ − s i n θ s i n θ c o s θ ] [ a 0 0 b ] [ 1 0 0 1 ] T=U\Sigma V^T=\begin{bmatrix} cos\theta & -sin\theta \\ sin\theta & cos\theta \\ \end{bmatrix} \begin{bmatrix} a & 0 \\ 0 & b \\ \end{bmatrix} \begin{bmatrix} 1 & 0 \\ 0 & 1 \\ \end{bmatrix} T=UΣVT=[cosθsinθsinθcosθ][a00b][1001]
    接下来进行验证
    T T T = [ a c o s θ a s i n θ − b s i n θ b c o s θ ] [ a c o s θ − b s i n θ a s i n θ b c o s θ ] = [ a 2 0 0 b 2 ] T^TT=\begin{bmatrix} acos\theta & asin\theta \\ -bsin\theta & bcos\theta \\ \end{bmatrix}\begin{bmatrix} acos\theta & -bsin\theta \\ asin\theta & bcos\theta \\ \end{bmatrix}=\begin{bmatrix} a^2 & 0 \\ 0 & b^2 \\ \end{bmatrix} TTT=[acosθbsinθasinθbcosθ][acosθasinθbsinθbcosθ]=[a200b2]
    容易计算得到,特征值与特征向量为( λ 1 = a 2 , v 1 = [ 1   0 ] T ; λ 2 = b 2 , v 2 = [ 0   1 ] T \lambda_1=a^2,v_1=[1 \ 0]^T;\lambda_2=b^2,v_2=[0 \ 1]^T λ1=a2,v1=[1 0]T;λ2=b2,v2=[0 1]T)
    可以看到 V = [ 1 0 0 1 ] V=\begin{bmatrix} 1 & 0 \\ 0 & 1 \\ \end{bmatrix} V=[1001], Σ = [ a 0 0 b ] \Sigma=\begin{bmatrix} a & 0 \\ 0 & b \\ \end{bmatrix} Σ=[a00b],
    U = T V [ 1 a 0 0 1 b ] = [ a c o s θ − b s i n θ a s i n θ b c o s θ ] [ 1 a 0 0 1 b ] = [ c o s θ − s i n θ s i n θ c o s θ ] U=TV\begin{bmatrix} \frac{1}{a} & 0 \\ 0 & \frac{1}{b} \\ \end{bmatrix}= \begin{bmatrix} acos\theta & -bsin\theta \\ asin\theta & bcos\theta \\ \end{bmatrix}\begin{bmatrix} \frac{1}{a} & 0 \\ 0 & \frac{1}{b} \\ \end{bmatrix} =\begin{bmatrix} cos\theta & -sin\theta \\ sin\theta & cos\theta \\ \end{bmatrix} U=TV[a100b1]=[acosθasinθbsinθbcosθ][a100b1]=[cosθsinθsinθcosθ]
    验证正确。
  2. 第二种思路 A V = U Σ AV=U\Sigma AV=UΣ:等式左边是一个正交基底,经过A的转换到另一个正交基底,同时把拉伸倍数提取出来,则成为了 Σ \Sigma Σ。从这个角度来说,应该是任何一个矩阵的作用都是对某个基底旋转加拉伸,而可对角化的矩阵的作用刚好是拉伸而并不旋转。

其实svd正是在做这么一件事情,以下的推导用第二种思路(毕竟是看别人博客的)。

奇异值分解(SVD)

将奇异分解所做的事情写成数学表达式,即为 A V = U Σ AV=U\Sigma AV=UΣV是一个正交基底,U也是一个正交基底, Σ \Sigma Σ是一个对角阵,对角线上的值为U里的每个列向量的拉伸倍数。我们的目标就是找到 V , U , Σ V,U,\Sigma V,U,Σ这个三个矩阵。
接下来寻找一下这三个矩阵

1. 具体怎么选取正交基底V我也不太清楚,不过前人已经帮我们找到了,就是 A T A A^TA ATA的单位特征向量
V = [ v 1   v 2 …   v 3 ] V=[v_1 \ v_2 …\ v_3] V=[v1 v2 v3] A T A v j = λ j v j , ∣ v i ∣ = 1 A^TAv_j=\lambda_j v_j,|v_i|=1 ATAvj=λjvjvi=1),并且各个列向量都是正交的(因为 A T A A^TA ATA是一个实对称阵),即 v i T v j = 0 v_i^Tv_j=0 viTvj=0
2. 则A矩阵会将这组基底映射成 A V = [ A v 1   A v 2 … A v n ] AV=[Av_1 \ Av_2…Av_n] AV=[Av1 Av2Avn],映射后的各个列向量依然是正交的,即 ( A v i ) T ( A v j ) = v i T A T A v j = λ j v i T v j = 0 (Av_i)^T(Av_j)=v_i^TA^TAv_j=\lambda_j v_i^T v_j=0 (Avi)T(Avj)=viTATAvj=λjviTvj=0
3.到此,我们已经证明了AV的基底也是正交的,即U的每一列都是正交的,即 u i T u j = 0 。 u_i^Tu_j=0。 uiTuj=0接下来是将U给单位化,因为我们的目的是得到单位正交基底。
已知 ( A v i ) T ( A v i ) = ∣ A v i ∣ 2 (Av_i)^T(Av_i)=| Av_i |^2 (Avi)T(Avi)=Avi2
( A v i ) T ( A v i ) = v i T A T A v i = λ i v i T v i = λ i (Av_i)^T(Av_i)=v_i^TA^TAv_i=\lambda_i v_i^T v_i=\lambda_i (Avi)T(Avi)=viTATAvi=λiviTvi=λi
可以得到 ∣ A v i ∣ = λ i = σ i | Av_i |=\sqrt{\lambda_i}=\sigma_i Avi=λi =σi
则令 A v i = σ i u i Av_i=\sigma_iu_i Avi=σiui(由于 A v i Av_i Avi的模长与 σ \sigma σ相等,则 u i u_i ui一定为与 A v i Av_i Avi同方向的单位向量),可以解得 u i = 1 σ i A v i u_i=\frac{1}{\sigma_i}Av_i ui=σi1Avi

将上面的内容整理一下便得到了svd分解的公式 A = U Σ V T A=U\Sigma V^T A=UΣVT
其中V为 A T A A^TA ATA的特征向量所组成的矩阵, Σ \Sigma Σ是一个对角阵,且对角线上的值为 λ i \sqrt{\lambda_i} λi , U = [ u 1 u 2 … u n ] U=[u_1 u_2…u_n] U=[u1u2un]
如果A是一个m×n的矩阵,那么V是n×n的正交矩阵,U是m×m的正交矩阵, Σ \Sigma Σ是m×n的对角阵,多余的位置用0去补充。

虽然理论上来说,按照上面的计算来说,V是一个n×n的正交阵,U是一个m×n的矩阵, Σ \Sigma Σ是一个n×n的对角阵,但是定义上是把A当成一个m×n的矩阵,V当成一个n×n的矩阵, Σ \Sigma Σ当成一个 m×n的矩阵,这就导致需要进行一些操作了。
当m>n的时候需要给U补上m-n个列向量,理论上可以补0向量,但是会导致U不是正交矩阵,所以可以补上与其他向量正交的单位向量,在 Σ \Sigma Σ下面也要补上m-n行0
当m Σ \Sigma Σ则要舍弃后面n-m个行向量。

k=rank(A),则对 A T A A^TA ATA计算特征向量,会发现它只有k个特征值不为0(我不知道怎么证明,我猜得)
奇异值分解的理解与oepncv代码_第1张图片

SVD用到图片上

对角阵 Σ \Sigma Σ的值代表的是每个方向上分量的值,明显值越大代表的影响就越大,一般来说如果将特征值按从大到小排列,那么前面的几个特征值已经占了绝大部分的能量,接下来用图片来展示,以下是opencv+c++代码

#include 
#include 
using namespace std;
using namespace cv;
int main(int argc, char const* argv[])
{
    if (argc != 2) {
        cout << "error" << endl
             << "./matrixFeature pic" << endl;
        return -1;
    }
    Mat pic = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
    pic.convertTo(pic, CV_64FC1, 1 / 255.0);
    Mat w, U, Vt;
    SVD::compute(pic, w, U, Vt);
    Mat W(w.rows, w.rows, w.type(), cv::Scalar(0));
    for (int i = 0; i < w.rows; i++) {
        W.at<double>(i, i) = w.at<double>(i);
        Mat svd_pic = U * W * Vt;
        imshow("svd", svd_pic);
        cout << i * 1.0 / w.rows * 100 << "%" << endl;
        waitKey(30);
        waitKey(0);
    }
}

原图
奇异值分解的理解与oepncv代码_第2张图片

一个奇异值的时候的效果
奇异值分解的理解与oepncv代码_第3张图片
10%奇异值的效果
奇异值分解的理解与oepncv代码_第4张图片

20%奇异值效果,可以看到20%效果已经挺不错了,就是噪点比较多
奇异值分解的理解与oepncv代码_第5张图片
50%的奇异值已经是只有很细微的噪点了
奇异值分解的理解与oepncv代码_第6张图片

PS:在用opencv或者Eigen求解矩阵A(m x n)的svd的时候会发现
设k=min{m,n},会发现 V T V^T VT的尺寸为k x n
U的尺寸为m*k, Σ \Sigma Σ是一个k x k的矩阵

其实本质上是一样的,只是没有补充成为上面规定的尺寸而已

参考:奇异值分解(SVD)原理

你可能感兴趣的:(SLAM)