从三维透视图重绘成二维图像

22

我需要一段用Pascal/Delphi/Lazarus编写的逆透视变换。见下图:

image process

我认为我需要遍历目标像素,然后计算出对应的源图像位置(以避免由于舍入误差等问题而产生错误)。

function redraw_3d_to_2d(sourcebitmap:tbitmap, sourceaspect:extended, point_a, point_b, point_c, point_d:tpoint, megapixelcount:integer):tbitmap;
var
   destinationbitmap:tbitmap;
   x,y,sx,sy:integer;
begin
  destinationbitmap:=tbitmap.create;
  destinationbitmap.width=megapixelcount*sourceaspect*???; // I dont how to calculate this
  destinationbitmap.height=megapixelcount*sourceaspect*???; // I dont how to calculate this
  for x:=0 to destinationbitmap.width-1 do
    for y:=0 to destinationbitmap.height-1 do
    begin
        sx:=??;
        sy:=??;
        destinationbitmap.canvas.pixels[x,y]=sourcebitmap.canvas.pixels[sx,sy];
    end;
  result:=destinationbitmap;
end;

我需要真正的公式...因此OpenGL解决方案并不理想...

2个回答

23

注意:这里有一个数学SE上适当的数学排版版本。

计算投影变换

透视是投影变换的一种特殊情况,而投影变换又由四个点定义。

步骤1:从源图像中的4个位置开始,命名为(x1,y1)(x4,y4),解下列线性方程组

[x1 x2 x3] [λ]   [x4]
[y1 y2 y3]∙[μ] = [y4]
[ 1  1  1] [τ]   [ 1]

这些列来自齐次坐标:通过在最后一个条目中添加1,增加了一维。在随后的步骤中,这些向量的倍数将用于表示相同的点。请参见最后一步,以了解如何将其转换回二维坐标。 第二步:按照您刚刚计算的系数缩放这些列:
    [λ∙x1 μ∙x2 τ∙x3]
A = [λ∙y1 μ∙y2 τ∙y3]
    [λ    μ    τ   ]

这个矩阵将会把(1,0,0)映射到(x1,y1,1)的倍数,(0,1,0)映射到(x2,y2,1)的倍数,(0,0,1)映射到(x3,y3,1)的倍数,而(1,1,1)则映射到(x4,y4,1)。因此,它将这四个特殊向量(在后续的解释中称为基向量)映射到图像中指定的位置。 步骤 3:重复步骤 1 和 2,以获得第二个矩阵B,对应于目标图像中的相应位置。
这是一个从基向量到目标位置的映射。 步骤 4:求逆B,得到B⁻¹B将基向量映射到目标位置,因此逆矩阵会反向映射。

步骤5:计算combined矩阵C = A∙B⁻¹

B⁻¹将目标位置映射到基向量,而A将其映射到源位置。因此,组合将目标位置映射到源位置。

步骤6:对于目标图像的每个像素(x,y),计算乘积。

[x']     [x]
[y'] = C∙[y]
[z']     [1]

这是您转换后点的齐次坐标。
第7步:按照以下方式计算源图像中的位置:
sx = x'/z'
sy = y'/z'

这被称为坐标向量的非齐次化。

如果 Stack Overflow 支持 MathJax,所有这些数学内容都会变得更易于阅读和编写...

选择图像大小

以上方法假定您知道目标图像中角落的位置。对于这些角落,您必须知道该图像的宽度和高度,在您的代码中用问号表示。因此,假设您输出图像的height1widthsourceaspect。在这种情况下,总面积也将为sourceaspect。您必须将该面积缩放一个因子pixelcount/sourceaspect,以达到pixelcount的面积。这意味着您必须按照该因子的平方根比例缩放每个边长。因此,最终您会得到

pixelcount = 1000000.*megapixelcount;
width  = round(sqrt(pixelcount*sourceaspect));
height = round(sqrt(pixelcount/sourceaspect));

只有在照片是正射拍摄时才有效。如果是斜角拍摄,则还需要角落的深度 - 不过这些可以从角度推导出来。 - Thomas
啊,我明白了。然而,你将没有足够的信息来准确重建最终图像,因为你将把“压扁”的像素放大到具有所需宽高比的像素,但这是不可避免的。 - Thomas
@Thomas,如果重建图像的megapixelcount比输入照片小得多,那么有机会,但我同意通常情况下,重建图像的保真度会受到影响。一些形式的混叠可能会通过超采样等技术来对抗,但这不会恢复在过程中丢失的信息,只是使它们的缺乏不那么明显。 - MvG
@KasperDK - 哎呀,这是一个全新的领域。 - Leonardo Herrera
我最终在Math Stackexchange上写了这个答案的版本,由于它使用了MathJax,因此具有更好的数学格式化功能。 - MvG
显示剩余7条评论

5

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接