透视投影(Perspective Projection)变换推导

2023-10-27

透视投影是3D固定流水线的重要组成部分,是将相机空间中的点从视锥体(frustum)变换到规则观察体(Canonical View Volume)中,待裁剪完毕后进行透视除法的行为。在算法中它是通过透视矩阵乘法和透视除法两步完成的。    
透视投影变换是令很多刚刚进入3D图形领域的开发人员感到迷惑乃至神秘的一个图形技术。其中的理解困难在于步骤繁琐,对一些基础知识过分依赖,一旦对它们中的任何地方感到陌生,立刻导致理解停止不前。   
没错,主流的3D APIs如OpenGL、D3D的确把具体的透视投影细节封装起来,比如gluPerspective(„) 就可以根据输入生成一个透视投影矩阵。而且在大多数情况下不需要了解具体的内幕算法也可以完成任务。但是你不觉得,如果想要成为一个职业的图形程序员或游 戏开发者,就应该真正降伏透视投影这个家伙么?我们先从必需的基础知识着手,一步一步深入下去(这些知识在很多地方可以单独找到,但我从来没有在同一个地 方全部找到,但是你现在找到了)。   
我们首先介绍两个必须掌握的知识。有了它们,我们才不至于在理解透视投影变换的过程中迷失方向(这里会使用到向量几何、矩阵的部分知识,如果你对此不是很熟悉,可以参考

image

可以找到一组坐标(v1,v2,v3),使得   
v = v1 a + v2 b + v3 c (1)   
而对于一个点p,则可以找到一组坐标(p1,p2,p3),使得   
p – o = p1 a + p2 b + p3 c (2)   
从上面对向量和点的表达,我们可以看出为了在坐标系中表示一个点(如p),我们把点的位置看作是对这个基的原点o所进行的一个位移,即一个向量——p – o(有的书中把这样的向量叫做位置向量——起始于坐标原点的特殊向量),我们在表达这个向量的同时用等价的方式表达出了点p:   
p = o + p1 a + p2 b + p3 c (3)   
(1)(3)是坐标系下表达一个向量和点的不同表达方式。这里可以看出,虽然都是用代数分量的形式表达向量和点,但表达一个点比一个向量需要额外的信息。如果我写出一个代数分量表达(1, 4, 7),谁知道它是个向量还是个点!   
我们现在把(1)(3)写成矩阵的形式:

image

这里(a,b,c,o)是坐标基矩阵,右边的列向量分别是向量v和点p在基下的坐标。

这样,向量和点在同一个基下就有了不同的表达:3D向量的第4个代数分量是0,而3D点的第4个代数分量是1。像这种这种用4个代数分量表示3D几何概念的方式是一种齐次坐标表示。

“齐次坐标表示是计算机图形学的重要手段之一,它既能够用来明确区分向量和点,同时也更易用于进行仿射(线性)几何变换。”——F.S. Hill, JR

这样,上面的(1, 4, 7)如果写成(1,4,7,0),它就是个向量;如果是(1,4,7,1),它就是个点。下面是如何在普通坐标 (Ordinary Coordinate)和齐次坐标(Homogeneous Coordinate)之间进行转换:

从普通坐标转换成齐次坐标时,如果(x,y,z)是个点,则变为(x,y,z,1); 如果(x,y,z)是个向量,则变为(x,y,z,0)

从齐次坐标转换成普通坐标时,如果是(x,y,z,1),则知道它是个点,变成(x,y,z);

如果是(x,y,z,0),则知道它是个向量,仍然变成(x,y,z)

以上是通过齐次坐标来区分向量和点的方式。从中可以思考得知,对于平移T、旋转R、缩放S这3个最常见的仿射变换,平移变换只对于点才有意义,因为普通向量没有位置概念,只有大小和方向,这可以通过下面的式子清楚地看出:

clip_image001

而旋转和缩放对于向量和点都有意义,你可以用类似上面齐次表示来检测。从中可以看出,齐次坐标用于仿射变换非常方便。 
此外,对于一个普通坐标的点P=(Px, Py, Pz),有对应的一族齐次坐标(wPx, wPy, wPz, w),其中w不等于零。比如,P(1, 4, 7)的齐次坐标有(1, 4, 7, 1)、(2, 8, 14, 2)、(-0.1, -0.4, -0.7, -0.1)等等。因此,如果把一个点从普通坐标变成齐次坐标,给x,y,z乘上同一个非零数w,然后增加第4个分量w;如果把一个齐次坐标转换成普通坐 标,把前三个坐标同时除以第4个坐标,然后去掉第4个分量。 
由于齐次坐标使用了4个分量来表达3D概念,使得平移变换可以使用矩阵进行,从而如F.S. Hill, JR所说,仿射(线性)变换的进行更加方便。由于图形硬件已经普遍地支持齐次坐标与矩阵乘法,因此更加促进了齐次坐标使用,使得它似乎成为图形学中的一个标准。 
简单的线性插值 
这是在图形学中普遍使用的基本技巧, 我们在很多地方都会用到,比如2D位图的放大、缩小,Tweening变换,以及我们即将看到的透视投影变换等等。基本思想是:给一个x属于[a, b],找到y属于[c, d],使得x与a的距离比上ab长度所得到的比例,等于y与c的距离比上cd长度所得到的比例,用数学表达式描述很容易理解: 
clip_image003

这样,从a到b的每一个点都与c到d上的唯一一个点对应。有一个x,就可以求得一个y。 
此外,如果x不在[a, b]内,比如x < a或者x > b,则得到的y也是符合y < c或者y > d,比例仍然不变,插值同样适用。 
透视投影变换 
好,有了上面两个理论知识,我们开始分析这次的主角——透视投影变换。这里我们选择OpenGL的透视投影变换进行分析,其他的 APIs会存在一些差异,但主体思想是相似的,可以类似地推导。经过相机矩阵的变换,顶点被变换到了相机空间。这个时候的多边形也许会被视锥体裁剪,但在这个不规则的体中进行裁剪并非那么容易的事情,所以经过图形学前辈们的精心分析,裁剪被安排到规则观察体(Canonical View Volume, CVV)中进行,CVV是一个正方体,x, y, z的范围都是[-1,1],多边形裁剪就是用这个规则体完成的。所以,事实上是透视投影变换由两步组成: 
1) 用透视变换矩阵把顶点从视锥体中变换到裁剪空间的CVV中。 
2)  CVV裁剪完成后进行透视除法(一会进行解释)。 
clip_image004

我们一步一步来,我们先从一个方向考察投影关系。 
clip_image005

上图是右手坐标系中 顶点在相机空间中的情形。设P(x,z)是经过相机变换之后的点,视锥体由eye——眼睛位置,np——近裁剪平面,fp——远裁剪平面组成。N是眼睛到 近裁剪平面的距离,F是眼睛到远裁剪平面的距离。投影面可以选择任何平行于近裁剪平面的平面,这里我们选择近裁剪平面作为投影平面。设 P’(x’,z’)是投影之后的点,则有z’ = -N。通过相似三角形性质,我们有关系: 
clip_image006

同理,有 
clip_image007

这样,我们便得到了P投影后的点P’ 
clip_image008

从上面可以看出,投影的结果z’始终等于-N,在投影面上。实际上,z’对于投影后的P’已经没有意义了,这个信息点已经没用了。但对于3D图形管线来 说,为了便于进行后面的片元操作,例如z缓冲消隐算法,有必要把投影之前的z保存下来,方便后面使用。因此,我们利用这个没用的信息点存储z,处理成: 
clip_image009

这个形式最大化地使用了3个信息点,达到了最原始的投影变换的目的,但是它太直白了,有一点蛮干的意味,我感觉我们最终的结果不应该是它,你说呢?我们开始结合CVV进行思考,把它写得在数学上更优雅一致,更易于程序处理。假入能够把上面写成这个形式: 
clip_image010

那么我们就可以非常方便的用矩阵以及齐次坐标理论来表达投影变换: 
clip_image011

其中 
clip_image012

哈,看到了齐次坐标的使用,这对于你来说已经不陌生了吧?这个新的形式不仅达到了上面原始投影变换的目的,而且使用了齐次坐标理论,使得处理更加规范化。注意在把 clip_image013

变成 clip_image014

的一步我们是使用齐次坐标变普通坐标的规则完成的。这一步在透视投影过程中称为透视除法(Perspective Division),这是透视投影变换的第2步,经过这一步,就丢弃了原始的z值(得到了CVV中对应的z值,后面解释),顶点才算完成了投影。而在这两步之间的就是CVV裁剪过程,所以裁剪空间使用的是齐次坐标 clip_image013[1]

,主要原因在于透视除法会损失一些必要的信息(如原始z,第4个-z保留的)从而使裁剪变得更加难以处理,这里我们不讨论CVV裁剪的细节,只关注透视投影变换的两步。 
矩阵

clip_image015

就是我们投影矩阵的第一个版本。你一定会问为什么要把z写成 
clip_image016

有两个原因: 
1)  P’的3个代数分量统一地除以分母-z,易于使用齐次坐标变为普通坐标来完成,使得处理更加一致、高效。 
2) 后面的CVV是一个x,y,z的范围都为[-1,1]的规则体,便于进行多边形裁剪。而我们可以适当的选择系数a和b,使得 clip_image016[1]

这个式子在z = -N的时候值为-1,而在z = -F的时候值为1,从而在z方向上构建CVV。 
接下来我们就求出a和b: 
clip_image017

这样我们就得到了透视投影矩阵的第一个版本: 
clip_image018

使用这个版本的透视投影矩阵可以从z方向上构建CVV,但是x和y方向仍然没有限制在[-1,1]中,我们的透视投影矩阵的下一个版本就要解决这个问题。 
为了能在x和y方向把顶点从Frustum情形变成CVV情形,我们开始对x和y进行处理。先来观察我们目前得到的最终变换结果: 
clip_image014[1]

我们知道-Nx / z的有效范围是投影平面的左边界值(记为left)和右边界值(记为right),即[left, right],-Ny / z则为[bottom, top]。而现在我们想把-Nx / z属于[left, right]映射到x属于[-1, 1]中,-Ny / z属于[bottom, top]映射到y属于[-1, 1]中。你想到了什么?哈,就是我们简单的线性插值,你都已经掌握了!我们解决掉它: 
clip_image019

则我们得到了最终的投影点: 
clip_image020

式出发反推出下一个版本的透视投影矩阵。注意到 clip_image014[2]

是 clip_image013[2]

经过透视除法的形式,而P’只变化了x和y分量的形式,az+b和-z是不变的,则我们做透视除法的逆处理——给P’每个分量乘上-z,得到 
clip_image021

而这个结果又是这么来的: 
clip_image022

则我们最终得到: 
clip_image023

M 就是最终的透视变换矩阵。相机空间中的顶点,如果在视锥体中,则变换后就在CVV中。如果在视锥体外,变换后就在CVV外。而CVV本身的规则性对于多边 形的裁剪很有利。OpenGL在构建透视投影矩阵的时候就使用了M的形式。注意到M的最后一行不是(0 0 0 1)而是(0 0 -1 0),因此可以看出透视变换不是一种仿射变换,它是非线性的。另外一点你可能已经想到,对于投影面来说,它的宽和高大多数情况下不同,即宽高比不为1,比 如640/480。而CVV的宽高是相同的,即宽高比永远是1。这就造成了多边形的失真现象,比如一个投影面上的正方形在CVV的面上可能变成了一个长方形。解决这个问题的方法就是在对多变形进行透视变换、裁剪、透视除法之后,在归一化的设备坐标(Normalized Device Coordinates)上进行的视口(viewport)变换中进行校正,它会把归一化的顶点之间按照和投影面上相同的比例变换到视口中,从而解除透视投影变换带来的失真现象。进行校正前提就是要使投影平面的宽高比和视口的宽高比相同。 
便利的投影矩阵生成函数 
3D APIs都提供了诸如gluPerspective(fov, aspect, near, far)或者D3DXMatrixPerspectiveFovLH(pOut, fovY, Aspect, zn, zf)这样的函数为用户提供快捷的透视矩阵生成方法。我们还是用OpenGL的相应方法来分析它是如何运作的。 
gluPerspective(fov, aspect, near, far) 
fov即视野,是视锥体在xz平面或者yz平面的开角角度,具体哪个平面都可以。OpenGL和 D3D都使用yz平面。 
aspect即投影平面的宽高比。 
near是近裁剪平面的距离 
far是远裁剪平面的距离。 
clip_image024

上图中左边是在xz平面计算视锥体,右边是在yz平面计算视锥体。可以看到左边的第3步top = right / aspect使用了除法(图形程序员讨厌的东西),而右边第3步right = top x aspect使用了乘法,这也许就是为什么图形APIs采用yz平面的原因吧!

在上一篇文章中我们讨论了透视投影变换的原理,分析了OpenGL所使用的透视投影矩阵的生成方法。正如我们所说,不同的图形API因为左右手坐标系、行向量列向量矩阵以及变换范围等等的不同导致了矩阵的差异,可以有几十个不同的透视投影矩阵,但它们的原理大同小异。这次我们准备讨论一下Direct3D(以下简称D3D)以及J2ME平台上的JSR184(M3G)(以下简称M3G)的透视投影矩阵,主要出于以下几个目 的: 
(1) 我们在写图形引擎的时候需要采用不同的图形API实现,当前主要是OpenGL和D3D。虽然二者的推导极为相似,但D3D的自身特点导致了一些地方仍然需要澄清。 
(2)       DirectX SDK的手册中有关于透视投影矩阵的一些说明,但并不详细,甚至有一些错误,从而使初学者理解起来变得困难,而这正是本文写作的目的。 
(3)       M3G是J2ME平台上的3D开发包,采用了OpenGL作为底层标准进行封装。它的透视投影矩阵使用OpenGL的环境但又进行了简化,值得一提。 
本文努力让读者清楚地了解D3D与M3G透视投影矩阵的原理,从而能够知道它与OpenGL的一些差别,为构建跨API的 图形引擎打好基础。需要指出的一点是为了完全理解本文的内容,请读者先理解上一篇文章《深入探索透视投影变换》的内容,因为OpenGL和它们的透视投影 矩阵的原理非常相似,因此这里不会像上一篇文章从基础知识讲起,而是对比它们的差异来推导变换矩阵。我们开始! 
OpenGL与D3D的基本差异 
前面提到,不同API的基本差异导致了最终变换矩阵的不同,而导致OpenGL和D3D的透视投影矩阵不同的原因有以下几个: 
(1)       OpenGL默认使用右手坐标系,而D3D 默认使用左手坐标系。 
clip_image025

(2)       OpenGL使用列向量矩阵乘法而D3D使用行向量矩阵乘法。 
clip_image026

(3)       OpenGL的CVV的Z范围是[-1, 1],D3D的CVV的Z范围是[0, 1]。 
以上这些差异导致了最终OpenGL和D3D的透视投影矩阵的不同。 
D3D的透视投影矩阵推导 
我们先来看最最基本的透视关系图(上一篇文章开始的时候使用的图): 
clip_image027

这里我们考察的是xz平面上的关系,yz平面上的关系同理。这里o是相机位置。np是近裁剪平面,也是投影平面,N是它到相机的距离。fp是远裁剪平面,F 是它到相机的位置。p是需要投影的点,p’是投影之后的点。根据相似三角形定理,我们有 
clip_image028

则有 
clip_image029

注意到OpenGL使用右手坐标系,因此应该使用-N(请参考上一篇文章的这一步),而D3D使用左手坐标系,因此使用N,这是二者的不同点之一。这样,我们得到投影之后的点 
clip_image030

第三个信息点是变换之后的z在投影平面上的位置,也就是N,它已经没用了,我们把p’写成 
clip_image031

从而用第三个没用信息点它来存储z(如果读者对这一点不太了解,请参考上一篇文章)。接下来我们求出a和b,从而在z方向 上构建CVV。请注意这里是 OpenGL和D3D的另一个不同点,OpenGL的CVV的z范围是[-1, 1],而D3D的CVV的z范围是[0, 1]。也就是说,D3D 中在近裁剪平面上的点投影之后的点会处于CVV的z=0平面上,而在远裁剪平面上的点投影之后的点会在CVV的z=1平面上。这样我们的计算方程就是 
clip_image032

从而我们得到了透视投影矩阵的第一个版本 
clip_image033

即 
clip_image034

这个时候第三个分量变换到CVV情形了,CVV的z范围是[0,1]。接下来根据上一篇文章所讲到的,我们要把前两个分量变成CVV情形,CVV的x和y范围是[-1, 1],如下图所示: 
clip_image035

使用线性插值,我们有: 
clip_image036

这里left和right是投影平面的左右范围,top和bottom是投影平面的上下范围。xcvv和ycvv是我们需要算出的在CVV情形中的x和y,也就是我们要计算出的结果。但在算出它们之前,我们先把上面的式子写成: 
clip_image037

这里有一个需要注意的地方,如果投影平面在x方向上居中,则 
clip_image038

那么第一个式子就可以销掉等号两边的1/2,写成 
clip_image039

同理,如果投影平面在y方向上居中,则第二个式子可以写成 
clip_image040

则我们现在分两种情况讨论: 
(1) 投影平面的中心和x-y平面的中心重合(在x和y方向上都居中) 
(2) 一般情况 
我们分别讨论: 
(1)特殊情况方程 
clip_image041

这组是特殊情况,方程比较简单,但也是使用频率最高的方式(这是D3DXMatrixPerspectiveLH、 D3DXMatrixPerspectiveRH、D3DXMatrixPerspectiveFovLH、 D3DXMatrixPerspectiveFovRH四个方法所使用的情况)。我们导出它: 
clip_image042

则我们反推出透视投影矩阵: 
clip_image043

其中 
clip_image044

而 r-l和t-b可以分别看作是投影平面的宽w和高h。最后那个矩阵就是D3D的透视投影矩阵之一。另外呢,如果我们不知道right、left、top以及bottom这几个参量,也可以根据视野(FOV – Field Of View)参量来求得。下面是两个平面的视野关系图: 
clip_image045

clip_image046

其中,两个fov分别是在x-z以及y-z平面上的视野。如果只给了一个视野,也可以通过投影平面的宽高比计算出来: 
clip_image047

用一个视野算出w或者h,然后用宽高比算出h或者w。 
(2)一般情况的方程 
clip_image048

这组方程比较繁琐,但更具一般性(和OpenGL一般矩阵的推导一致,这也是D3DXMatrixPerspectiveOffCenterLH和 D3DXMatrixPerspectiveOffCenterRH两个方法所使用的情况)。我们导出它: 
clip_image049

我们继续反推出透视投影矩阵: 
clip_image050

其中 
clip_image051

最后那个矩阵就是D3D的一般透视投影矩阵。 
好了,目前为止,我们已经导出了D3D的两个透视投影矩阵。下面我把上一篇导出的OpenGL的透视投影矩阵写出来,大家可以拿它和刚刚导出的D3D的一般性透视投影矩阵做一个对比。 
clip_image052

如果仔细观察,可以发现二者在元素的布局上是一个转置的关系,这个就是由它们使用的左右手坐标系以及使用的行列矩阵的差异造成的。而另外在一些元素的细节上也存在着差异,这是由于D3D的CVV的z范围不同造成的。可见在原理相同的情况下,细微的环境差异可以造成非常大的变 化,而这就是透视投影矩阵存在诸多不同版本的原因。一般情况的透视投影矩阵也可以使用视野方式来定义,方法和特殊情况相同。 
M3G的透视投影矩阵 
M3G是对OpenGL进行的一个封装,它的透视投影变换矩阵被放到了类Camera里面。因为它封装了OpenGL,因 此环境和OpenGL相同:右手坐标系、列向量乘法、CVV范围[-1, 1]。它唯一和OpenGL有些差异的地方就在于它只使用投影平面的中心和x-y平面的中心重合(在x和y方向上都居中)的情况(就是我们上面D3D的第 一种特殊情况)。我们用OpenGL透视投影矩阵最终版本来说明(再次提醒,如果读者对此感到迷惑,请参考第一篇文章): 
上面是OpenGL透视投影矩阵的最终版本,也是一般性版本,我们要把它变成特殊性,版本,非常简单,和上面D3D的特殊情况一样,我们从对x和y进行插值的那一步来看: 
clip_image053

和 D3D的第一种情况一样,销掉两边的1/2,得到: 
clip_image054

则我们反推出透视投影矩阵: 
clip_image055

最右边那个矩阵就是M3G的透视投影矩阵。仍然可以通过视野参数来设置透视投影矩阵,这里请读者自行推导,方法与上面D3D的完全相同。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

透视投影(Perspective Projection)变换推导 的相关文章

  • 分布式系统详解--框架(Hadoop-单机版搭建)

    分布式系统详解 框架 Hadoop 单机版搭建 前面讲了这么多的理论知识 也有一些基础的小知识点 很简单的概括了一下 从这篇文章开始 就会进入到一个理论实践相结合中 这篇文章主要是讲的Hadoop 讲解它的基础认识 安装 常用命令 还有就是
  • 前缀和、差分和双指针 算法学习

    1 前缀和 1 1 算法原理 所谓前缀和 就是记录下前方所有数据之和 当所需中间数据时 可以通过o 1 的时间复杂度将数据求出 一维数组前缀和 求出1 i的所有项之和 由于当运算到第i位时 前i 1位已经运算完成 故a i a i a i
  • mysqldump备份数据库

    某项目的负责人要求我们拿出一个MYSQL的备份方案 查了一下资料 结合CSDN上的MYSQL备份工具 发现使用MYSQLDUMP命令进行数据库的备份 现在不考虑差异和增量备份 只做完全备份 该项目的工控机的系统环境 Windows2003
  • 使用Python中的pandas库,我们可以很方便地对数据进行处理和操作。本文将介绍如何使用iloc函数将DataFrame所有的数值重置为0或其他固定值。

    使用Python中的pandas库 我们可以很方便地对数据进行处理和操作 本文将介绍如何使用iloc函数将DataFrame所有的数值重置为0或其他固定值 步骤1 导入pandas库 首先需要导入pandas库 并且生成一个DataFram
  • Python编程题每日一练day1(附答案)

    Python编程题每日一练day1 Python编程题每日一练day2 附答案 题目一 游乐园的门票 题目二 寻找被污染的字符串 题目三 实现计算求最大公约数和最小公倍数的函数 题目四 实现判断一个数是不是素数的函数 题目五 输入两个正整数
  • 电子水尺在农田灌区渠道水位流量监测方案

    一 方案背景 农田灌区渠道流量监测系统是农田水利信息化建设的一个重要部分 也是高标准农田生产灌溉水资源灌溉监测的一部分 我们公司利用计算机技术 电子技术 软件技术 通信技术 研发并生产出了 用于农田及高标准农田灌区渠道灌溉使用的流量监测一体
  • oppo怎么修改dns服务器地址,OPPO R7/R7 Plus修改DNS图文教程

    OPPO R7 R7 Plus怎么修改DNS 以下是操作方法 1 进入WLAN设置界面 打开设置 WLAN 进入wlan设置界面 长按已经连接上的网络名称 2 找到 修改网络 接着弹出来一个选项框 选择 修改网络 勾选 显示高级选项 3 将
  • JS-词法作用域

    词法作用域 词法作用域就是定义在词法阶段的作用域 换句话说 词法作用域是由你在写代码时将变量和块作用域写在哪里来决定的 因此当词法分析器处理代码时会保持作用域不变 大部分情况下是这样的 作用域查找会在找到第一个匹配的标识符时停止 无论函数在
  • win10 防火墙导致mysql Can't connect to MySQL server on 'localhost' (10060)

    说明 本地是win10 mysql一直正常使用 今天不知道它抽什么风 连不上了 如下图 解决过程 先是net stop mysql 后net start mysql 提示mysql服务开启成功 但还是连不上 妈呀 接着查看3306端口 正常
  • 1.STM32简介

    STM32简介 STM32是ST公司基于ARM Cortex M内核开发的32位微控制器 STM32常应用在嵌入式领域 如智能车 无人机 机器人 无线通信 物联网 工业控制 娱乐电子产品等 STM32功能强大 性能优异 片上资源丰富 功耗低
  • IDEA打包deploy梳理

    我们有时候经常需要将本地的包deploy到私服上去 可能是snapshot的 也可能是release的 具体逻辑如下 deploy会涉及到两个仓库 一个是包下载仓库 一个是包上传仓库 完成一次deploy 我们要清楚这两个标签内的内容 包下
  • 成为Android高手必须掌握的28大项内容和10个建议

    一 成为Android高手必须掌握的8项基本要求 1 Android操作系统概述 1 Android系统架构 2 Android利用设计理念 3 Android 开源知识 4 Android 参考网站与权威信息 2 Android SDK及
  • 10分钟了解关键路径及如何求得关键路径

    文章目录 一 什么是关键路径 二 求解关键路径需要的4个描述量 三 如何求得关键路径 视频参考 6 6 4关键路径2 求解关键路径 一 什么是关键路径 引例 1 某项目的任务是对A公司的办公室重新进行装修 如果10月1日前完成装修工程 项目
  • 概率论与数理统计--假设检验

    参数估计能解决实际问题中分布类型已知时对位置参数进行估计的问题 可是还有许多问题参数估计无法解决 例如 某弓藏生产产品某项指标服从 N 2 0 N mu sigma 0 2 分布 经过技术改造后 mu与 2 0 sigma 0 2是否发生了
  • Mybatis typealiaspackage 通配符扫描方法

    最近两天项目需求研究了一下mybatis拦截器 对于Mybatis拦截器发现其功能强大 虽很灵活但是其内部对象转换太麻烦很多接口没有完全暴露出来 甚至不得不通过反射的方式去取其内部关联对象 可能Mybatis也不希望用户直接对其内部Stat

随机推荐

  • 服务器上数据盘不显示,云服务器不显示数据盘

    云服务器不显示数据盘 内容精选 换一换 当卸载数据盘时 支持离线或者在线卸载 即可在挂载该数据盘的云服务器处于 关机 或 运行中 状态进行卸载 弹性云服务器在线卸载磁盘 详细信息请参见在线卸载磁盘 裸金属服务器当前支持将SCSI类型磁盘挂载
  • 169.多数元素 C++

    ans1 先对数组排序 1 1 class Solution public int majorityElement vector
  • 前端web基础四:css简介

    1 什么是css css3 css的第三个版本 css是由很多模块构成 有些模块高于3或者低于3 但是现在w3c统一标准称为css3跟html5一样称html 一般我们说的css就是css3以后基本上不会改了 css 层叠样式表cascad
  • x264源码分析--dpb-size

    dpb size 参数含义 解码缓冲区大小 decode picture buffer 参数解析 OPT dpb size p gt i dpb size atoi value 代码逻辑 h gt param i dpb size x264
  • 面试官问 : ArrayList 不是线程安全的,为什么 ?(看完这篇,以后反问面试官)

    前言 金三银四 也许 但是 近日 又收到金三银四一线作战小队成员反馈的战况 我不管你从哪里看的面经 但是我不允许你看到我这篇文章之后 还不清楚这个面试问题 本篇内容预告 ArrayList 是线程不安全的 为什么 结合代码去探一探所谓的不安
  • Mask Rcnn目标分割-训练自己数据集-详细步骤

    本文接着介绍了Mask Rcnn目标分割算法如何训练自己数据集 对训练所需的文件以及训练代码进行详细的说明 本文详细介绍在只有样本图片数据时 如果建立Mask Rcnn目标分割训练数据集的步骤 过程中用到的所有代码均已提供 一 制作自己的数
  • 严重性代码说明项目文件行 禁止显示状态错误 C4996 fopen('fscanf'、strcmp):This function or variable may be unsafe. 最全解决办法

    解决fopen fscanf 在VS中要求替换为fopen s fscanf s的最全解决办法 ps 在使用MFC中遇到上述问题 可以通过方法三解决方法一 在程序最前面加 define CRT SECURE NO DEPRECATE 方法二
  • k8s中通过ingress暴露多端口deployment

    前言 项目中有一个notify微服务 业务逻辑上 需要在web界面上操作发送模板 微服务 和推送 websocket 因此需要将后端的微服务和websocket同时对外暴露 前端web界面操作时需要走外网 同时实现微服务内部之间和notif
  • 树莓派4B使用串口登录的设置方法

    特别提示 本文具有时效性 当前我使用的是pi4硬件 镜像版本 raspberrypi 5 15 61 32位 在我解决该问题的时候 在网上查找了很多方法 有些方法被实际测试发现是不行的 所以 请注意随时间的推移有可能我的这些解决方法并不一定
  • 配置可视化docker+ROS环境

    一直以来 我以为docker是没有图形界面的 我就用它做过编译服务 构建编译环境 时隔多年 再次用到 它居然支持了 1 docker图形界面配置 主机端运行命令 xhost 使能宿主机接收其他客户端的显示需求 docker端配置显示参数 e
  • 推荐系统(3)---寻找数据集中的相似用户

    寻找数据集中的相似用户 coding utf 8 寻找数据集中的相似用户 import json import numpy as np 计算user1 和 user2的相关系数 def pearson score dataset user1
  • Leetcode 150.逆波兰表达式求值(以及字符串比较时遇到的问题)

    题目 根据 逆波兰表示法 求表达式的值 有效的算符包括 每个运算对象可以是整数 也可以是另一个逆波兰表达式 注意 两个整数之间的除法只保留整数部分 可以保证给定的逆波兰表达式总是有效的 换句话说 表达式总会得出有效数值且不存在除数为 0 的
  • ThreadPoolTaskScheduler实现动态管理定时任务

    最近 有个项目有需要用到定时任务 所以做了一个动态管理定时任务的模块 本文将从项目背景 需求 选型 思路 具体实现等方面展开介绍 背景 有个支付类的项目 中间会产生一些中间态的订单 需要有个定时任务轮询确认订单状态 该类项目体量较小 单节点
  • [数据库] SQL语句select简单记录总结

    最近SQL语句写得比较多 也发现了自己的很多不足之处 在此先写一篇关于SQL语句的在线笔记 方便大家学习和后面的工作 SQL Server MySQL Oracle基本语法都类似 接下来我需要阅读 SQL Server性能优化与管理的艺术
  • 【漏洞一】检测到目标URL存在http host头攻击漏洞

    漏洞 检测到目标URL存在http host头攻击漏洞 原因 在项目中使用了 request getServerName 导致漏洞的出现 不要使用request中的serverName 也就是说host header可能会在攻击时被篡改 依
  • 回归分析常数项t值没有显著异于零怎么办_一文详解经典回归分析

    在如今机器学习 数据科学 人工智能热潮下 回归分析似乎成了家喻户晓的东西 实际上回归分析自Galton爵士提出以及Pearson和Fisher的理论的加持 经过一百多年的发展 早已成了发现客观规律的有力武器 回归分析的文章已经多得数不胜数了
  • Go语言中的函数字面量与匿名函数

    写在前面 习惯性的在写内容前说点儿什么 个人感觉Go语言中的函数字面量这个东西用着不是很顺手 所以想着总结一下 今天先从简单的开始 持续更新 给出概念 命名函数的作用范围是包级别的 这个大家都知道 如果想在程序的任意表达式中使用一个变量来表
  • 小谈移动端加密

    加密方式大致分为以下几种 哈希 散列函数 MD5 SHA1 SHA256 512 对称加密算法 DES 3DES AES 高级密码标准 美国国家安全局使用的加密算法 非对称加密算法 RSA 很多项目中都用到了MD5 它是一种不可逆算法 相同
  • 【数据结构初阶】单链表OJ题

    博客主页 CS semi主页 欢迎关注 点赞收藏 留言 系列专栏 数据结构初阶 代码仓库 Data Structure 家人们更新不易 你们的点赞和关注对我而言十分重要 友友们麻烦多多点赞 关注 你们的支持是我创作最大的动力 欢迎友友们私信
  • 透视投影(Perspective Projection)变换推导

    透视投影是3D固定流水线的重要组成部分 是将相机空间中的点从视锥体 frustum 变换到规则观察体 Canonical View Volume 中 待裁剪完毕后进行透视除法的行为 在算法中它是通过透视矩阵乘法和透视除法两步完成的 透视投影