精华内容
下载资源
问答
  • 线性代数:矩阵变换-投影变换

    千次阅读 2019-12-09 23:35:31
  • 之前我们学习了“顶点机器”变换顶点的一系列过程,其中就谈到了从眼睛空间到裁剪空间的裁剪变换,这篇我们就来学着推导一下这个裁剪变换,毕竟假如我们对于计算机知识只是像看小说看新闻一样,那其实没什么用,前...

    转载:https://blog.csdn.net/yinhun2012/article/details/80336487

            之前我们学习了“顶点机器”变换顶点的一系列过程,其中就谈到了从眼睛空间到裁剪空间的裁剪变换,这篇我们就来学着推导一下这个裁剪变换,毕竟假如我们对于计算机知识只是像看小说看新闻一样,那其实没什么用,前一秒看完后一秒就忘记了。要亲自用纸和笔推导和多遍仔细阅读的记忆才能保证掌握了这个知识点。

            首先我们来观察下我们要变换的眼睛仿射空间和裁剪仿射空间是个什么样子的,如下图:

            

            咋一看就是near面伸缩到22的正方形,far面也伸缩成22的正方形,同时near和far面的距离伸缩到数值2的范围内,然后绕X轴180°逆时针旋转到Z轴反向(或者绕Y轴逆时针180°),最后平移到坐标系中心就得到结果了。

            但是其中美中不足的地方就是near面和far面都处于在XY平面而且缩放后的大小都是22,也就是说near和far缩放不均匀,那么我们并不能用一个缩放矩阵搞定,这样的话我们必须推导出新的矩阵求解near和far以及其距离变换成222的立方体。

            前面我们学习矩阵推导的时候,也了解到求解矩阵参数,无非是在矩阵T向量V = 向量V’的情况下,建立T和V的行列相乘=V’的分量的n元一次方程组,然后通过各种数学方法(三角函数几何向量等)预先得到向量V和向量V’,再反过来推导矩阵T的参数。如此一来我们就先来求出起码一对眼睛仿射空间和裁剪仿射空间的映射向量。先来随便取一个眼睛视椎体内的顶点坐标P(x,y,z),然后通过边视图和顶视图来观察,如下图:

            

            ps:其中t(top)代表near面y轴正方向长度,b(bottom)代表y轴负方向长度,l(left)代表near面x轴负方向长度,r(right)代表near面x轴正方向长度,n(N)代表near面到坐标中心距离,f(F)代表far面到坐标中心距离。

            我们先假设视椎体中有一点P,然后求出P点在视椎体near面的投影点P’,为什么要求出P’呢?主要是为了通过间接方式求出裁剪立方体空间near面上投影点Pv’,这样我们就得到最终映射点Pv的x,y分量,同时通过near面到far面的Z轴坐标插值求出depth[-1,1]区间的z值,进而得到最终P的映射点Pv(x,y,z)。接下来我们继续从裁剪立方体的near面观察同时从边视图观察得到depth,如下图:

            

            上图我们通过插值计算出裁剪空间near面投影点Pv’的x、y分量,然后通过裁剪空间边视图计算出z(depth[-1,1])分量,然后组装出眼睛空间中P(x,y,z)的变换映射点Pv(Xv,Yv,Zv)。这时候我们就已经准备好了求解裁切矩阵T的两个已知量了。

            接下来我们怎么构建变换矩阵T呢?其实还是通过线性方程组,同时我们还能直接得到观察线性方程组的参数值,如下图:

            

            这里我们就算出了裁剪矩阵T的具体数值了,别急,我们还没结束,这里先抛出两个问题:

            第一:我们还没使用程序计算推导的结果是否正确呢?这是因为篇幅长了点,我准备下一篇立刻开始根据这篇的计算结果进行程序验证!

            第二:我们可以观察到推导出的矩阵T的数值中居然带有P(x,y,z)的z分量,这可是一个未知值!虽然我们程序可以直接传入z的值,但是这种矩阵并没有完全的“解耦”,我们写程序都追求低耦合,这里别慌,等我们验证完这个矩阵的正确性之后,我再使用fov(field of view)这个参数进行新的换算推导,得到新的“解耦”后的矩阵T。



    展开全文
  • 紧接上一篇:https://blog.csdn.net/yinhun2012/article/details/80336487 之前我们推导完裁剪变换的矩阵T,这次我们就来对该矩阵T进行程序验证和演示,毕竟加入我们 ...

    紧接上一篇:https://blog.csdn.net/yinhun2012/article/details/80336487
      之前我们推导完裁剪变换的矩阵T,这次我们就来对该矩阵T进行程序验证和演示,毕竟我们学习图形学就是用来写程序的,把学到的知识最终使用到程序上,才是最终目标。
      接下来就让我们打开unity开始编写代码,首先要做的就是创建一个视椎体模型了,因为我们要形象观察眼睛空间,当然我又不是美术,3dmax又不会用,只能用程序去创建了,这里可以看一下unity自带的camera的视椎体,如下图:
    camera_frustum
      大概就是这么个样子,前面画图小伙伴们大致也了解过了,这里我继续描绘一下我们大致要创建的模型网格的顶点坐标和拓扑信息等参数,如下图:
    draw_frustum
      这里我标注好了顶点名和拓扑三角标号(这里提示:n(near) f(far) b(bottom) t(top) r(right) l(left)那么,比如nbl就是near面的左下角),接下来就写c#代码创建一个frustum_mesh,代码如下:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    [ExecuteInEditMode]
    public class TestFrustumMesh : MonoBehaviour
    {
    
        //构建视椎体的基本参数
        float _Near = 3.0f;
        float _Far = 10.0f;
        float _L = -4.0f;
        float _R = 4.0f;
        float _T = 3.0f;
        float _B = -3.0f;
        //创建的网格
        Mesh mMesh;
    
        void Start()
        {
            CreateFrustumMesh();
        }
    
        void CreateFrustumMesh()
        {
            //构建视椎体near四个顶点和far面四个顶点
            float far2near = _Far / _Near;
            //这里我们按照逆时针排序顶点
            Vector3 nbl = new Vector3(_L, _B, _Near);
            Vector3 nbr = new Vector3(_R, _B, _Near);
            Vector3 ntr = new Vector3(_R, _T, _Near);
            Vector3 ntl = new Vector3(_L, _T, _Near);
            //这里我们按照逆时针排序顶点
            Vector3 fbl = new Vector3(_L * far2near, _B * far2near, _Far);
            Vector3 fbr = new Vector3(_R * far2near, _B * far2near, _Far);
            Vector3 ftr = new Vector3(_R * far2near, _T * far2near, _Far);
            Vector3 ftl = new Vector3(_L * far2near, _T * far2near, _Far);
            mMesh = new Mesh();
            Vector3[] vertices = new Vector3[8] {
                   nbl,
                   nbr,
                   ntr,
                   ntl,
                   fbl,
                   fbr,
                   ftr,
                   ftl
            };
            int[] triangles = new int[] {
                   0,1,2,
                   0,2,3,
                   0,1,5,
                   0,5,4,
                   1,5,6,
                   1,6,2,
                   2,6,7,
                   2,7,3,
                   0,3,7,
                   0,7,4,
                   4,5,6,
                   4,6,7,
            };
            Vector2[] uvs = new Vector2[8]
            {
                new Vector3(0, 0),
                new Vector3(1, 0),
                new Vector3(0, 1),
                new Vector3(1, 1),
                new Vector3(0, 0),
                new Vector3(1, 0),
                new Vector3(0, 1),
                new Vector3(1, 1),
            };
            mMesh.vertices = vertices;
            mMesh.triangles = triangles;
            mMesh.uv = uvs;
            GetComponent<MeshFilter>().sharedMesh = mMesh;
        }
    }
    
    

    绑定物体看下效果,如下图:
    csharp_mesh
      接下来我们就通过前面我们推导出的裁剪矩阵去计算出变换后的视椎体顶点,代码如下:

    Vector3 getClipMatrixVector4(Vector3 vPos)
        {
            Vector4 vPos4 = new Vector4(vPos.x, vPos.y, vPos.z, 1);
            float _Z = vPos4.z;
            Matrix4x4 clipMat = new Matrix4x4();
            clipMat.m00 = 2 * _Near / ((_R - _L) * _Z);
            clipMat.m01 = 0;
            clipMat.m02 = 0;
            clipMat.m03 = -(_R + _L) / (_R - _L);
    
            clipMat.m10 = 0;
            clipMat.m11 = 2 * _Near / ((_T - _B) * _Z);
            clipMat.m12 = 0;
            clipMat.m13 = -(_T + _B) / (_T - _B);
    
            clipMat.m20 = 0;
            clipMat.m21 = 0;
            clipMat.m22 = -2 / (_Far - _Near);
            clipMat.m23 = (_Far + _Near) / (_Far - _Near);
    
            clipMat.m30 = 0;
            clipMat.m31 = 0;
            clipMat.m32 = 0;
            clipMat.m33 = 1;
            Vector4 cPos4 = clipMat * vPos4;
            return new Vector3(cPos4.x, cPos4.y, cPos4.z);
        }
    
    

    这个函数把原始的视椎体的顶点经过矩阵变换得到裁剪空间的顶点。接下来为了方便起见,我创建两套顶点坐标信息,一套是眼睛空间视椎体的顶点坐标,一套是变换后的裁剪空间的顶点坐标,代码如下:

    /// <summary>
        /// 填充眼睛空间视椎体顶点数据
        /// </summary>
        void FillViewSpaceVertex()
        {
            //构建视椎体near四个顶点和far面四个顶点
            float far2near = _Far / _Near;
            //这里我们按照逆时针排序顶点
            Vspace_n_b_l = new Vector3(_L, _B, _Near);
            Vspace_n_b_r = new Vector3(_R, _B, _Near);
            Vspace_n_t_r = new Vector3(_R, _T, _Near);
            Vspace_n_t_l = new Vector3(_L, _T, _Near);
            //这里我们按照逆时针排序顶点
            Vspace_f_b_l = new Vector3(_L * far2near, _B * far2near, _Far);
            Vspace_f_b_r = new Vector3(_R * far2near, _B * far2near, _Far);
            Vspace_f_t_r = new Vector3(_R * far2near, _T * far2near, _Far);
            Vspace_f_t_l = new Vector3(_L * far2near, _T * far2near, _Far);
        }
    
        /// <summary>
        /// 填充标准设备空间顶点数据
        /// </summary>
        void FillNDCSpaceVertex()
        {
            //构建视椎体near四个顶点和far面四个顶点
            float far2near = _Far / _Near;
            //这里我们按照逆时针排序顶点
            Vspace_n_b_l = new Vector3(_L, _B, _Near);
            Vspace_n_b_r = new Vector3(_R, _B, _Near);
            Vspace_n_t_r = new Vector3(_R, _T, _Near);
            Vspace_n_t_l = new Vector3(_L, _T, _Near);
            //这里我们按照逆时针排序顶点
            Vspace_f_b_l = new Vector3(_L * far2near, _B * far2near, _Far);
            Vspace_f_b_r = new Vector3(_R * far2near, _B * far2near, _Far);
            Vspace_f_t_r = new Vector3(_R * far2near, _T * far2near, _Far);
            Vspace_f_t_l = new Vector3(_L * far2near, _T * far2near, _Far);
    
            NDCspace_n_b_l = getClipMatrixVector4(Vspace_n_b_l);
            NDCspace_n_b_r = getClipMatrixVector4(Vspace_n_b_r);
            NDCspace_n_t_r = getClipMatrixVector4(Vspace_n_t_r);
            NDCspace_n_t_l = getClipMatrixVector4(Vspace_n_t_l);
            NDCspace_f_b_l = getClipMatrixVector4(Vspace_f_b_l);
            NDCspace_f_b_r = getClipMatrixVector4(Vspace_f_b_r);
            NDCspace_f_t_r = getClipMatrixVector4(Vspace_f_t_r);
            NDCspace_f_t_l = getClipMatrixVector4(Vspace_f_t_l);
        }
    

    最后就简单了,用update去处理两套坐标信息的插值变换,然后生成实时变换的网格,就能看到效果了,如下所示:

    void Update()
        {
            if (!lerp_reverse)
            {
                lerp_time += Time.deltaTime / 2.0f;
                if (lerp_time >= 1.0f)
                {
                    lerp_reverse = true;
                }
            }
            else
            {
                lerp_time -= Time.deltaTime / 2.0f;
                if (lerp_time <= 0.0f)
                {
                    lerp_reverse = false;
                }
            }
            Vector3 lerp_nbl = Vector3.Lerp(Vspace_n_b_l, NDCspace_n_b_l, lerp_time);
            Vector3 lerp_nbr = Vector3.Lerp(Vspace_n_b_r, NDCspace_n_b_r, lerp_time);
            Vector3 lerp_ntr = Vector3.Lerp(Vspace_n_t_r, NDCspace_n_t_r, lerp_time);
            Vector3 lerp_ntl = Vector3.Lerp(Vspace_n_t_l, NDCspace_n_t_l, lerp_time);
            Vector3 lerp_fbl = Vector3.Lerp(Vspace_f_b_l, NDCspace_f_b_l, lerp_time);
            Vector3 lerp_fbr = Vector3.Lerp(Vspace_f_b_r, NDCspace_f_b_r, lerp_time);
            Vector3 lerp_ftr = Vector3.Lerp(Vspace_f_t_r, NDCspace_f_t_r, lerp_time);
            Vector3 lerp_ftl = Vector3.Lerp(Vspace_f_t_l, NDCspace_f_t_l, lerp_time);
            UpdateFrustumMesh(lerp_nbl, lerp_nbr, lerp_ntr, lerp_ntl, lerp_fbl, lerp_fbr, lerp_ftr, lerp_ftl);
        }
    

    这里的UpdateFrustumMesh只是将坐标信息通过参数传递的形式改了一下,原理和最上面创建frustum是一样的,最后得到我们想要的比较形象的变换效果,如下图:
    gif
      这时候我们就得到了推导出的裁剪矩阵的效果了,也就是将视椎体变换成Z轴相反的222标准正方体。
      demo下载地址:https://download.csdn.net/download/yinhun2012/10464281
      这里顺便说一下,下篇将使用fov进行新的裁剪矩阵推导和程序演算

    展开全文
  • 1个线性变换和1个矩阵相互对应,进行线性变换和乘以相应的矩阵相互对应 如对1个列向量进行投影相当于对其左乘1个投影矩阵 2.线性变换: 如果变换T满足下述2条运算法则,则称为"线性变换" ①T(v+w)=T(v)+T(w) ②T(cv)=...

    一.线性变换(Linear Transformation)
    1.线性变换:

    如果变换T满足下述2条运算法则,则称为"线性变换"
    ①T(v+w)=T(v)+T(w)
    ②T(cv)=cT(v)
    其中v,w为向量,c∈R
    
    #性质:v,w为向量,c,d∈R,0为零向量
    1.T(cv+dw)=cT(v)+dT(w)
    2.T(0)=0
    

    2.线性变换与矩阵乘法相对应(不引入基):

    1个线性变换和1个矩阵相互对应,进行线性变换和乘以相应的矩阵相互对应
      如对1个列向量进行投影相当于对其左乘1个投影矩阵
    矩阵相当于用坐标来表示线性变换
    
    这里,所有向量都是用不变的,作为背景的标准基向量表示的
    
    #求与线性变换相对应的矩阵:
    已知原来的基是v1...vn,得到T(vi)=A·vi(i=1,2...n),即可解出与T相对应的矩阵A
    
    #已知相应的矩阵,求变换结果:
    已知向量p,线性映射对应的矩阵为A,则变换后的向量为y=Ap
    
    v0=c1·v1+...+cn·vn,新基是w1...wm(m≤n),T(v0)=c1'·w1+...+cm'·wm,
    

    3.用矩阵代表线性变换(引入基):

    #坐标来自于基(通常是来自标准基):
    若v1...vn为1个基,v=c1v1+...cnvn,则在该基下v的坐标为(c1...cn)
    
    这里,新旧2个基是用不变的,作为背景的标准基向量表示的;而v,T(V)是分别用这2个基表示的
    因而下面的W与上面的A不同
    
    #坐标与基:
    设v1...vn为旧基,w1...wm为新基,v=c1v1+...cnvn,T(v)=c1'w1+...cn'wn
      则一.2中的矩阵A满足A·[c1...cn]'=[c1'...cn']'
    特别地,若ai'=ri·ai(i=1...n),即基是线性变换的特征向量,则A是对角阵
      如对投影矩阵P,ai(i=1...n)是原来的1个基且均为P的特征向量,则变换后的基ai'=ri·ai(i=1...n)
      从而P是对角阵且P的对角线上是相应的特征值构成
      这种由特征向量构成的基是最方便,最好的基
    

    4.空间变换:

    若T:x→Ax=y作用于向量空间中的每个向量,就相当于对向量空间进行线性变换,即空间变换
    若x是n维向量,y是m维向量,则A是m×n矩阵
    
    知道线性变换T对向量空间的1个基的影响后,就知道了T对所有向量的影响
      设a1,a2...an是向量空间的1个基,a=k1a1+...+knan,则T(a)=k1T(a1)+...+knT(an)
      故a的坐标在变换前后均为(k1,k2...kn)
    

    二.基变换
    1.基变换(Base Conversion):

    将向量空间原本的基换成另1个,称为基变换
    
    已知旧/新基分别为V=[v1...vn],W=[w1...wn]的列向量组,x,c分别是用旧/新基表示的同一向量
    则V·x=W·c ⇒ c=W^{-1}·V·x
    
    若有2个原来的基,在这2个基下代表线性变换的矩阵相似
      即若原基1为v1...vn,原基2为w1...wn,新基为t1...tm,r=c1v1+...+cnvn=c1'w1+...cn'wn
      且T(r)=k1t1+...kmtm,A·[c1...cn]'=[k1...km]',B·[c1'...cn']=[k1...km]'
      则B=M^{-1}·A·M(即A~B),其中M满足[w1...wn]=[v1...vn]·M(即原基1到原基2的过渡矩阵)
        M满足的条件相当于c'=M^{-1}·c
        #证明时注意:从BM^{-1}c=Ac推不出BM^{-1}=A(因为2侧采用的原基不同)
    
    若vi(i=1...n)为1个原基,T(vi)=a11v1+...+an1vn,记A=[a11...an1;...;a1n...ann]
    则A·[v1...vn]=[T(v1)...T(vn)]
    特别地,若vi(i=1...n)是1个特征基,则A=[λ1 0 ... 0;0 λ2 ... 0;...;0 0 ... λn]
    

    2.图像压缩(有损压缩(Lossy Compression)):

    好的基应该满足:
    ①从标准基转换到该基的过程计算速度快,用时少
    ②具有良好的可压缩性,可以用尽可能少的基中的向量来近似原信号
    
    #############################################################################
    
    标准基是[1 0 ... 0],[0 1 ... 0]...[0 0 ... 1];更好的基是[1 1 ... 1](常数向量/DC向量),[1 -1 1 -1 ...],[1 ... 1 -1 ... -1]
    最好的基是傅里叶基(Fourier Base):[1 1... 1],[1 W... W^{n-1}]...[1 W^{n-1} ... W^{(n-1)^2}](即傅里叶矩阵的列向量组)
    
    另1种常用的基是小波基(Wavelet Base):以8维为例
    v1=[1 ... 1],v2=[1 1 1 1 -1 -1 -1 -1],v3=[1 1 -1 -1 0 ... 0],v4=[0 ... 0 1 1 -1 -1],v5=[1 -1 0 ... 0]...v8=[0 ... 0 1 -1]
    小波基是正交的,将每个向量除以各自的长度后得到1个标准正交基
    小波基通常用于信号会在小范围内大幅变动的情况
    
    快速小波变换(Fast Wavelet Transform;FVT):记W=[v1 ... vn]
    由于小波基是正交的,故W^{-1}=W^T
    若信号P=W·c ⇒ c=W^{-1}·P=W^T·P
    
    #############################################################################
    
    1个图像由m×n个像素表示,每个像素有1个灰度值(假设为黑白图像,如果是RGB图像,每个像素有3个灰度值)
    该图像可以用1个m×n矩阵表示,矩阵中的元素就是相应像素的灰度值,或用1个m·n维向量表示,这需要m·n个基
      #注意:处理图像和传输信号时使用的都是向量而不是矩阵
    压缩图像的方法就是进行基变换:由于大部分相邻的像素的灰度值也接近,因此可以舍弃一部分信号
    
    JPEG格式的压缩步骤:
    ①将1个图像(如512px×512px)分成8px×8px的小块,或者说64维向量(需要64个基来表示)
    ②随每个小块进行基变换,用新的基表示原图像,得到64个系数ci(i=1...64)
    ③设定阈值,将小于该阈值的系数改为0,其他不变,这称为"阈值量化"(Thresholding)
    ④得到1组新的系数c'i(i=1...64),其中有很多为0(DC向量的系数通常比较大,不会被舍弃)
    ⑤按新的系数组合这64个基后得到压缩后的小块的信号
    
    #############################################################################
    
    视频压缩原理:
    ①可以压缩构成视频的静态图像
    ②由于相邻的帧之间的差别很小,因此可以用某帧加修正量来近似下1帧
    

    三.左右逆与伪逆
    1.逆矩阵:

    矩阵A的逆矩阵记为A^{-1},定义是AA^{-1}=A^{-1}A=I
    
    设A_{m×n}的秩为r,则当m=n=r时A有逆矩阵
      #此时A具有如下性质:
        ①N(A)=N(A^T)={0}
        ②Ax=b的解的个数只可能为1
        ③P1=A·[(A^T·A)^{-1}·A^T]=P2=[A^T·(A·A^T)^{-1}]·A=I
    

    2.左逆(Left Inverse)与右逆(Right Inverse):

    左逆:若B满足B·A=I,则称B为A的左逆
    
    若r=n≤m,则A列满秩,此时A具有如下性质:
      ①N(A)={0}
      ②Ax=b的解的个数只可能为0或1
      ③A^T·A满秩,因而A^T·A可逆
      ④A的左逆是(A^T·A)^{-1}·A^T
        [(A^T·A)^{-1}·A^T]·A=(A^T·A)^{-1}·(A^T·A)=I
      ⑤P1=A·[(A^T·A)^{-1}·A^T]是1个投影矩阵,投影到C(A)上
    
    #############################################################################
    
    左逆:若C满足A·C=I,则称C为A的右逆
    
    若r=m≤n,则A行满秩,此时A具有如下性质:
      ①N(A^T)={0}
      ②Ax=b总有无穷多个解(有n-m个自由变量)
      ③A·A^T满秩,因而A·A^T可逆
      ④A的右逆是A^T·(A·A^T)^{-1}
        A·[A^T·(A·A^T)^{-1}]=(A·A^T)·(A·A^T)^{-1}=I
      ⑤P2=[A^T·(A·A^T)^{-1}]·A是1个投影矩阵,投影到C(A^T)上
    

    3.伪逆(Pseudo Inverse):
    在这里插入图片描述

    当r<min{m,n},矩阵A既不列满秩也不行满秩,此时A^T·A为奇异矩阵
    
    若x,y∈C(A^T)且x≠y,则Ax,Ay∈C(A)且Ax≠Ay从而A对应的映射T是C(A^T)→C(A)的单射
      x,y∈C(A^T) ⇒ x-y∈C(A^T)
      若Ax=Ay ⇒ A(x-y)=0 ⇒ x-y∈N(A) ⇒ x-y=0 ⇒ x=y ⇒ 矛盾 ⇒ Ax≠Ay
    由于dim C(A^T)=dim C(A),可证T是满射,从而T是双射,因而T可逆
    T^{-1}对应的矩阵称为A的"伪逆",记为A^{+},即y=A^{+}(Ay)(其中y属于C(A^T))
      对c∈N(A^T),A^{+}c=0,即A^{+}消除了N(A^T);对d∈N(A),Ad=0.即A消除了N(A)
    
    A·A^{+}是到C(A)的投影矩阵P1,A^{+}·A是到C(A^T)的投影矩阵P2
      P1_m=[1 0 ... 0 ... 0;0 1 ... 0 ... 0;...;0 0 ... 1 ... 0;...;0 0 ... 0 ... 0]_m,共r个1
      P2_n=[1 0 ... 0 ... 0;0 1 ... 0 ... 0;...;0 0 ... 1 ... 0;...;0 0 ... 0 ... 0]_n,共r个1
    
    为逆矩阵可用于最小二乘法
    
    性质:
    ①A·A^{+}·A=A
    ②A^{+}·A·A^{+}=A^{+}
    ③A·A^{+}=(A·A^{+})^T
    ④A^{+}·A=(A^{+}·A)^T
    
    #############################################################################
    
    利用奇异值分解(SVD)求伪逆:
    A=U·Σ_{mn}·V^T ⇒
    Σ^{+}_{nm}=Σ=[1/σ1 0 ... 0 ... 0;0 1/σ2 ... 0 ... 0;...;0 0 ... 1/σr ... 0;...;0 0 ... 0 ... 0]; ⇒
      #注意:Σ_{mn}的伪逆还可以是其他矩阵,但这里的是其中最简单的1个
    A^{+}=V·Σ^{+}_{nm}·U^T
    
    
    展开全文
  • 线性代数:线性变换

    2013-07-29 11:06:00
    1、向量变换 向量变换是从一个向量空间到另一个(或者同一个)向量空间的函数。...Rn,如果满足T(A+B) = T(A)+T(B)和T(cA)=cT(A),变换T是线性变换。 3、矩阵向量乘法 基于矩阵Amn,可以定义变换T(x) = Ax,T是一个R...
  • 线性代数笔记18:线性变换与基变换

    万次阅读 2018-05-09 20:56:28
    这里不严格给出线性变换的定义,但举例来说,投影变换、反射变换、不定积分等都可以看做是线性变换。 与线性变换相对的是仿射变换,例如: T(x)=Ax+x0T(x)=Ax+x0T(x)= Ax + x_0 就是一个仿射变换,可...
  • 文章目录线性代数学习笔记(二):线性变换的理解一、基变换与坐标变换二、 线性变换2.1 线性变换与基变换的不同2.2 线性变换的表示2.3 线性变换的分类2.4 线性变换与矩阵2.5 应用:线性代数观点看线性变换2.5.1 ...
  •  线性变换这个词在线性代数中经常被提及,每个线性变换的背后都有一个矩阵。矩阵的概念比较直观,相比之下,线性变换就显得抽象了。 线性变换  抛开矩阵,我们从变换的角度讨论投影。通过T变换,使平面内的一个...
  • 1. 线性变换的概念 当一个矩阵 AAA 乘以一个向量 v\boldsymbol vv 时,它将 v\boldsymbol vv 变换到另一个向量 AvA\boldsymbol vAv。进来的是 v\boldsymbol vv,出去的是 T(v)=AvT( \boldsymbol v) = A\boldsymbol ...
  • 本文是Gilbert Strang的线性代数导论课程笔记。课程地址:http://v.163.com/special/opencourse/daishu.html  第三十课时:线性变换与对应矩阵 本讲从线性变换这一概念出发,每个线性变换都对应于一个矩阵。矩阵...
  • 漫步线性代数十三——线性变换

    千次阅读 2016-08-31 22:12:40
    这是步入线性代数的基础,从性质(1) 开始引申出许多其他结论。现在我们直接从矩阵开始,看看他们如何表示线性变换。 一个变换没必要必须从 R n R^n 变到相同的空间 R n R^n ,允许将 R n R^n 中的向量变成不同...
  • 线性代数是工科数学的核心与基础内容之一,掌握好线性代数,不仅有助于日后的各种数学学科的理论学习,更是掌握各种专业知识的必备技能。但可惜的是,很多人由于受到教材排版的缺陷、授课水平的约束,并没有很好地...
  • 线性变换- 线性代数

    2015-10-17 22:15:16
    投影与旋转。
  • 本篇博客是线性代数的基础理论知识下篇,限于篇幅,不会把所有定义都罗列出来,而是将整理的重点放在定理和结论上(当然有些必要的定义还是会说明的),对于最基础的概念(如什么是矩阵、行列式的定义及基本计算方法...
  • 线性变换与计算机图形学5.1 旋转、伸缩、剪切变换5.2 平移变换5.2.1 齐次坐标系5.2.2 二维的平移变换5.2.3 三维的平移变换5.3 透视投影5.4 绕某点旋转 1. 矩阵与向量相乘的两重含义 1.1 重新线性组合   对于矩阵...
  • 基本图像变换:线性变换,仿射变换,投影变换

    千次阅读 多人点赞 2017-11-04 21:44:43
    投影变换 总结平面变换包括 线性变换,仿射变换等, 线性变换包括 旋转,镜像(翻转),伸缩(缩放),推移(错切) 仿射变换 = 线性变换 + 平移线性变换直观定义: 变换前是直线变换后仍是直线(平行关系) 直线...
  • 线性代数”,同微积分一样,是高等数学中两大入门课程之一,不仅是一门非常好的数学课程,也是一门非常好的工具学科,在很多领域都有广泛的用途。本课程讲述了矩阵理论及线性代数的基本知识,侧重于那些与其他学科...
  • 线性代数

    千次阅读 多人点赞 2019-05-17 17:15:19
    线性代数课程,无论你从行列式入手还是直接从矩阵入手,从一开始就充斥着莫名其妙。 比如说,在全国一般工科院系教学中应用最广泛的同济线性代数教材(现在到了第四版),一上来就介绍逆序数这个古怪概念,然后...
  • 线性代数课程,无论你从行列式入手还是直接从矩阵入手,从一开始就充斥着莫名其妙。 比如说,在全国一般工科院系教学中应用最广泛的同济线性代数教材(现在到了第四版),一上来就介绍逆序数这个古怪概念,然后用...
  • 线性代数有什么用? 用于求解线性问题(即求解线性方程中的未知数)。如:化学方程式中的系数,杠杆平衡。怎么求解?答:用高斯消元法。什么是高斯消元法?高中教的解方程的那种方法就是消元法。任何计算机都是这么...
  • 为什么要有线性代数?可能有人对把线性代数当成一门DSL不放心,我给你一个矩阵,你就把我的图形旋转了60度沿x轴拉伸了2倍,我总感觉不踏实啊,我都不知道你“底 层”是怎么做!其实,这就像有的程序员用高级语言不...
  • 线性变换 接上一篇线性变换(上) 我们今天来讨论关于平面向量的线性变换。 在这里,我先说一个引理,根据线性变换的定义,T(cv)=cT(v),T(u+v)=T(u)+T(v)T(cv)=cT(v),T(u+v)=T(u)+T(v)T(cv)=cT(v),T(u+v)=T(u)+T(v)...
  • 线性变换和基变换基本概念线性相关性维数基线性变换 基本概念 线性相关性 如果x1,x2,⋯ ,xm∈Vx_1,x_2,\cdots,x_m\in Vx1​,x2​,⋯,xm​∈V,其中VVV是线性空间,且∃c1,c2⋯ ,cm∈K\exists c_1 , c_2 \cdots , c...
  • 本文是Gilbert Strang的线性代数导论课程笔记。课程地址:http://v.163.com/special/opencourse/daishu.html  第三十五课时:线性代数全总结 本节是Gilbert Strang主讲的线性代数导论最后一讲,我想我会想念这...
  •   一个矩阵AAA既可以表示一种线性变换,又可以是一个子空间(由基张开的),还可以是一组坐标,甚是神奇。 文章目录About 投影矩阵一维空间的投影矩阵投影矩阵的多维推广投影的物理意义信号处理中的正交投影技术 ...
  • 线性代数笔记

    2018-12-05 13:26:00
    线性代数导读+总结 线性代数笔记1:矩阵的四个基本子空间 ...线性代数笔记3:向量投影 线性代数笔记4:最小二乘法 线性代数笔记5:Gram-Schmidit正交化 线性代数笔记6:行列式 线性代数笔记7:特征...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 7,575
精华内容 3,030
关键字:

线性代数投影变换