用GD进行透视转换 [英] Perspective transformation with GD

查看:161
本文介绍了用GD进行透视转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何仅使用 PHP GD库对图像
应用透视转换?

How can I apply a perspective transformation on an image using only the PHP GD library?

我不想使用别人让我想要的功能理解发生了什么

I don't want to use a function someone else made I want to UNDERSTAND what's going on

推荐答案

老实说,我不知道如何用数学方式描述透视失真。您可以尝试搜索文献(例如 Google学术搜索)。另请参阅OpenGL文档, glFrustum

I honestly don't know how to describe mathematically a perspective distortion. You could try searching the literature for that (e.g. Google Scholar). See also in the OpenGL documentation, glFrustum.

编辑:有趣的是,从版本开始8,Mathematica有 ImagePerspectiveTransformation 。在相关部分中,它说:

EDIT: Interestingly, starting with version 8, Mathematica has a ImagePerspectiveTransformation. In the relevant part, it says:


对于3 * 3矩阵 m ImagePerspectiveTransformation [image,m] LinearFractionalTransform [m] 应用于图像。

这是一个转换,对于某些 a (矩阵), b (向量), c (向量)和 d (标量),转换向量 r (a.r + b)/(c.r + d)。在2D情况下,这给出了同构矩阵

This is a transformation that, for some a (matrix), b (vector), c (vector) and d (scalar), transforms the vector r to (a.r+b)/(c.r+d). In a 2D situation, this gives the homogeneous matrix:

a_11 a_12 b_1
a_21 a_22 b_2
c_1  c_2  d

要应用转换,请将此矩阵乘以用 z = 1 扩展的列向量,然后取前两个元素结果并将它们除以第三个:

To apply the transformation, you multiply this matrix by the column vector extended with z=1 and then take the first two elements of the result and divide them by the third:

{{a11, a12, b1}, {a21, a22, b2}, {c1, c2, d}}.{{x}, {y}, {1}} // #[[
     1 ;; 2, All]]/#[[3, 1]] & // First /@ # &

给出:

{(b1 + a11 x + a12 y)/(d + c1 x + c2 y),
  (b2 + a21 x + a22 y)/(d + c1 x + c2 y)}

使用示例:

a = {{0.9, 0.1}, {0.3, 0.9}}
b = {0, -0.1}
c = {0, 0.1}
d = 1

你得到了这个转变:

im = Import["/home/cataphract/Downloads/so_q.png"];
orfun = BSplineFunction[ImageData[im], SplineDegree -> 1];

(*transf=TransformationFunction[{{0.9, 0.1, 0.}, {0.3, 
   0.9, -0.1}, {0., 0.1, 1.}}] -- let's expand this:*)

transf = {(0.9 x + 0.1 y)/(1.+ 0.1 y), (-0.1 + 0.3 x + 0.9 y)/(
     1. + 0.1 y)} /. {x -> #[[1]], y -> #[[2]]} &;

ParametricPlot[transf[{x, y}], {x, 0, 1}, {y, 0, 1},
 ColorFunction -> (orfun[1 - #4, #3] &),
 Mesh -> None,
 FrameTicks -> None,
 Axes -> False,
 ImageSize -> 200,
 PlotRange -> All,
 Frame -> False
 ]

一旦你有一张描述一个位置的地图根据原始图像中的一个点,最终图像的点,只需要找到新图像中每个点的值。

Once you have a map that describes the position of a point of the final image in terms of a point in the original image, it's just a matter of finding its value for each of the points in the new image.

有一个额外的困难。由于图像是离散的,即具有像素而不是连续值,因此必须使其连续。

There's one additional difficulty. Since an image is discrete, i.e., has pixels instead of continuous values, you have to make it continuous.

假设您的转换使图像的大小加倍。在最终图像中计算点 {x,y} 的函数将查找点 {x / 2,y / 2} 原文。这一点不存在,因为图像是离散的。所以你必须插入这一点。有几种可能的策略。

Say you have a transformation that doubles the size of an image. The function to calculate a point {x,y} in the final image will look for point {x/2, y/2} in the original. This point doesn't exist, because images are discrete. So you have to interpolate this point. There are several possible strategies for this.

在这个Mathematica示例中,我做了一个简单的2D旋转并使用1度样条函数进行插值:

In this Mathematica example, I do a simple 2D rotation and use a degree-1 spline function to interpolate:

im = Import["d:\\users\\cataphract\\desktop\\img.png"]
orfun = BSplineFunction[ImageData[im], SplineDegree -> 1];
transf = Function[{coord}, RotationMatrix[20. Degree].coord];
ParametricPlot[transf[{x, y}], {x, 0, 1}, {y, 0, 1}, 
 ColorFunction -> (orfun[1 - #4, #3] &), Mesh -> None, 
 FrameTicks -> None, Axes -> None, ImageSize -> 200, 
 PlotRange -> {{-0.5, 1}, {0, 1.5}}]

这样:

PHP:

对于插值,google为B-spline。剩下的如下。

For the interpolation, google for "B-spline". The rest is as follows.

首先选择原始图像的参考,比如图像是200x200,像素(1,1)地图(0,0)和像素(200,200)映射到(1,1)。

First choose a referential for the original image, say if the image is 200x200, pixel (1,1) maps (0,0) and pixel (200,200) maps to (1,1).

然后你必须猜测在应用变换时你的最终图像将落在哪里。这取决于转换,您可以例如将它应用到图像的角落或只是猜测。

Then you have to guess where your final image will land when the transformation is applied. This depends on the transformation, you can e.g. apply it to the corners of the image or just guess.

假设您考虑(-.5,0)和(1,1.5)之间的映射,就像我做的那样您的最终图像也应该是200x200。然后:

Say you consider the mapped between (-.5,0) and (1, 1.5) like I did and that your final image should be 200x200 also. Then:

$sizex = 200;
$sizey = 200;
$x = array("min"=>-.5, "max" => 1);
$y = array("min"=>0, "max" => 1.5);
// keep $sizex/$sizey == $rangex/$rangey
$rangex = $x["max"] - $x["min"];
$rangey = $y["max"] - $y["min"];
for ($xp = 1; $xp <= $sizex; $xp++) {
    for ($yp = 1; $yp <= $sizey; $yp++) {
        $value = transf(
             (($xp-1)/($sizex-1)) * $rangex + $x["min"],
             (($yp-1)/($sizey-1)) * $rangey + $y["min"]);
        /* $value should be in the form array(r, g, b), for instance */
    }
}

这篇关于用GD进行透视转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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