透视变换(Perspective Transformation)用于解决仿射变换(Affine Transformation)无法改变形状内部的相对位置关系的问题。类似Photoshop中的“自由变换”功能,或者GIMP中的“透视”功能,都可以用透视变换矩阵来实现。

现在给定2个四边形:Poly1={{x1, y1}, {x2, y2}, {x3, y3}, {x4, y4}}、Poly2={{u1, v1}, {u2, v2}, {u3, v3}, {u4, v4}},求做一个透视变换Matrix,满足Poly1的点能够变形(Warp)到Poly2中的点。

perspectivewarping

[问题在哪里]
透视变换矩阵的形式为:

latex1113_1

TEX:[code]begin{pmatrix}
wu
wv
w
end{pmatrix}
=
begin{pmatrix}
m0 & m1 & m2
m3 & m4 & m5
m6 & m7 & 1
end{pmatrix}
begin{pmatrix}
x
y
1
end{pmatrix}[/code]

显然,我们需要求解的只是矩阵中8个未知量;已知量包括四边形的4个顶点 x 2个坐标(x, y),一共是8个方程,数量刚刚好。对于每个顶点坐标,Poly1中的点总是通过下面的方程转换到Poly2中:

latex1113_2

TEX:[code]begin{cases}
u=frac{m_0x+m_1y+m_2}{m_6x+m_7y+1}
v=frac{m_3x+m_4y+m_5}{m_6x+m_7y+1}
end{cases}[/code]

问题的关键在于,上面的公式需要求解非线性方程。因此,在解决Homography的问题上,常常用最小二乘法(Least Squares)求得参数估计。而真正令[tc]却步的问题在于,这一次的需求与上一次用Levenberg Marquardt算法求解非线性回归不同,这一次有两个自变量(x、y),而且这两个量之间存在关系。

[花絮]
其实.net平台下还有一个变通的解决方案,是利用System.Drawing.Drawing2D.GraphicsPath的Warp()方法,实现对路径的变形,而且在指定了WarpMode.Perspective之后,也能获得透视效果。虽然这样做的代价是无法直接得到变换矩阵,因此对任意图像的变形存在困难,但是如果能简化编程,也算是一件好事。

糟糕的是,当我下载到mono-2.4.2.3、libgdiplus-2.4.2之后,才知道mono暂时没有实现这个功能。graphics-path.c的GdipWarpPath函数中标注为“NOT IMPLEMENTED”。

随后我就将目光转向专门解决homography问题的homest。然后华丽的发现它依赖于Lapack,Lapack是用Fortran书写的……

[我的解法]
好吧,回到我的思路。其实稍加分析就不难发现,上面那个使用了分式的所谓“非线性方程”,实际上可以变形为:

latex1113_3

TEX:[code]begin{cases}
u=m_0x+m_1y+m_2-m_6xu-m_7yu
v=m_3x+m_4y+m_5-m_6xv-m_7yv
end{cases}[/code]

它居然变成了线性方程!看来一切试图用Newton迭代的算法都是没有必要的,因为我们可以用最简单的线性代数来解决:

latex1113_4

 

TEX:[code]begin{pmatrix}
u_1
v_1
u_2
v_2
u_3
v_3
u_4
v_4
end{pmatrix}
=
begin{pmatrix}
x_1 & y_1 & 1 & 0 & 0 & 0 & -x_1u_1 & -y_1u_1
0 & 0 & 0 & x_1 & y_1 & 1 & -x_1v_1 & -y_1v_1
x_2 & y_2 & 1 & 0 & 0 & 0 & -x_2u_2 & -y_2u_2
0 & 0 & 0 & x_2 & y_2 & 1 & -x_2v_2 & -y_2v_2
x_3 & y_3 & 1 & 0 & 0 & 0 & -x_3u_3 & -y_3u_3
0 & 0 & 0 & x_3 & y_3 & 1 & -x_3v_3 & -y_3v_3
x_4 & y_4 & 1 & 0 & 0 & 0 & -x_4u_4 & -y_4u_4
0 & 0 & 0 & x_4 & y_4 & 1 & -x_4v_4 & -y_4v_4
end{pmatrix}
begin{pmatrix}
m_0
m_1
m_2
m_3
m_4
m_5
m_6
m_7
end{pmatrix}[/code]

现在已经太简单了,你是用GaussJordan消去法还是LU分解法,总之得到的m0…m7就组成了所需的透视变换矩阵。

附注:关于LaTex公式刷不出来的问题,我还在努力,估计今晚就能显示了。
更新(当日14:20):我放弃了,公式改用LaTeX Equation Editor静态生成,现在应该可以显示了。