本文介绍了将图像从 3d 透视重绘为 2d的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I need an inverse perspective transform written in Pascal/Delphi/Lazarus. See the following image:

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

I think I need to walk through destination pixels and then calculate the corresponding position in the source image (To avoid problems with rounding errors etc.).

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 解决方案并不理想...

I need the real formula... So an OpenGL solution would not be ideal...

推荐答案

注意:此版本具有正确的数学排版数学SE.

Note: There is a version of this with proper math typesetting on the Math SE.

透视图是投影变换的特例,它反过来是由四个点定义.

A perspective is a special case of a projective transformation, which in turn is defined by four points.

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

Step 1: Starting with the 4 positions in the source image, named (x1,y1) through (x4,y4), you solve the following system of linear equations:

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

列形成齐次坐标:多一维,通过添加创建1 作为最后一个条目.在后续步骤中,这些向量的倍数将用于表示相同的点.有关如何将这些转换回二维坐标的示例,请参阅最后一步.

The colums form homogenous coordinates: one dimension more, created by adding a 1 as the last entry. In subsequent steps, multiples of these vectors will be used to denote the same points. See the last step for an example of how to turn these back into two-dimensional coordinates.

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

Step 2: Scale the columns by the coefficients you just computed:

    [λ∙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).所以它将这四个特殊向量(在后面的解释中称为基向量)映射到图像中的指定位置.

This matrix will map (1,0,0) to a multiple of (x1,y1,1), (0,1,0) to a multiple of (x2,y2,1), (0,0,1) to a multiple of (x3,y3,1) and (1,1,1) to (x4,y4,1). So it will map these four special vectors (called basis vectors in subsequent explanations) to the specified positions in the image.

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

Step 3: Repeat steps 1 and 2 for the corresponding positions in the destination image, in order to obtain a second matrix called B.

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

This is a map from basis vectors to destination positions.

第 4 步: 反转 B获得B⁻¹.

B 从基向量映射到目标位置,所以逆矩阵映射到相反的方向.

B maps from basis vectors to the destination positions, so the inverse matrix maps in the reverse direction.

步骤 5: 计算 组合 矩阵 C = A∙B⁻¹.

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

B⁻¹ maps from destination positions to basis vectors, while A maps from there to source positions. So the combination maps destination positions to source positions.

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

Step 6: For every pixel (x,y) of the destination image, compute the product

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

这些是变换点的齐次坐标.

These are the homogenous coordinates of your transformed point.

步骤 7: 像这样计算源图像中的位置:

Step 7: Compute the position in the source image like this:

sx = x'/z'
sy = y'/z'

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

如果这样支持 MathJax...

上述方法假设您知道目标图像中角落的位置.对于这些,您必须知道该图像的宽度和高度,在您的代码中也用问号标记.所以让我们假设输出图像的 height1,而 widthsourceaspect.在这种情况下,整个区域也将是 sourceaspect.您必须将该区域按 pixelcount/sourceaspect 的系数进行缩放,以达到 pixelcount 的面积.这意味着您必须通过该因子的平方根来缩放每个边长.所以最后,你有

The above aproach assumes that you know the location of your corners in the destination image. For these you have to know the width and height of that image, which is marked by question marks in your code as well. So let's assume the height of your output image were 1, and the width were sourceaspect. In that case, the overall area would be sourceaspect as well. You have to scale that area by a factor of pixelcount/sourceaspect to achieve an area of pixelcount. Which means that you have to scale each edge length by the square root of that factor. So in the end, you have

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

这篇关于将图像从 3d 透视重绘为 2d的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-30 12:10