2010-08-22 28 views
6

¿Cómo se puede aplicar una transformación de perspectiva en una imagen utilizando sólo la biblioteca GD de PHP?transformación de perspectiva con GD

no quiero utilizar una función a otra persona hizo Quiero ENTENDER lo que está pasando

+0

Esto ya ha sido respondido [aquí] [1]. [1]: http://stackoverflow.com/a/2536847/577306 – Jarrod

Respuesta

9

Sinceramente, no sé cómo describir matemáticamente una distorsión de la perspectiva. Puede intentar buscar en la literatura para eso (por ejemplo, Google Scholar). Consulte también en la documentación de OpenGL, glFrustum.


EDITAR: Curiosamente, comenzando con la versión 8, Mathematica tiene un ImagePerspectiveTransformation. En la parte pertinente, dice:

Para una matriz de 3 * 3 m, ImagePerspectiveTransformation[image,m] se aplica a LinearFractionalTransform[m] imagen.

Esta es una transformación que, por alguna a (matriz), b (vector), c (vector) y d (escalar), transforma el vector r a (a.r+b)/(c.r+d). En una situación en 2D, esto le da al homogeneous matrix:

a_11 a_12 b_1 
a_21 a_22 b_2 
c_1 c_2 d 

para aplicar la transformación, se multiplica esta matriz por el vector columna extendida con z=1 y luego tomar los dos primeros elementos del resultado y dividirlos por el tercero:

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

que da:

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

Con el ejemplo:

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

Se obtiene esta transformación:

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 
] 

Transformation result


Una vez que tenga un mapa que describe la posición de un punto de la imagen final en términos de un punto en el original imagen, solo se trata de encontrar su valor para cada uno de los puntos en la nueva imagen.

Hay una dificultad adicional. Como una imagen es discreta, es decir, tiene píxeles en lugar de valores continuos, debe hacerla continua.

Supongamos que tiene una transformación que duplica el tamaño de una imagen. La función para calcular un punto {x,y} en la imagen final buscará el punto {x/2, y/2} en el original. Este punto no existe, porque las imágenes son discretas. Entonces debes interpolar este punto. Hay varias estrategias posibles para esto.

En este ejemplo Mathematica, hago una simple rotación 2D y utilizar una función spline grado-1 para interpolar:

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

Esto da:

alt text

PHP:

Para la interpolación, google para "B-spline". El resto es el siguiente.

Primero elija un referencial para la imagen original, digamos si la imagen es de 200x200, píxeles (1,1) mapas (0,0) y píxeles (200,200) se asigna a (1,1).

Luego tiene que adivinar dónde aterrizará su imagen final cuando se aplique la transformación. Esto depende de la transformación, puede, por ejemplo, aplicarlo a las esquinas de la imagen o simplemente adivinar.

Supongamos que considera el mapa entre (-5,0) y (1, 1,5) como lo hice y que su imagen final también debería ser 200x200. Entonces:

$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 */ 
    } 
} 
+0

interesante pero que no parece ser código PHP (¿es?) –

+0

@ Marcos No, no lo es. Es Mathematica. En PHP, tendría que implementar la spline usted mismo y usar dos bucles (anidados) para construir la gráfica paramétrica. Pero el principio es el mismo. – Artefacto

+0

¿Cómo implementaría eso en PHP con los bucles? –

Cuestiones relacionadas