本文作为课程作业记录,仅译出原文Single View Metrology中有关3D视觉理论的部分,而没有译出有关不确定性算法校准的部分。

Abstract

本文描述如何通过只给出从图像确定的最小几何信息的单透视图来计算3D仿射量。其中有代表性的最小信息有基准平面的消失线和不平行于此平面的方向消失点。结果表明,即使没有相机校准的知识(例如焦距),也没有相机和环境的明确关系(例如姿势),依然可以从图像中确定仿射场景结构。

具体而言,本文展示如何(1)在带有一个公共的缩放系数下,计算基准面和与之平行的平面的距离;(2)计算基准面和任何与之平行的平面的长度与面积比;(3)确定相机位置。从这些成果中可以引申出一个简单的几何学。

在此基础上,本文用python复现了论文《Single View Metrology》1中的一些示例结果。

关键词:3D重建;视频测量;摄影测量法

Geometry

在本文中,相机模型是一个中心投影。我们假设在场景中,基准面的消失线可以在图像上测量得出,另一个方向(不平行于此平面)的消失点也是如此。这些信息总体上可以容易地从有结构的场景的图片中获得。例如径向畸变(通常在安保摄像头上使用广角镜头会略微出现)等等会破坏中心投影的影响普遍可以被修复,因此对我们的方法无害。

虽然示意图会展示出相机中心处于一个有限的位置,我们推导的结果仍然对相机中心处于无穷远,或者说图像通过平行投影得出的情况有效。

关于平面的消失线和消失点的基础理论在图1中说明。基准面的消失线l\mathbf{l}l是基准面上的直线的无穷远点在图像上的投影。消失点v\mathbf{v}v是基准方向上无穷远点在图像上的点。要注意到,虽然为了清晰直白,我们通常倾向于将消失点作为"竖直"消失点,这样图像上的消失点就是相机中心在基准面的竖直落脚点,但是基准方向不必是竖直的。同理,基准面通常但不是必须是地平面,这样消失线就是为人熟知的"地平线"。

图 1 基础理论:一个平面与基准面平行,穿过相机中心,平面的消失线l\mathbf{l}l是此平面与图像平面的相交线。消失点v\mathbf{v}v是经过相机中心、与基准方向平行的线和图像平面的相交点。

可以看到,消失线隔开了场景空间的所有点。任何投影在消失线上的点与基准面的距离和相机中心一样高。在其之上则比相机中心距离基准面更远,在其之下则比相机中心距离基准面更近。

2.1 Measurements Between Parallel Planes

我们希望通过图像上两个点x\mathbf{x}x和x′\mathbf{x'}x′测量两个平行平面在基准方向上的距离。图2通过对应点x\mathbf{x}x和x′\mathbf{x'}x′展示了这个理论。我们用大写字母X\mathbf{X}X表示在空间中的点,小写x\mathbf{x}x表示图像上的点。

定义1.
如果穿过两点X\mathbf{X}X和X′\mathbf{X'}X′的线与基准方向平行,那么分开平面上(都平行于基准面)的两点X\mathbf{X}X和X′\mathbf{X'}X′相对应

因此对应点和消失点共线。例如如果方向是竖直的话,人的头顶和落脚点对应。如果这两点实际距离已知,那么就称为基准距离。

理论1.
给出基准面的消失线和基准方向的消失点,可以计算出带有公共缩放系数的消失线到消失点的距离。这个缩放系数可以通过已知基准长度确定。

图 2 两个平面间的距离与相机中心到两者其中一个平面的距离有关:(a)实际(b)图像。在平面π\mathbf{\pi}π上的点x\mathbf{x}x与平面π′\mathbf{\pi'}π′上的点x′\mathbf{x'}x′对应,一条线上四个对齐的点x,x′,v\mathbf{x,x',v}x,x′,v与消失线交点c\mathbf{c}c定义了交叉比。交叉比的值确定了平面间实际距离的比值。

证明:在图 2(b)中已标记的四点x,x′,c,v\mathbf{x,}\mathbf{x'}\mathbf{,c,v}x,x′,c,v定义了交叉比。消失点是图像上的场景中的一个无穷远点。鉴于c\mathbf{c}c点在消失线上,c\mathbf{c}c点是一个到平面π\mathbf{\pi}π距离ZcZ_{c}Zc​的点,其中ZcZ_{c}Zc​是相机中心到平面π\mathbf{\pi}π的距离。与ZcZ_{c}Zc​相关联的交叉比的值确定了穿过X\mathbf{X}X和X′\mathbf{X'}X′的平面之间的距离ZZZ的仿射长度比(或者说π′\mathbf{\pi'}π′取决于交叉比的次序)。要注意到,距离ZZZ也可以用线间单应变换来计算,来回避交叉比次序的歧义。

从图 2(b)我们可以得出

d(x,c)d(x′,v)d(x′,c)d(x,v)=d(X,C)d(X′,V)d(X′,C)d(X,V)(1)\frac{d\left( \mathbf{x,c} \right)d\left( \mathbf{x'}\mathbf{,v} \right)}{d\left( \mathbf{x'}\mathbf{,c} \right)d\left( \mathbf{x,v} \right)} = \frac{d\left( \mathbf{X,C} \right)d\left( \mathbf{X'}\mathbf{,V} \right)}{d\left( \mathbf{X'}\mathbf{,C} \right)d\left( \mathbf{X,V} \right)}\tag{1} d(x′,c)d(x,v)d(x,c)d(x′,v)​=d(X′,C)d(X,V)d(X,C)d(X′,V)​(1)

其中d(x1,x2)d(\mathbf{x_1,x_2})d(x1​,x2​)是俩一般点x1,x2\mathbf{x_1,x_2}x1​,x2​间的距离。鉴于点v\mathbf{v}v
反向投影到无穷远点有d(X′,V)/d(X,V)=1d(\mathbf{X',V})/d(\mathbf{X,V}) = 1d(X′,V)/d(X,V)=1,所以(1)中右手边可以归约为Zc/(Zc−Z)Z_{c}/(Z_{c} - Z)Zc​/(Zc​−Z)。简单的代数操作即可得出

ZZc=1−d(x,c)d(x′,v)d(x′,c)d(x,v)(2)\frac{Z}{Z_{c}} = 1 - \frac{d\left( \mathbf{x,c} \right)d\left( \mathbf{x',v} \right)}{d\left( \mathbf{x',c}\right)d\left( \mathbf{x,v} \right)}\tag{2} Zc​Z​=1−d(x′,c)d(x,v)d(x,c)d(x′,v)​(2)

一旦相机距离ZcZ_{c}Zc​确定,距离ZZZ也一并可获得。

然而实践上更常见的是通过另外一种测量方法在图像上获得距离ZZZ,也就是基准长度。事实上,给出一个已知基准距离ZrZ_{r}Zr​,通过(2)我们可以计算出ZcZ_{c}Zc​从而将公式应用到新的一对端点并计算出ZZZ。

下面我们推广理论1。

定义2.
如果通过对应点的约束链可以从一个平面集合内一个平面到另一个任意平面,则这个集合内的平面是被链接的

图 3 两个平面间距离与另外两个平面间距离有关系:(a)实际(b)图像。平面π\mathbf{\pi}π上的点x\mathbf{x}x对应平面π′\mathbf{\pi'}π′上的点x′\mathbf{x'}x′。点s1\mathbf{s}_{\mathbf{1}}s1​对应点s2\mathbf{s}_{\mathbf{2}}s2​。点r1\mathbf{r_1}r1​对应点r2\mathbf{r_2}r2​。R1\mathbf{R_1}R1​和R2\mathbf{R_2}R2​的实际距离ZrZ_{r}Zr​已知,且作为基准值计算ZZZ

理论2.
给出一个被链接的平面集合,任何一对平面间距离足以确定另一对任意平面间的绝对距离。链接的来源是对应点的约束链。

证明: 图3展示了四个平行的平面。注意它们共享了同一条消失线,同时也是多条轴的消失线。它们间距离ZrZ_{r}Zr​可以作为基准来计算另外两个的距离ZZZ。

  • 从四个对齐点v,cr,r2,r1\mathbf{v,c_r,r_2,r_1}v,cr​,r2​,r1​定义的交叉比和已知点R1,R2\mathbf{R_1,R_2}R1​,R2​距离ZrZ_{r}Zr​可以计算出从平面πr\mathbf{\pi_r}πr​到相机间的距离。

  • 四个对齐点v,cs,s2,s1\mathbf{v,c_s,s_2,s_1}v,cs​,s2​,s1​定义的交叉比和相机距离确定了平面πr\mathbf{\pi_r}πr​到π\mathbf{\pi}π间距离。相机到平面π\mathbf{\pi}π的距离ZcZ_{c}Zc​也因此确定。

  • 现在可以在(2)中用ZcZ_{c}Zc​计算平面π\mathbf{\pi}π到π′\mathbf{\pi'}π′间距离ZZZ。

2.2 Measurements on Parallel Planes

如果基准平面π\piπ经过仿射校准(即已知它消失线),从图像度量值上我们可以计算:

  1. 平面上平行线段的长度比
  2. 平面上面积之比

另外,消失线被平行于基准面的一束平面共享,于是从束中其他任意平面都可以得出仿射度量值。然而,即使如面积比这样的仿射度量值可以在一个特定的平面得出,但是在不同平面上的区域面积不能直接比较。如果从一个平面到另一个平面平行投影一个区域,由于两个区域都在同一个平面,所以可以得出仿射度量值。平行投影不改变仿射属性。

两个平行平面实际上的映射关系诱导出在图像上两个平面内的点的投影映射关系。这个图像映射是平面同调关系。这个关系是带有五个自由度的投影变换。它具有一条线上的固定点,称为,和单独一个不在轴上的固定点,称为顶点。依据反映在图像上的三维空间透视,平面同调关系很自然就可以产生。

在这里,平面消失线和竖直消失点分别是轴和顶点。同调关系可以参数化为

H~=I+μvl⊤v⋅l(3)\widetilde{H} = I + \mu\frac{\mathbf{v}\mathbf{l}^{\top}}{\mathbf{v} \cdot \mathbf{l}}\tag{3}H=I+μv⋅lvl⊤​(3)

其中v\mathbf{v}v是消失点,l\mathbf{l}l是平面消失线,μ\muμ是缩放系数。v\mathbf{v}v和l\mathbf{l}l确定了四个同调关系自由度。剩下的自由度μ\muμ是由任意一对对应点唯一确定。一旦矩阵H~\widetilde{H}H计算出来,平面上的每个点都可以被转换成对应点,即x′=H~x\mathbf{x'} = \widetilde{H}\mathbf{x}x′=Hx。

因此我们可以比较两个分开平面上的度量值。尤其是可以计算:

  1. 平行线各在自己的平面上的长度之间的比。
  2. 各在自己平面上的面积之比

事实上我们可以用同调关系从一个平面上转换所有点到基准平面上。然后从已知的基准面消失线得出仿射度量值。

2.3 确定相机位置

在2.1节中我们依据相机到基准面的距离计算出平面间距离比。反其道行之,我们可以从一个特定已知平面的单独的基准距离ZrZ_{r}Zr​计算出相机距离ZcZ_{c}Zc​。再者,考虑图1,相机位置对于基准面似乎是竖直消失点对于基准面的反投影。这个反投影已经被从图像到基准面的单应投影完成了(反之亦然)。即使实际场景的坐标框架选择有点随意,框架一固定,单应关系以及相机位置就立刻被定义。

代数形式表示

前面的章节描述基于交叉比计算度量值。在这一节我们延伸出一个独特的代数方法。这对构建几何有几个好处。第一是它回避了交叉比次序的潜在问题。第二是它可以让我们处理极小值和普遍的过度约束设置。第三我们在一个表示形式上整合了不同类型的度量值。第四可以进行不确定性分析。

首先我们在空间内定义一个仿射坐标系XYZXYZXYZ。让原点位于基准面内,并在平面上生成XXX和YYY轴。ZZZ轴是基准方向。图像坐标系就是通常的xyxyxy仿射图像框架。空间上的一个点X\mathbf{X}X通过一个3×43 \times 43×4的投影矩阵PPP投影到图像点x\mathbf{x}x:

x=PX=[p1p2p3p4]X\mathbf{x} = P\mathbf{X} = \begin{bmatrix} \mathbf{p_1} & \mathbf{p_2} & \mathbf{p_3} & \mathbf{p_4} \\ \end{bmatrix}\mathbf{X}x=PX=[p1​​p2​​p3​​p4​​]X

其中x\mathbf{x}x和X\mathbf{X}X是形如x=(x,y,w)⊤,X=(X,Y,Z,W)⊤\mathbf{x} = (x,y,w)^{\top},\mathbf{X} = (X,Y,Z,W)^{\top}x=(x,y,w)⊤,X=(X,Y,Z,W)⊤的齐次向量。"==="意思是带一个缩放系数下相等。

如果我们用消失点来分别指示出X,Y,ZX,Y,ZX,Y,Z方向vX,vY,v\mathbf{v}_{X},\mathbf{v}_{Y},\mathbf{v}vX​,vY​,v,显然可以检验PPP的前三列是消失点:vX=p1,vY=p2,v=p3\mathbf{v}_{X} = \mathbf{p_1},\mathbf{v}_{Y} = \mathbf{p_2},\mathbf{v =}\mathbf{p_3}vX​=p1​,vY​=p2​,v=p3​,最后一列则是实际空间坐标系原点o=p4\mathbf{o}\mathbf{=}\mathbf{p_4}o=p4​。由于我们选择的坐标框架在基准面上的X,YX,YX,Y轴p1=vX,p2=vY\mathbf{p_1}\mathbf{=}\mathbf{v}_{X},\mathbf{p_2}\mathbf{=}\mathbf{v}_{Y}p1​=vX​,p2​=vY​是在消失线上的两个单独的点,选择这些点会固定X,YX,YX,Y轴,我们将消失线表示为l\mathbf{l}l,为了强调vX,vY\mathbf{v}_{X},\mathbf{v}_{Y}vX​,vY​在消失线上,我们将它们表示为l1⊥,l2⊥\mathbf{l}_{\mathbf{1}}^{\mathbf{\bot}}\mathbf{,}\mathbf{l}_{\mathbf{2}}^{\mathbf{\bot}}l1⊥​,l2⊥​,并且li⊥⋅l=0\mathbf{l}_{i}^{\mathbf{\bot}}\mathbf{\cdot l} = 0li⊥​⋅l=0。

投影矩阵的1,2,4列是基准面到图像的单应矩阵的三列。单应矩阵必须要秩为3,不然从基准面到图像的映射会退化。另外,最后一列(坐标原点)不能在消失线上,不然三点共线,列之间不再线性无关。于是我们将其设为p4=l/∥l∥=l‾\mathbf{p_4}\mathbf{= l/\| l\| =}\overline{\mathbf{l}}p4​=l/∥l∥=l。

因此投影矩阵PPP的参数化形式为

P=[l1⊥l2⊥αvl‾](4)P = \begin{bmatrix} \mathbf{l}_{\mathbf{1}}^{\mathbf{\bot}} & \mathbf{l}_{\mathbf{2}}^{\mathbf{\bot}} & \alpha\mathbf{v} & \overline{\mathbf{l}} \\ \end{bmatrix}\tag{4}P=[l1⊥​​l2⊥​​αv​l​](4)

其中α\alphaα是缩放系数。

要注意到竖直消失点v\mathbf{v}v对矩阵P附加了两个约束、l\mathbf{l}l有两个、α\alphaα有一个,总共五个约束。(目前前两列不完全已知,唯一约束仅仅只是垂直于l\mathbf{l}l)。然而一般而言PPP矩阵有十一个自由度,可以认为包括从基准面诱导的从实际场景到图像的单应矩阵的八个、消失点的两个、仿射参数α\alphaα的一个自由度。这里消失线确定了单应矩阵的八个自由度中的两个。

3.1 平行平面间的测量

3.1.1平面到基准面π\mathbf{\pi}π的距离

我们希望通过场景中X\mathbf{X}X和X′\mathbf{X}\mathbf{'}X′测量两个平面的距离。两个点可以选择为X=(X,Y,0)⊤,X′=(X,Y,Z)⊤\mathbf{X} = (X,Y,0)^{\top},\mathbf{X'} = (X,Y,Z)^{\top}X=(X,Y,0)⊤,X′=(X,Y,Z)⊤,它们的映射是x\mathbf{x}x和x′\mathbf{x'}x′。如果PPP是投影矩阵,那么图像坐标为

x=P(XY01),x′=P(XYZ1)\mathbf{x} = P\begin{pmatrix} X \\ Y \\ 0 \\ 1 \\ \end{pmatrix},\mathbf{x'} = P\begin{pmatrix} X \\ Y \\ Z \\ 1 \\ \end{pmatrix}x=P⎝⎛​XY01​⎠⎞​,x′=P⎝⎛​XYZ1​⎠⎞​

上面的等式可以写成

x=ρ(Xp1+Yp2+p4)(5)\mathbf{x} = \rho\left( X\mathbf{p_1} + Y\mathbf{p_2} + \mathbf{p_4} \right)\tag{5}x=ρ(Xp1​+Yp2​+p4​)(5)
x′=ρ′(Xp1+Yp2+Zp3+p4)(6)\mathbf{x'} = \rho'\left( X\mathbf{p_1} + Y\mathbf{p_2} + Z\mathbf{p_3} + \mathbf{p_4} \right)\tag{6}x′=ρ′(Xp1​+Yp2​+Zp3​+p4​)(6)

其中ρ\rhoρ和ρ′\rho'ρ′是未知放缩系数。pi\mathbf{p}_{i}pi​是矩阵PPP的第iii列。

由于p1⋅l‾=p2⋅l‾=0\mathbf{p_1}\mathbf{\cdot}\overline{\mathbf{l}}\mathbf{=}\mathbf{p_2}\mathbf{\cdot}\overline{\mathbf{l}} = 0p1​⋅l=p2​⋅l=0,p4⋅l‾=1\mathbf{p_4}\mathbf{\cdot}\overline{\mathbf{l}} = 1p4​⋅l=1,用l‾\overline{\mathbf{l}}l点乘(5)得到ρ=l‾⋅x\rho = \overline{\mathbf{l}}\mathbf{\cdot}\mathbf{x}ρ=l⋅x,于是(6)可以写成

x′=ρ′(xρ+αZv)(7)\mathbf{x'} = \rho'\left( \frac{\mathbf{x}}{\rho} + \alpha Z\mathbf{v} \right)\tag{7}x′=ρ′(ρx​+αZv)(7)

用x′\mathbf{x}\mathbf{'}x′向量乘(7)中每一项得到

x×x′=−αZρ(v×x′)(8)\mathbf{x \times x'} = - \alpha Z\rho\left( \mathbf{v \times}\mathbf{x'} \right)\tag{8}x×x′=−αZρ(v×x′)(8)

最后,(8)两边取绝对值得到

αZ=−∥x×x′∥(l‾⋅x)∥v×x′∥(9)\alpha Z = - \frac{\left\| \mathbf{x \times x'} \right\|}{\left( \overline{\mathbf{l}}\mathbf{\cdot}\mathbf{x} \right)\left\| \mathbf{v \times}\mathbf{x'} \right\|}\tag{9} αZ=−(l⋅x)∥v×x′∥∥x×x′∥​(9)

由于αZ\alpha ZαZ是α\alphaα的线性放缩,仿射结构已经得出了。如果α\alphaα已知,ZZZ的度量值也可以立刻计算出:

Z=−∥x×x′∥(p4⋅x)∥p3×x′∥(10)Z = - \frac{\left\| \mathbf{x \times x'} \right\|}{\left( \mathbf{p_4}\mathbf{\cdot}\mathbf{x} \right)\left\| \mathbf{p_3}\mathbf{\times}\mathbf{x'} \right\|}\tag{10} Z=−(p4​⋅x)∥p3​×x′∥∥x×x′∥​(10)

反过来,如果ZZZ已知(例如它是一个基准距离),(9)也提供计算α\alphaα的一个方法,并因此移除了仿射歧义。

从多基准值进行度量校准

如果不只一个基准距离已知,α\alphaα的估计值可以由一个误差最小化算法衍生。这里展示当从基准面出发的距离都被测量的情况,并最小化其代数误差。

对于第iii个以点ri,ri′\mathbf{r}_i\mathbf{,}\mathbf{r}_i'ri​,ri′​为端点基准距离ZiZ_{i}Zi​,我们定义βi=∥ri×ri′∥,ρi=l‾⋅ri,γi=∥v×ri′∥\beta_{i} = \left\| \mathbf{r}_{i}\mathbf{\times}\mathbf{r}_i' \right\|,\rho_{i} = \overline{\mathbf{l}}\mathbf{\cdot}\mathbf{r}_{i}\mathbf{,}\gamma_{i} = \left\| \mathbf{v \times}\mathbf{r}_i' \right\|βi​=∥ri​×ri′​∥,ρi​=l⋅ri​,γi​=∥v×ri′​∥,于是从(9)我们得到

αZρiγi=−βi(11)\alpha Z\rho_{i}\gamma_{i} = - \beta_{i}\tag{11}αZρi​γi​=−βi​(11)

现在定义n×2n \times 2n×2矩阵AAA(对(11)重新组织得)

A=(Z1ρ1γ1β1⋮⋮Ziρiγiβi⋮⋮Znρnγnβn)A = \begin{pmatrix} Z_{1}\rho_{1}\gamma_{1} & \beta_{1} \\ \vdots & \vdots \\ Z_{i}\rho_{i}\gamma_{i} & \beta_{i} \\ \vdots & \vdots \\ Z_{n}\rho_{n}\gamma_{n} & \beta_{n} \\ \end{pmatrix}A=⎝⎛​Z1​ρ1​γ1​⋮Zi​ρi​γi​⋮Zn​ρn​γn​​β1​⋮βi​⋮βn​​⎠⎞​

其中nnn是基准距离的数量。如果没有测量误差,或者n=1n = 1n=1则有As=0A\mathbf{s}\mathbf{= 0}As=0,其中s=(s1s2)⊤\mathbf{s} = \left( s_{1}\quad s_{2} \right)^{\top}s=(s1​s2​)⊤是一个齐次2维向量,且

α=s1s2(12)\alpha = \frac{s_{1}}{s_{2}}\tag{12}α=s2​s1​​(12)

通常情况下n>1n>1n>1,且基准距离都有不确定性,在此情况下,我们找寻令∥As∥\Vert A\mathbf{s} \Vert∥As∥取最小值的解。那就是对应2×22 \times 22×2的矩阵M=A⊤AM = A^{\top}AM=A⊤A的最小特征值的特征向量。此时α\alphaα仍然可以通过(12)计算。

3.1.2两个平行平面间的距离

投影矩阵PPP只定义在基准面上。在这一节我们根据平行平面π′\mathbf{\pi'}π′确定投影矩阵P′P'P′,以及如何计算到平面π′\mathbf{\pi'}π′的距离。

图 4 度量平行于基准面πππ的任意两个平面π′,π′′π',π''π′,π′′间的距离

假设实际坐标通过基准方向上的ZrZ_{r}Zr​从平面π\mathbf{\pi}π变换到π′\mathbf{\pi'}π′(图 4),我们可以参数化新投影矩阵P′P'P′为

P′=[p1p2p3Zrp3+p4](13)P' = \begin{bmatrix} \mathbf{p_1} & \mathbf{p_2} & \mathbf{p_3} & Z_{r}\mathbf{p_3}\mathbf{+}\mathbf{p_4} \\ \end{bmatrix}\tag{13}P′=[p1​​p2​​p3​​Zr​p3​+p4​​](13)

π′,π′′\mathbf{\pi'}\mathbf{,\pi}\mathbf{''}π′,π′′间的距离Z′Z'Z′可以计算

Z′=−∥x′×x′′∥ρ′∥p3×x′′∥(14)Z' = - \frac{\Vert \mathbf{x'}\mathbf{\times}\mathbf{x''} \Vert}{\rho'\left\| \mathbf{p_3}\mathbf{\times}\mathbf{x}^{\mathbf{''}} \right\|}\tag{14}Z′=−ρ′∥p3​×x′′∥∥x′×x′′∥​(14)

其中

ρ′=x′⋅p41+Zrp3⋅p4\rho' = \frac{\mathbf{x'}\mathbf{\cdot}\mathbf{p_4}}{1 + Z_{r}\mathbf{p_3}\mathbf{\cdot}\mathbf{p_4}}ρ′=1+Zr​p3​⋅p4​x′⋅p4​​

3.2 平行平面上的测量

正如在2.2节所描述的,给出平面π\mathbf{\pi}π到π′\mathbf{\pi'}π′同调矩阵我们就可以让一个平面上的所有点转换到另一个平面,从而在另一个平面上得出仿射度量值。同调矩阵可以直接从投影矩阵中得出。平面到图像的单应矩阵就是忽略第三列的投影矩阵

H=[p1p2p4],H′=[p1p2Zrp3+p4]H = \begin{bmatrix} \mathbf{p_1} & \mathbf{p_2} & \mathbf{p_4} \\ \end{bmatrix},H' = \begin{bmatrix} \mathbf{p_1} & \mathbf{p_2} & Z_{r}\mathbf{p_3}\mathbf{+}\mathbf{p_4} \\ \end{bmatrix}H=[p1​​p2​​p4​​],H′=[p1​​p2​​Zr​p3​+p4​​]

于是H~=H′H−1\widetilde{H} = H'H^{- 1}H=H′H−1是图像上在平面π\mathbf{\pi}π的点到π′\mathbf{\pi'}π′的映射,而且定义了同调矩阵。通过检验,由于p1⋅p4=p2⋅p4=0\mathbf{p_1}\mathbf{\cdot}\mathbf{p_4}\mathbf{=}\mathbf{p_2}\mathbf{\cdot}\mathbf{p_4} = 0p1​⋅p4​=p2​⋅p4​=0,所以(I+Zrp3p4⊤)H=H′\left( I + Z_{r}\mathbf{p_3}\mathbf{p_4}^{\mathbf{\top}} \right)H = H'(I+Zr​p3​p4​⊤)H=H′,于是同调矩阵:

H~=I+Zrp3p4⊤(15)\widetilde{H} = I{+ Z}_{r}\mathbf{p_3}\mathbf{p_4}^{\mathbf{\top}}\tag{15} H=I+Zr​p3​p4​⊤(15)

另一方面,从(4)同调矩阵可写为

H~=I+ψvl‾⊤(16)\widetilde{H} = I + \psi\mathbf{v}{\overline{\mathbf{l}}}^{\mathbf{\top}}\tag{16} H=I+ψvl⊤(16)

其中v\mathbf{v}v是竖直消失点,l‾\overline{\mathbf{l}}l是平面消失线的正则化,ψ=αZr\psi = \alpha Z_{r}ψ=αZr​(参考(3))。

如果ZrZ_{r}Zr​且矩阵PPP后两列已知,同调矩阵就可以用(15)计算,如果只有v\mathbf{v}v,l‾\overline{\mathbf{l}}l已知,对应点r,r′\mathbf{r,r'}r,r′可见,那么同调参数ψ\psiψ可以用(9)计算(因为αZr=ψ\alpha Z_{r} = \psiαZr​=ψ)而不需要知道α,Zr\alpha,Z_{r}α,Zr​的值。

3.3 确定相机位置

假设相机中心是C=(Xc,Yc,Zc.Wc)⊤\mathbf{C} = \left( X_{c},Y_{c},Z_{c}.W_{c} \right)^{\top}C=(Xc​,Yc​,Zc​.Wc​)⊤,于是由于PC=0P\mathbf{C = 0}PC=0,有

PC=p1Xc+p2Yc+p3Zc+p4Wc=0(17)P\mathbf{C}\mathbf{=}\mathbf{p_1}X_{c}\mathbf{+}\mathbf{p_2}Y_{c}\mathbf{+}\mathbf{p_3}Z_{c}\mathbf{+}\mathbf{p_4}W_{c}\mathbf{= 0}\tag{17}PC=p1​Xc​+p2​Yc​+p3​Zc​+p4​Wc​=0(17)

给出问题的解答(通过克莱姆法则)

Xc=−det⁡[p2p3p4]Yc=det⁡[p1p3p4]Zc=−det⁡[p1p2p4]Wc=det⁡[p1p2p3](18)\begin{matrix} X_{c} &=& - \det\begin{bmatrix} \mathbf{p_2} & \mathbf{p_3} & \mathbf{p_4} \\ \end{bmatrix} \\ Y_{c} &=& \det\begin{bmatrix} \mathbf{p_1} & \mathbf{p_3} & \mathbf{p_4} \\ \end{bmatrix} \\ Z_{c} &=& - \det\begin{bmatrix} \mathbf{p_1} & \mathbf{p_2} & \mathbf{p_4} \\ \end{bmatrix} \\ W_{c} &=& \det\begin{bmatrix} \mathbf{p_1} & \mathbf{p_2} & \mathbf{p_3} \\ \end{bmatrix} \\ \end{matrix}\tag{18} Xc​Yc​Zc​Wc​​====​−det[p2​​p3​​p4​​]det[p1​​p3​​p4​​]−det[p1​​p2​​p4​​]det[p1​​p2​​p3​​]​(18)

于是相机中心也被定义了。如果α\alphaα未知,我们可以

Xc=−det⁡[p2vp4]Yc=det⁡[p1vp4]αZc=−det⁡[p1p2p4]Wc=det⁡[p1p2v](19)\begin{matrix} X_{c} &=& - \det\begin{bmatrix} \mathbf{p_2} & \mathbf{v} & \mathbf{p_4} \\ \end{bmatrix} \\ Y_{c} &=& \det\begin{bmatrix} \mathbf{p_1} & \mathbf{v} & \mathbf{p_4} \\ \end{bmatrix} \\ \alpha Z_{c} &=& - \det\begin{bmatrix} \mathbf{p_1} & \mathbf{p_2} & \mathbf{p_4} \\ \end{bmatrix} \\ W_{c} &=& \det\begin{bmatrix} \mathbf{p_1} & \mathbf{p_2} & \mathbf{v} \\ \end{bmatrix} \\ \end{matrix}\tag{19} Xc​Yc​αZc​Wc​​====​−det[p2​​v​p4​​]det[p1​​v​p4​​]−det[p1​​p2​​p4​​]det[p1​​p2​​v​]​(19)

来获得带有一个仿射放缩系数α\alphaα的距离ZcZ_{c}Zc​。如果是以前,我们需要利用α\alphaα的知识来更新ZcZ_{c}Zc​,或者需要相机高度的知识来计算α\alphaα,从而更新仿射框架。

可以注意到,仿射观察条件(相机中心在无穷远点)在(18)(19)上没有问题。因为其实我们可以让l‾=[00∗]⊤,v=[∗∗0]⊤\overline{\mathbf{l}} = \begin{bmatrix}0 & 0 & *\\ \end{bmatrix}^{\top},\mathbf{v} = \begin{bmatrix}* & * & 0 \\\end{bmatrix}^{\top}l=[0​0​∗​]⊤,v=[∗​∗​0​]⊤。由于
Wc=0W_{c} = 0Wc​=0,我们此时获得在平面无穷远点的相机中心。在π∞\mathbf{\pi}_{\mathbf{\infty}}π∞​的点代表平行投影的观察方向。

如果观察点是有限的(即不是仿射观察条件),αZc\alpha Z_{c}αZc​的公式可以更进一步,通过两边标量乘l‾\overline{\mathbf{l}}l可以得到

αZc=−1l‾⋅v(20)\alpha Z_{c} = - \frac{1}{\overline{\mathbf{l}} \cdot \mathbf{v}}\tag{20} αZc​=−l⋅v1​(20)

代码复现

在这一节中我们复现了论文《Single View Metrology》中的一些示例结果。

图 5展示了怎么在额外给出一个垂直基准距离下计算人的升高。图 6展示了如何测量水平线到地面的高度。图 6的流程如下:

  • 通过相交的(场景中)竖直边缘计算竖直消失点v\mathbf{v}v。

所有与地面平行的线都交于地平线上的点,则

  • 通过右边木板的边缘计算地平线上的交点v1\mathbf{v}_{1}v1​。
  • 通过左边的木板和房顶计算另一个交点v2\mathbf{v}_{2}v2​。
  • 通过两个点算出平面消失线l\mathbf{l}l(l=v1×v2\mathbf{l} = \mathbf{v}_{1}\mathbf{\times}\mathbf{v}_{2}l=v1​×v2​)。
  • 通过基准距离用(9)算出α\alphaα。
  • 选择lx′\mathbf{l}_{x'}lx′​上的任意两点来构造平行线lx′\mathbf{l}_{x'}lx′​。
  • 可以算出与之有关的消失点vh(vh=lx′×l)\mathbf{v}_{h}(\mathbf{v}_{h} = \mathbf{l}_{x'} \times \mathbf{l})vh​(vh​=lx′​×l)。
  • 与lx′\mathbf{l}_{x'}lx′​平行的直线lx\mathbf{l}_{x}lx​必须经过点vh\mathbf{v}_{h}vh​,再另外选择一个点就可以确定lx\mathbf{l}_{x}lx​。
  • 从lx′\mathbf{l}_{x'}lx′​中选择一点x′\mathbf{x'}x′,可以计算在lx\mathbf{l}_{x}lx​上与之对应的点x=(x′×v)×lx\mathbf{x}\mathbf{=}\left( \mathbf{x'}\mathbf{\times}\mathbf{v} \right)\mathbf{\times}\mathbf{l}_{x}x=(x′×v)×lx​。
  • 用(10)可以算出两点间距离ZZZ


图 5 从单视图中测量人的身高:(a)原图(b)示例(ccc)复现结果。在示例中消失线以白色线表示,基准距离是右边的窗框高度。在复现结果中用于确定消失点vx,vy,v\mathbf{v}_{x},\mathbf{v}_{y},\mathbf{v}vx​,vy​,v的平行线以蓝色线表示。消失线以红色线表示。基准距离是柱高度201cm以紫色线表示。身高以黄色线表示,结果为178.08cm。

图 6 利用平行线计算高度:(a)示例(b)复现结果。在上方的蓝色线是lx′\mathbf{l}_{x'}lx′​,在下方的是lx\mathbf{l}_{x}lx​。竖直的蓝色线经过竖直消失点。x,x′\mathbf{x},\mathbf{x'}x,x′是一对对应点,分别与窗上边缘和地面在同一平面,计算结果297.25cm。

在这步骤中计算α\alphaα的代码如下

def cal_alpha(Z: list, r1: list, r2: list, v, l):alpha=0beta_i = rho_i = gamma_i = 0A = np.zeros([len(Z), 2])for i in range(len(Z)):beta_i = np.linalg.norm(np.cross(r1[i], r2[i]))l_bar = l / np.linalg.norm(l) #l的正则化rho_i = np.dot(l_bar, r1[i])gamma_i = np.linalg.norm(np.cross(v, r2[i]))A[i, 0] = Z[i] * rho_i * gamma_iA[i, 1] = beta_iif len(Z) == 1:#只有一个基准距离alpha = (-1.0 * beta_i) / (Z[0] * rho_i * gamma_i)else:M = np.dot(A.T, A)lam,xi = np.linalg.eig(M)#计算特征值和向量s = xi[:,np.argmin(lam)]#取最小特征值的特征向量alpha = s[0] / s[1]return alpha

计算距离Z的代码为

'''
其他代码中已定义以下内容
P = np.zeros([3, 4])
p1 = P[:, 0]
p2 = P[:, 1]
p3 = P[:, 2]
p4 = P[:, 3]
'''
def cal_z(point1, point2):return -np.linalg.norm(np.cross(point1, point2)) / (np.dot(p4, point1) * np.linalg.norm(np.cross(p3, point2)))

图 7反映了如何利用同调关系来计算一个点在平行平面上的对应点。图 8展示了如何在平行平面间比较线段长度。图 9展示如何在平行平面间比较面积大小。计算同调矩阵需要先计算参数ψ\psiψ。ψ\psiψ可以通过(9)计算。需要注意的是,由于python的OpenCV库默认图像坐标系左上角为原点,y轴正方向向下,与示例中设置的图像坐标系不同。所以ψ\psiψ的符号也要变动。在最后,由于矩阵PPP需要带系数ρ\rhoρ才能使等式x=PX\mathbf{x} = P\mathbf{X}x=PX成立,所以由PPP推导出的同调矩阵H~\widetilde{H}H也需要带缩放系数。

图 7 从平面到另一个平行平面的点的同调映射:(a)原图,柜子的上顶面和下底面是平行平面。(b)示例图,共同的消失线(同调轴,上方白色)©示例图,显示物体轮廓(d)复现结果,用于确定消失点vx,vy,v\mathbf{v}_{x},\mathbf{v}_{y},\mathbf{v}vx​,vy​,v的平行线以蓝色线表示。消失线以红色线表示。利用相同消失点和消失线推导的同调关系,给出上方选取点x\mathbf{x}x,就能计算出下方对应点x′\mathbf{x'}x′。橙色线表现了这个关系。


图 8 在两个平面之间测量平行线段长度之比:(a)原图示例(b)复现结果。点r,r′\mathbf{r,r'}r,r′与消失点、消失线定义了两面墙的同调关系,蓝色线是定义消失点和消失线的平行线。紫色线段是以r,r′\mathbf{r,r'}r,r′为端点的线段。橙色线是左外墙的线段映射到右外墙的结果。


图 9 测量在两个不同平面上的面积之比:(a)原图,目标是测量两个窗户的面积(b)复现效果图。橙色框是A1映射到A2平面的结果。利用r,r′\mathbf{r}\mathbf{,r'}r,r′计算同调关系,并转换A1点到A2所在平面上,获得两个窗户的面积比为A1/A2=1.2A1/A2 = 1.2A1/A2=1.2

图 9 的流程为

  • 用平面边缘的窗户的计算正交消失点v\mathbf{v}v
  • 用俩平面的平行边缘计算共同的消失线l\mathbf{l}l
  • (16)中的唯一的参数ψ\psiψ用(9)算出
    ψ=−∥r×r′∥(lˉ⋅r)∥v×r′∥\psi=-\frac{ \mathbf{\Vert r\times r'\Vert}}{\mathbf{(\bar{l}\cdot r)\Vert v\times r'\Vert}} ψ=−(lˉ⋅r)∥v×r′∥∥r×r′∥​
  • 左平面窗户四角通过同调矩阵H~\widetilde{H}H转换为另外一个窗户所在平面上的对应点

现在我们的两个四边形在同一个平面上了

  • 对图像进行仿射变换,把消失线推至无穷远处2
  • 现在可以在仿射变换图像上计算面积比了

下面是计算ψ,H~\psi,\widetilde{H}ψ,H、同调对应点、以及额外缩放系数ρ~\widetilde{\rho}ρ​的代码

def cal_psi(point1, point2, v, l):l_bar = l / np.linalg.norm(l)# 使用公式(9)计算psi。没有负号是因为图像坐标系y轴与示例中y轴正方向相反return np.linalg.norm(np.cross(point1, point2)) / ((np.dot(l_bar, point1)) * (np.linalg.norm(np.cross(v, point2))))def cal_H_tilde(psi, v, l):l_bar = l / np.linalg.norm(l)return np.identity(3) + psi * (np.dot(np.mat(v).T, np.mat(l_bar)))def correspond(H_tilde, point):correspond_point = np.dot(H_tilde, point)correspond_point = np.array(correspond_point)[0]  # 由矩阵转为向量correspond_point = correspond_point / correspond_point[-1]return correspond_point # 返回结果之后还需要乘缩放系数rho_tilderho_tilde = np.linalg.norm(reference_bottom_point) / np.linalg.norm(correspond(reference_top_point))


图 10 在不同平面上计算物体高度:(a)原示例结果(b)复现结果。蓝色线是定义消失点和消失线的平行线。紫色线是基准距离,桌子r,r′\mathbf{r}\mathbf{,r'}r,r′的高度设定为60cm,计算出文件夹高度31.41cm。

图 10展示了如何计算在不同平行平面上物体的高度。地平面是基准面π\mathbf{\pi}π,将桌子桌面作为平面π′\mathbf{\pi'}π′。用(14)即可以算出高度。
其计算过程如下

  • 地平面是基准面π\mathbf{\pi}π,将桌子桌面作为平面π′\mathbf{\pi'}π′。
  • 通过相交的平行边缘计算出消失线和消失点。
  • r,r′\mathbf{r,r'}r,r′之间的距离ZrZ_rZr​是已知距离,用于在(9)计算参数α\alphaα
  • 把(14)用在标记线段的两个端点上计算出高度Z′Z'Z′

下面是计算文件夹高度Z′Z'Z′的代码

'''
其他代码中已定义以下内容
P = np.zeros([3, 4])
p1 = P[:, 0]
p2 = P[:, 1]
p3 = P[:, 2]
p4 = P[:, 3]
'''
def cal_z_prime(point2, point3):rho_prime = np.dot(point2, p4) / (1 + reference_distance * np.dot(p3, p4))return -np.linalg.norm(np.cross(point2, point3)) / (rho_prime * (np.linalg.norm(np.cross(p3, point3))))


图 11 计算相机位置:(a)原示例图(b)附带标识了参考点的复现图。wiw_{i}wi​表示用于计算单应矩阵的走廊矩形四个点。w0w_{0}w0​与原点重合。紫色线是基准距离。坐标系表示将空间坐标系XYZXYZXYZ按照图示构造。设定走廊矩形长宽为830cm×120cm830cm \times 120cm830cm×120cm。计算出相机位置为Xc=−385.36cm,Yc=−651.01cm,Zc=161.29cmX_{c} = - 385.36cm,Y_{c} = - 651.01cm,Z_{c} = 161.29cmXc​=−385.36cm,Yc​=−651.01cm,Zc​=161.29cm

图11展示在确定空间坐标系时,如何计算相机位置。在这里,空间坐标原点不再被设定为p4=l‾\mathbf{p_4} = \overline{\mathbf{l}}p4​=l,而是p4=w0\mathbf{p_4} = w_{0}p4​=w0​。这导致两个结果。一是需要修改α\alphaα的计算方法,因为之前计算方法依赖于p4=l‾\mathbf{p_4} = \overline{\mathbf{l}}p4​=l,l‾⋅p4=1\overline{\mathbf{l}}\mathbf{\cdot}\mathbf{p_4}\mathbf{=}1l⋅p4​=1。二是需要另一种方法计算从实际到图像的单应矩阵HHH,因为矩阵PPP现在是未知的。计算单应矩阵HHH可以利用图像点和空间坐标的点的关系联立方程用矩阵解法。(至少4对点,8个方程)。3

图11的计算流程如下
注意我们选择了p4\mathbf{p_4}p4​而不是lˉ\mathbf{\bar{l}}lˉ作为o\mathbf{o}o点。

  • 地面(X,YX,YX,Y平面)作为基准面
  • 通过相交的竖直边缘计算出消失点。
  • 测量出图像中走廊矩形的两个边长,从而算出在基准面上四个点的坐标,继而算出从实际场景到图像的单应矩阵3
  • 用基准距离算出α\alphaα
  • 然后用(18)算出相机三维坐标。
def cal_H(world_point:list,img_point:list):A = np.zeros([2 * len(img_point), 9])for i in range(len(img_point)):ip = img_point[i]wp = world_point[i]A[i * 2] = [wp[0], wp[1], 1, 0, 0, 0, -wp[0] * ip[0], -wp[1] * ip[0], -ip[0]]A[i * 2 + 1] = [0, 0, 0, wp[0], wp[1], 1, -wp[0] * ip[1], -wp[1] * ip[1], -ip[1]]lam, xi = np.linalg.eig(np.dot(A.T, A))H_vector = xi[:, np.argmin(lam)]return np.array([H_vector[:3], H_vector[3:6], H_vector[6:9]])

由于前提发生变换(l‾⋅p4≠1)(\overline{\mathbf{l}}\mathbf{\cdot}\mathbf{p_4} \neq 1)(l⋅p4​=1),所以α\alphaα的计算方法也发生了变化

def cal_alpha2(z: list, r1: list, r2: list, v, l):global alphabeta_i = rho_i = gamma_i = 0A = np.zeros([len(z), 2])for i in range(len(z)):beta_i = np.linalg.norm(np.cross(r1[i], r2[i]))l_bar = l / np.linalg.norm(l)# 这里更改了代码,因为np.dot(l_bar,p4)不等于1rho_i = np.dot(l_bar, r1[i]) / (np.dot(l_bar, p4))gamma_i = np.linalg.norm(np.cross(v, r2[i]))A[i, 0] = z[i] * rou_i * gamma_iA[i, 1] = beta_iif len(z) == 1:alpha = (-1.0 * beta_i) / (z[0] * rho_i * gamma_i)else:M = np.dot(A.T, A)lam, xi = np.linalg.eig(M)  # 计算特征值和向量s = xi[:, np.argmin(lam)]  # 取最小特征值的特征向量alpha = s[0] / s[1]

在算出单应矩阵后就可以得到投影矩阵PPP的1,2,4列。以下是获得矩阵PPP的流程。

    p1[:] = H[:, 0]p2[:] = H[:, 1]p4[:] = H[:, 2]#cal_alpha2()函数需要p4。所以需要计算p4后才运行cal_alpha2()alpha=cal_alpha2(reference_distances, reference_ground_points, reference_plane_points, v, l)p3[:] = alpha * v[:]

算出矩阵PPP后依据(18)算出相机位置(前面提到,由于坐标朝向问题,ZcZ_{c}Zc​计算结果的符号与实际相反。)

Xc = -np.linalg.det(np.array([p2, p3, p4]).T)
Yc = np.linalg.det(np.array([p1, p3, p4]).T)
Zc = -np.linalg.det(np.array([p1, p2, p4]).T)
Wc = np.linalg.det(np.array([p1, p2, p3]).T)

参考文献


  1. A. Criminisi, I. Reid, and A. Zisserman, “Single view metrology,” International Journal of Computer Vision, vol. 40, no. 2, pp.123–148, 2000. ↩︎

  2. Liebowitz, D. and Zisserman, A. 1998. “Metric rectification for perspective images of planes.” In Proceedings of the Conference on Computer Vision and Pattern Recognition, pp. 482–488 ↩︎

  3. A. Criminisi, I. Reid, and A. Zisserman, “A plane measuring device,” Image and Vision Computing, vol. 17, no. 8, pp. 625–634,1999. ↩︎ ↩︎

Single View Metrology 单视图度量衡 复现相关推荐

  1. 视图可视化 后台_如何在单视图中可视化复杂的多层主题

    视图可视化 后台 Sometimes a dataset can tell many stories. Trying to show them all in a single visualizatio ...

  2. 3D鸟类重建—数据集、模型以及从单视图恢复形状

    点击上方"小白学视觉",选择"星标" 干货第一时间送达 代码.项目.论文地址:在公众号「计算机视觉工坊」,后台回复「3D鸟类重建」,即可直接下载. 概述 动物姿 ...

  3. odoo10参考系列--视图二(表单视图)

    表单视图 表单视图用于从单个记录中显示数据.它们的根元素是<form>.它们由常规HTML组成,具有额外的结构和语义组件. 结构组件 结构组件提供了结构化的或很小逻辑的"视觉&q ...

  4. 使用Laravel View Composers在视图之间共享数据

    Laravel视图入门 ( Getting Started With Laravel Views ) Views hold the presentation logic of a Laravel ap ...

  5. MySQL实现成绩表单视图

    问题 大家平时所看到的成绩表单基本上都是用excel来制作的,学习数据库基础,你就多了一项用MySQL制作表单的技能.不仅方便快捷,输入一些命令就可以很直观的看出重要数据:而且便于储存.那么如何用My ...

  6. DeepFusion:基于单视图深度和梯度预测的单目SLAM实时稠密三维重建

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 标题:DeepFusion: Real-Time Dense 3D Reconstruction fo ...

  7. 什么是数据库视图(view),视图(view)优缺点是什么?

    什么是数据库视图(view),视图(view)优缺点是什么? 什么是数据库视图(view)? 在 SQL 中,视图是基于 SQL 语句的结果集的可视化的表. 视图包含行和列,就像一个真实的表.视图中的 ...

  8. monotouch Single View Application

    创建Single View Application,在AppDelegate中启动完成以后会自动跳转到主页面上. 在不使用Storyboard的情况下,直接创建单个的xib,跳转方式如下: stati ...

  9. Course 2: 单视图计量

    Course 2: 单视图计量 2.1 概述 在之前的课堂讲稿中,我们讨论了如何利用相机的外部和内在特性将点从真实的三维世界转换为数字图像.我们研究了如何在校准装置中使用已知的结构及其相应的图像来推断 ...

最新文章

  1. php 实现tab切换_微信小程序实例:实现顶部tab切换以及滑动切换时导航栏会随着移动的效果(代码)...
  2. l2_norm opencv torch比较
  3. (2014年2月7日升级)Ubuntu-14.04-Alpha2-32位简体中文优化封装版
  4. 李飞飞访谈:AI以人为本——之笔者见
  5. TensorFlow for Hackers - Part III
  6. Syszuxpin中文输入法移植
  7. jQuery内置动画和多库共存
  8. Redis之高级特性
  9. 清华大学中国人工智能学会:2019人工智能发展报告
  10. 安卓移动办公软件_安卓免费办公软件套装 速度快功能强大 WPS Office 12.6.4 解锁高级版特权...
  11. Graph2Vec运行
  12. deep|Bayes(4)
  13. MODIS数据介绍及下载
  14. CSS opacity - 实现图片半透明效果
  15. 【递归调用在二叉树中的应用】前序遍历、中序遍历、后序遍历、求二叉树叶子结点及复制二叉树的C语言实现
  16. 【web前端期末大作业】html网上在线书城大学生静态网页 大学生html当当书城仿站 网上书城购物网页作业HTML
  17. jw实验二:配置VLAN Trunks
  18. linux 文件转换ascii,关于linux:如何将文件从ASCII转换为UTF-8?
  19. ECNU || 宇恒棋
  20. 你的团队健康吗?如何打造一支健康的团队?

热门文章

  1. 公交卡软件测试思路,中国移动NFC专用SIM卡测试过程介绍
  2. Swift编码规范(目前swift 4.2,持续更新)
  3. 一家图灵奖得主背书创企的陨落,暴露了AI弱国“恒弱”的困境?
  4. 谷歌无人车报告(中文版)(42页):通往自动驾驶之路
  5. 使用docker中容器的坑
  6. 计算机桌面操作系统版本,查看电脑操作系统版本(适用于Mac OS)
  7. Spin test 两个脑图如何计算空间相关的P值?两张大脑map图如何做空间相关置换检验?
  8. springboot定时任务未登录情况下获取用户信息报错解决方案
  9. svn+teamcity+YouTrack+Upsource搭建—写给明天工作室的小伙伴
  10. 我在阿里第一年375晋升的心得