views:

273

answers:

1

How could you distort an image with PHP GD from this...

alt text

To this...
alt text

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

+7  A: 

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.

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:

alt text

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 */
    }
}
Artefacto
Interesting but that doesn't seem to be PHP code (Is it?)
Mark
@Mark No, it's not. It's Mathematica. In PHP, you'd have to implement the spline yourself and use two loops (nested) to build the parametric plot. But the principle is the same.
Artefacto
How would you implement that into PHP with the loops?
Mark
@Mark See my edit.
Artefacto
@geon That's what the phrase says. The "its" refers to the mapping (the function that takes the new to the old).
Artefacto