Delphi 将图像从三维透视图重绘到二维透视图

Delphi 将图像从三维透视图重绘到二维透视图,delphi,math,geometry,pascal,lazarus,Delphi,Math,Geometry,Pascal,Lazarus,我需要一个用Pascal/Delphi/Lazarus编写的逆透视变换。请参见下图: 我认为我需要遍历目标像素,然后计算源图像中的相应位置(以避免舍入错误等问题) 我需要真正的公式。。。所以OpenGL解决方案并不理想…注意:在math SE上有适当的数学排版 计算射影变换 透视图是A的一个特例,而A又由四个点定义 步骤1:从源图像中名为(x1,y1)的4个位置开始,通过(x4,y4)求解以下问题: [x1x2x3][λ][x4] [y1 y2 y3]∙[μ] =[y4] [ 1 1 1]

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

我认为我需要遍历目标像素,然后计算源图像中的相应位置(以避免舍入错误等问题)

我需要真正的公式。。。所以OpenGL解决方案并不理想…

注意:在math SE上有适当的数学排版

计算射影变换 透视图是A的一个特例,而A又由四个点定义

步骤1:从源图像中名为
(x1,y1)
的4个位置开始,通过
(x4,y4)
求解以下问题:

[x1x2x3][λ][x4]
[y1 y2 y3]∙[μ] =[y4]
[ 1  1  1] [τ]   [ 1]
colums表单:增加一个维度,通过添加
1
作为最后一个条目创建。在随后的步骤中,将使用这些向量的倍数来表示相同的点。有关如何将这些坐标转换回二维坐标的示例,请参见最后一步

第2步:根据刚才计算的系数缩放列:

[λ∙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)映射为
(x4,y4,1)
。因此,它会将这四个特殊向量(在后面的解释中称为基向量)映射到图像中的指定位置

步骤3:对目标图像中的相应位置重复步骤1和2,以获得称为
B
的第二个矩阵

这是从基向量到目标位置的映射

步骤4:
B
获取
B⁻CharStyle

B
从基向量映射到目标位置,因此逆矩阵映射方向相反

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

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

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

[x'][x]
[y']=C∙[y]
[z'][1]
这些是变换点的同质坐标

步骤7:按如下方式计算源图像中的位置:

sx=x'/z'
sy=y'/z'
这称为坐标向量的非均匀化

如果是这样的话,所有这些数学都会…☹

选择图像大小 上述方法假设您知道目标图像中角点的位置。对于这些,您必须知道图像的宽度和高度,这在代码中也用问号标记。因此,我们假设输出图像的
高度
1
,而
宽度
sourceaspect
。在这种情况下,整个区域也将是
sourceaspect
。您必须按
pixelcount/sourceaspect
的因子缩放该区域,以获得
pixelcount
的区域。这意味着您必须按该因子的平方根缩放每条边的长度。所以最后,你有

pixelcount=1000000.*兆像素计数;
宽度=圆形(sqrt(像素计数*源纵横比));
高度=圆形(sqrt(像素计数/源纵横比));

使用,特别是(与方法一起使用)。不要忘了在源图像中留下一些透明的边缘,这样你就不会得到锯齿状的边缘。

这只在照片以正常角度拍摄时有效。如果是从一个角度拍摄,你也需要角的深度——然而,这些可以从角度推断出来。@Thomas,我不明白你的担心。我知道我的aproach不会处理任何真实的像差,但只要使用理想的针孔相机模型,角度就无关紧要:无论角度如何,透视都是投影变换(除非光轴位于纸张平面内)。上述计算适用于一般的prohective变换。所以不需要深度。注意,我是在真实的投影平面上进行计算,而不是在真实的仿射3d空间中。这可能是您误解了这一点吗?假设照片是在图纸的掠射角度拍摄的-您可以像往常一样应用旋转以获得正确对齐的照片,但仍然是在掠射角度,这不是期望的结果(OP希望“正好在纸张上方”)。OP没有提到输入的照片是否总是从绘图的正上方拍摄。@Thomas,我正在应用投影变换,而不仅仅是旋转。它将以掠射角度拍摄的矩形图像映射到填充目标图像的矩形。没有要求照片必须直接从图纸上方拍摄。啊,我明白了。但是,您将没有足够的信息来准确地重建最终图像,因为您将以所需的纵横比将“挤压”像素放大到像素,但这是不可避免的。
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;