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

特征分解的缺点

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

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

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

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

  • PS:第一种说法是我根据特征分解的思路去理解svd分解每个矩阵代表的意义,第二种说法是根据另一篇博客的证明思路去理解的。我不知道两种思路是否都正确,欢迎指出错误
  1. 第一种思路 A = U Σ V T A=U\Sigma V^T :从右到左,第一个矩阵代表将从基底I转换到基底V,第二个矩阵代表在V基底下的一定的拉伸,U是一个单位正交矩阵(因为旋转矩阵一定是单位正交矩阵,但是单位旋转矩阵是否是正交矩阵我不确定,假设是吧),那么U的作用便是一个旋转。
  2. 第二种思路 A V = U Σ AV=U\Sigma :等式左边是一个正交基底,经过A的转换到另一个正交基底,同时把拉伸倍数提取出来,则成为了 Σ \Sigma 。从这个角度来说,应该是任何一个矩阵的作用都是对某个基底旋转加拉伸,而可对角化的矩阵的作用刚好是旋转的角度为0,而对角矩阵的基底刚刚好是I,所以作用只是对各个轴上进行拉伸。

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

奇异值分解(SVD)

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

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

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

SVD用到图片上

对角阵 Σ \Sigma 的值代表的是每个方向上分量的值,明显值越大代表的影响就越大,以下是opencv+c++代码

#include <iostream>
#include <opencv2/opencv.hpp>
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);
    }
}

原图
在这里插入图片描述

一个奇异值的时候的效果
在这里插入图片描述
10%奇异值的效果
在这里插入图片描述

20%奇异值效果,可以看到20%效果已经挺不错了,就是噪点比较多
在这里插入图片描述
50%的奇异值已经是只有很细微的噪点了
在这里插入图片描述

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

猜你喜欢

转载自blog.csdn.net/Dang_boy/article/details/85118516