Perspective transformation with GD

我是研究僧i 提交于 2019-12-12 08:48:54

问题


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


回答1:


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.


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

For a 3*3 matrix m, ImagePerspectiveTransformation[image,m] applies LinearFractionalTransform[m] to image.

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

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 /@ # &

which gives:

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

With the example:

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

You get this transformation:

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.

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.

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}}]

This gives:

PHP:

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

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.

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 */
    }
}


来源:https://stackoverflow.com/questions/3540001/perspective-transformation-with-gd

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!