使用 ARKit 矫正图像

1,101 阅读3分钟

在拍摄文件时,如果手机和待拍摄的文件不是正对时,拍摄的文件会产生扭曲。可以使用 ARKit 对拍摄的图形进行矫正,获取到垂直拍摄的效果。

下面是实现的思路和过程。

前提条件

在拍摄的过程中,默认待拍摄的图像在一个水平面或者垂直平面上(因为 ARKit 目前只能检测到水平面或者垂直平面)。

思路

  1. 通过 ARKit 获取到待拍摄的平面,推导出表达平面的方程式
  2. 根据相机内参,相机当前的位置,取拍摄图片上的左上、左下、右上、右下四个点,推算出这四个点所拍摄的三维世界中的线
  3. 计算步骤 2 中的四条线和步骤 1 中的平面的四个交点,相机所拍摄的图像即是这四个交点内的内容
  4. 根据投影变换,将拍摄图片的左上、左下、右上、右下四个点和步骤 3 中的四个交点进行对应变换,得出矫正后的图片

计算过程

获取待拍摄的平面的方程式

可以通过一个平面上的三个点(不在一条直线上),计算一个平面的方程表达式。

ARKit 可以提供的能力:

  1. 识别出世界空间中的水平、垂直的平面
  2. 射线检测:可以测试手机图像上的点和特征点的交点

平面的一般式为:Ax+By+Cz+D=0Ax + By + Cz + D = 0

可以选取手机平面正中间相邻的、不再一条直线上的三个点,根据射线检测,看是否在同一个平面上。如果在同一个平面上,则获取到对应的三个点,来计算平面公式。

假设三个交点为 P1(x1,y1,z1)P_1(x_1, y_1, z_1) P2(x2,y2,z2)P_2(x_2, y_2, z_2) P3(x3,y3,z3)P_3(x_3, y_3, z_3) ,根据三点坐标分别求得 ABCDA、B、C、D的值,推到公式为:

A=(y3y1)(z3z1)(z2z1)(y3y1)B=(x3x1)(z2z1)(x2x1)(z3z1)C=(x2x1)(y3y1)(x3x1)(y2y1)D=(Ax1+By1+Cz1)A = (y_3 - y_1)*(z_3 - z_1) - (z_2 -z_1)*(y_3 - y_1) \\ B = (x_3 - x_1)*(z_2 - z_1) - (x_2 - x_1)*(z_3 - z_1) \\ C = (x_2 - x_1)*(y_3 - y_1) - (x_3 - x_1)*(y_2 - y_1) \\ D = -(Ax_1 + By_1 + Cz_1)

相机图片坐标和世界坐标之间的对应关系

通过相机内参获取平面上点和相机坐标的三维点

可以通过相机内参,推到出图像上的点和相机左边空间的点的对应关系。

假设:平面上的点的坐标为 P(xphoto,yphoto)P(x_{photo}, y_{photo}),相机空间的对应的点为:P(xcamera,ycamera,zcamera)P(x_{camera}, y_{camera}, z_{camera}),相机内参为:[fx0ox0fyoy001]\begin{bmatrix}fx&0 &ox\\0&fy&oy\\0&0&1\\ \end{bmatrix} ,则:

[fx0ox0fyoy001][xcameraycamerazcamera]=[xphotoyphotozphoto][xphotoyphotozphoto]/zphoto=[xphotoyphoto1]\begin{bmatrix}f_x&0 &o_x\\0&f_y&o_y\\0&0&1\\ \end{bmatrix}\begin{bmatrix}x_{camera}\\y_{camera}\\z_{camera}\\ \end{bmatrix}=\begin{bmatrix}x'_{photo}\\y'_{photo}\\z'_{photo}\\ \end{bmatrix} \to\begin{bmatrix}x'_{photo}\\y'_{photo}\\z'_{photo}\\ \end{bmatrix} / z'_{photo} = \begin{bmatrix}x_{photo}\\y_{photo}\\1\\ \end{bmatrix}

所以 P(xphoto,yphoto)P(x_{photo}, y_{photo})P(xcamera,ycamera,zcamera)P(x_{camera}, y_{camera}, z_{camera}) 的关系为:

xphoto=fxxcamera/zcamera+oxyphoto=fyycamera/zcamera+oyx_{photo} = f_xx_{camera}/z_{camera} + o_x \\ y_{photo} = f_yy_{camera}/z_{camera} + o_y

计算世界坐标和相机坐标的对应关系

通过相机的位姿(transform),可以获取相机坐标和世界坐标之间的关系。 即:(P相机坐标,1)=T相加位姿1(P世界坐标,w)(P_{相机坐标}, 1) = {T_{相加位姿}}^{-1}(P_{世界坐标}, w)

假设相机的坐标点为:P(xcamera,ycamera,zcamera)P(x_{camera}, y_{camera}, z_{camera}),对应的世界的坐标为 P(xworld,yworld,zworld)P(x_{world}, y_{world}, z_{world}),相机的位姿(transform)为 T相机位姿T_{相机位姿},相机的位姿的逆矩阵为T1{T}^{-1},即[t00t10t20t30t01t11t21t31t02t12t22t32t03t13t23t33]\begin{bmatrix} t'_{00}&t'_{10} &t'_{20}&t'_{30} \\t'_{01}&t'_{11} &t'_{21}&t'_{31} \\t'_{02}&t'_{12} &t'_{22}&t'_{32} \\t'_{03}&t'_{13} &t'_{23}&t'_{33}\\ \end{bmatrix}

则:

[xcameraycamerazcamera1]=[t00t10t20t30t01t11t21t31t02t12t22t32t03t13t23t33][xworldyworldzworldw]\begin{bmatrix}x_{camera}\\y_{camera}\\z_{camera}\\1\\ \end{bmatrix}=\begin{bmatrix} t'_{00}&t'_{10} &t'_{20}&t'_{30} \\t'_{01}&t'_{11} &t'_{21}&t'_{31} \\t'_{02}&t'_{12} &t'_{22}&t'_{32} \\t'_{03}&t'_{13} &t'_{23}&t'_{33}\\ \end{bmatrix} \begin{bmatrix}x_{world}\\y_{world}\\z_{world}\\w\\ \end{bmatrix}

综上条件,可以得出相机图片坐标P(xphoto,yphoto)P({x_{photo}, y_{photo}})和世界坐标P(xworld,yworld,zworld)P({x_{world}, y_{world}, z_{world}})之间的对应关系:

{[xcameraycamerazcamera1]=[t00t10t20t30t01t11t21t31t02t12t22t32t03t13t23t33][xworldyworldzworldw]xphoto=fxxcamera/zcamera+oxyphoto=fyycamera/zcamera+oy\left\{ \begin{array}{c} \begin{bmatrix}x_{camera}\\y_{camera}\\z_{camera}\\1\\ \end{bmatrix}= \begin{bmatrix} t'_{00}&t'_{10} &t'_{20}&t'_{30} \\t'_{01}&t'_{11} &t'_{21}&t'_{31} \\t'_{02}&t'_{12} &t'_{22}&t'_{32} \\t'_{03}&t'_{13} &t'_{23}&t'_{33}\\ \end{bmatrix} \begin{bmatrix}x_{world}\\y_{world}\\z_{world}\\w\\ \end{bmatrix} \\ x_{photo} = f_xx_{camera}/z_{camera} + o_x \\ y_{photo} = f_yy_{camera}/z_{camera} + o_y \end{array} \right.

可以推导出: {(fxt00+fxt02xphotot02)xworld+(fxt10+oxt12xphotot12)yworld+(t20fx+oxt22xcameratxx)zworld+t30fx+oxt32xphotot32=0(fyt01+oyt02yphotot02)xworld+(fyt11+oyt12yphotot12)yworld+(fyt21+oyt22yphotot22)zworld+fyt31+oyt32yphotot32=0\left\{ \begin{array}{c} (f_xt'_{00}+f_xt'_{02}-x_{photo}t'_{02})x_{world} + (f_xt'_{10}+o_xt'_{12}-x_{photo}t'_{12})y_{world}+(t'_{20}f_x+o_xt'_{22}-x_{camera}txx)z_{world}+t'_{30}f_x+o_xt'_{32}-x_{photo}t'_{32}=0 \\ (f_yt'_{01}+o_yt'_{02}-y_{photo}t'_{02})x_{world}+(f_yt'_{11}+o_yt'_{12}-y_{photo}t'_{12})y_{world}+(f_yt'_{21}+o_yt'_{22}-y_{photo}t'_{22})z_{world}+f_yt'_{31}+o_yt'_{32}-y_{photo}t'_{32}=0 \end{array} \right.

计算 ARKit 拍摄图片上的四个点和平面的焦点

有了相机拍摄图片的坐标和世界坐标的关系,再加上平面方程式,则可以计算出,相机拍摄的图片坐标在指定平面上的交点。

相机拍摄的图片上的一点对应世界中的一条射线,即求:这条射线和平面的焦点。

假设平面为:Ax+By+Cz+D=0Ax + By + Cz + D = 0,则可以得出一个三元一次方程组: {(fxt00+fxt02xphotot02)xworld+(fxt10+oxt12xphotot12)yworld+(t20fx+oxt22xcameratxx)zworld+t30fx+oxt32xphotot32=0(fyt01+oyt02yphotot02)xworld+(fyt11+oyt12yphotot12)yworld+(fyt21+oyt22yphotot22)zworld+fyt31+oyt32yphotot32=0Axworld+Byworld+Czworld+D=0\left\{ \begin{array}{c} (f_xt'_{00}+f_xt'_{02}-x_{photo}t'_{02})x_{world} + (f_xt'_{10}+o_xt'_{12}-x_{photo}t'_{12})y_{world}+(t'_{20}f_x+o_xt'_{22}-x_{camera}txx)z_{world}+t'_{30}f_x+o_xt'_{32}-x_{photo}t'_{32}=0 \\ (f_yt'_{01}+o_yt'_{02}-y_{photo}t'_{02})x_{world}+(f_yt'_{11}+o_yt'_{12}-y_{photo}t'_{12})y_{world}+(f_yt'_{21}+o_yt'_{22}-y_{photo}t'_{22})z_{world}+f_yt'_{31}+o_yt'_{32}-y_{photo}t'_{32}=0\\Ax_{world} + By_{world} + Cz_{world} + D = 0\end{array}\right.

当确定相机拍摄的图片上一个点之后,带入上面的方程组,就是确定平面上的一点P(xworld,yworld,zworld)P(x_{world}, y_{world},z_{world})的三个方程组,

{A1xworld+B1yworld+C1zworld+D1=0A2xworld+B2yworld+C2zworld+D2=0Axworld+Byworld+Czworld+D=0\left\{ \begin{array}{c} A_1x_{world} + B_1y_{world} + C_1z_{world} + D_1 = 0\\A_2x_{world} + B_2y_{world} + C_2z_{world} + D_2 = 0\\Ax_{world} + By_{world} + Cz_{world} + D = 0\end{array}\right.

根据克莱姆法则,可以计算得出 P(xworld,yworld,zworld)P(x_{world}, y_{world},z_{world}) 的值。

使用同样的过程,我们就可以获得相机照片上的4的点对应的世界坐标。

投影变换

获取到照片拍摄的图片上四个顶点的世界坐标之后,就可以应用投影变换,对图片进行矫正。