将图像从 3d 透视图重绘为 2d [英] Redraw image from 3d perspective to 2d

查看:25
本文介绍了将图像从 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.

透视图是投影变换的特例,而后者又是由四个点定义.

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

第一步:从源图片中的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.

第五步:计算组合矩阵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'

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

所有这些数学运算都会如此容易读写href="https://meta.stackexchange.com/q/4152/188688">支持MathJax…

All this math would be so much easier to read and write if SO were to support 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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆