从3d透视重绘图像到2d

时间:2013-01-09 18:31:48

标签: delphi math geometry pascal lazarus

我需要用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 个答案:

答案 0 :(得分:21)

注意:在Math SE上有a version of this正确的数学排版。

计算投影变换

透视是projective transformation的特例,而后者又由四个点定义。

第1步:从源图片中的4个位置开始,名为(x1,y1)(x4,y4),您解决了以下system of linear equations

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

colums形成homogenous coordinates:更多一个维度,通过添加1作为最后一个条目来创建。在随后的步骤中,这些矢量的倍数将用于表示相同的点。有关如何将这些转换回二维坐标的示例,请参见最后一步。

第2步:按您刚刚计算的系数缩放列:

    [λ∙x1 μ∙x2 τ∙x3]
A = [λ∙y1 μ∙y2 τ∙y3]
    [λ    μ    τ   ]

此矩阵会将(1,0,0)映射到(x1,y1,1)的倍数,(0,1,0)(x2,y2,1)的倍数,(0,0,1)到{{1}的倍数}和(x3,y3,1)(1,1,1)。因此,它会将这四个特殊向量(在后续解释中称为基础向量)映射到图像中的指定位置。

步骤3:对目标图像中的相应位置重复步骤1和2,以获得名为(x4,y4,1)的第二个矩阵。

这是从基础向量到目的地位置的地图。

第4步: Invert B获取B

B⁻¹从基础向量映射到目标位置,因此逆矩阵以相反的方向映射。

第5步:计算combined矩阵B

C = A∙B⁻¹从目标位置映射到基础向量,而B⁻¹从那里映射到源位置。因此,组合将目标位置映射到源位置。

第6步:对于目标图片的每个像素A,计算产品

(x,y)

这些是转换点的同质坐标。

第7步:计算源图像中的位置,如下所示:

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

这称为坐标向量的去均匀化

所有这些数学都是so much easier to read and write如果是support MathJax那么......

选择图像尺寸

上述方法假设您知道目标图像中角落的位置。对于这些,您必须知道该图像的宽度和高度,在您的代码中也会用问号标记。因此,我们假设输出图像的sx = x'/z' sy = y'/z' height,而1width。在这种情况下,整个区域也将是sourceaspect。您必须将该区域缩放sourceaspect因子才能达到pixelcount/sourceaspect的区域。这意味着您必须按照该因子的平方根缩放每个边长。所以最后,你有

pixelcount

答案 1 :(得分:4)

使用Graphics32,特别是TProjectiveTransformation(与Transform方法一起使用)。不要忘记在源图像中留下一些透明边距,这样就不会出现锯齿状边缘。