estiramiento de imagen de iPhone (sesgo)

¿Cómo puedo sesgar una imagen? Por ejemplo, cada esquina tiene un CGPoint con coords – p1, p2, p3, p4. Entonces, necesito establecer – p4.x + = 50, p4.y + = 30. Por lo tanto, esta esquina (p4) debe estirarse en una perspectiva 2D y la imagen debe estar distorsionada.

texto alternativo http://sofes.miximages.com/image/scew.png

Traté de usar CATransform3D , pero parece que esto no se puede hacer de esa manera, ya que es solo un cambio la perspectiva de la vista (rotar, acercar / alejar un lado). Tal vez CGAffineTransform puede ser útil?

Si conoce la respuesta, por favor escriba un código de muestra.

Gracias por adelantado

No es posible con CGAffineTransform. Una transformación afín siempre se puede descomponer en traducciones, rotaciones, corte y escala. Todos ellos asignan paralelogramos en paralelogramos, que tu transformación no hace.

Para su transformación, se puede hacer en dos pasos. Uno para convertir el cuadrado en un trapezoide.

p1-----p2 p1-----p2 | | --> | \ p3-----p4 p3--------p4' 

Otro a la dirección vertical. Una regla de transformación ingenua es

  y - c x' = (x - p1.x) * ———————— + p1.x p1.y - c y' = y 

donde c es la coordenada y del punto de intersección de las líneas que unen p1 y p3, y p2 y p4.

Ahora observe el factor x * y en la transformación. Esto indica que tal transformación no es lineal. Por lo tanto, CATransform3D tampoco puede realizar esto como una transformación 2D.

Sin embargo, el vector

 [x, y, z, w=1] 

se convertirá en el vector 3D real

 (x/w, y/w, z/w) 

antes de la proyección si CA sigue las reglas habituales de gráficos de computación 3D, por lo que podría “hacer trampa” utilizando la transformación

 [ P . . Q ] [ x ] [ x' ] [ . R . S ] [ y ] = [ y' ] [ . . 1 . ] [ z ] [ z' ] [ . T . U ] [ 1 ] [ w' ] 

con P, Q, R, S, T, U apropiados que mapea los 4 puntos a las ubicaciones esperadas. (6 coordenadas únicas y 6 variables deberían tener exactamente 1 solución en la mayoría de los casos).

Cuando haya encontrado estas 6 constantes, puede crear un CATransform3D . Observe que la definición de la estructura es

 struct CATransform3D { CGFloat m11, m12, m13, m14; CGFloat m21, m22, m23, m24; CGFloat m31, m32, m33, m34; CGFloat m41, m42, m43, m44; }; typedef struct CATransform3D CATransform3D; 

Entonces puede cambiar directamente los elementos de la matriz, en lugar de confiar en las funciones CATransform3DMake. (Es posible que deba realizar una transposición debido a la convención de usar vectores de fila o columna).


Para obtener la transformación para convertir un rectángulo ((X, Y), (W, H)) a cualquier cuadrilátero ((x1a, y1a), (x2a, y2a); (x3a, y3a), (x4a, y4a)), use esta función (puede necesitar una transposición):

 function compute_transform_matrix(X, Y, W, H, x1a, y1a, x2a, y2a, x3a, y3a, x4a, y4a) { var y21 = y2a - y1a, y32 = y3a - y2a, y43 = y4a - y3a, y14 = y1a - y4a, y31 = y3a - y1a, y42 = y4a - y2a; var a = -H*(x2a*x3a*y14 + x2a*x4a*y31 - x1a*x4a*y32 + x1a*x3a*y42); var b = W*(x2a*x3a*y14 + x3a*x4a*y21 + x1a*x4a*y32 + x1a*x2a*y43); var c = H*X*(x2a*x3a*y14 + x2a*x4a*y31 - x1a*x4a*y32 + x1a*x3a*y42) - H*W*x1a*(x4a*y32 - x3a*y42 + x2a*y43) - W*Y*(x2a*x3a*y14 + x3a*x4a*y21 + x1a*x4a*y32 + x1a*x2a*y43); var d = H*(-x4a*y21*y3a + x2a*y1a*y43 - x1a*y2a*y43 - x3a*y1a*y4a + x3a*y2a*y4a); var e = W*(x4a*y2a*y31 - x3a*y1a*y42 - x2a*y31*y4a + x1a*y3a*y42); var f = -(W*(x4a*(Y*y2a*y31 + H*y1a*y32) - x3a*(H + Y)*y1a*y42 + H*x2a*y1a*y43 + x2a*Y*(y1a - y3a)*y4a + x1a*Y*y3a*(-y2a + y4a)) - H*X*(x4a*y21*y3a - x2a*y1a*y43 + x3a*(y1a - y2a)*y4a + x1a*y2a*(-y3a + y4a))); var g = H*(x3a*y21 - x4a*y21 + (-x1a + x2a)*y43); var h = W*(-x2a*y31 + x4a*y31 + (x1a - x3a)*y42); var i = W*Y*(x2a*y31 - x4a*y31 - x1a*y42 + x3a*y42) + H*(X*(-(x3a*y21) + x4a*y21 + x1a*y43 - x2a*y43) + W*(-(x3a*y2a) + x4a*y2a + x2a*y3a - x4a*y3a - x2a*y4a + x3a*y4a)); return [[a,b,0,c],[d,e,0,f],[0,0,1,0],[g,h,0,i]]; } 

Transformación 3D en UIImage / CGImageRef

Deberías poder calcular el mapeo de cada píxel tú mismo. No es perfecto, pero funciona …

Está disponible en este repository http://github.com/hfossli/AGGeometryKit/

Los archivos interesantes son

https://github.com/hfossli/AGGeometryKit/blob/master/Source/AGTransformPixelMapper.m

https://github.com/hfossli/AGGeometryKit/blob/master/Source/CGImageRef%2BCATransform3D.m

https://github.com/hfossli/AGGeometryKit/blob/master/Source/UIImage%2BCATransform3D.m


Transformada 3D en UIView / UIImageView

https://stackoverflow.com/a/12820877/202451

Entonces tendrás control total sobre cada punto en el cuadrilátero. 🙂

 struct CATransform3D { CGFloat m11, m12, m13, m14; CGFloat m21, m22, m23, m24; CGFloat m31, m32, m33, m34; CGFloat m41, m42, m43, m44; }; 

Tienes que ajustar m24 y m14 para obtener esa forma.

Probé la maravillosa respuesta @KennyTM en Swift, y obtuve un error “La expresión era demasiado compleja para ser resuelta en un tiempo razonable”.

Así que aquí hay una versión simplificada para Swift:

 let y21 = y2a - y1a let y32 = y3a - y2a let y43 = y4a - y3a let y14 = y1a - y4a let y31 = y3a - y1a let y42 = y4a - y2a let a = -H*(x2a*x3a*y14 + x2a*x4a*y31 - x1a*x4a*y32 + x1a*x3a*y42) let b = W*(x2a*x3a*y14 + x3a*x4a*y21 + x1a*x4a*y32 + x1a*x2a*y43) let c0 = -H*W*x1a*(x4a*y32 - x3a*y42 + x2a*y43) let cx = H*X*(x2a*x3a*y14 + x2a*x4a*y31 - x1a*x4a*y32 + x1a*x3a*y42) let cy = -W*Y*(x2a*x3a*y14 + x3a*x4a*y21 + x1a*x4a*y32 + x1a*x2a*y43) let c = c0 + cx + cy let d = H*(-x4a*y21*y3a + x2a*y1a*y43 - x1a*y2a*y43 - x3a*y1a*y4a + x3a*y2a*y4a) let e = W*(x4a*y2a*y31 - x3a*y1a*y42 - x2a*y31*y4a + x1a*y3a*y42) let f0 = -W*H*(x4a*y1a*y32 - x3a*y1a*y42 + x2a*y1a*y43) let fx = H*X*(x4a*y21*y3a - x2a*y1a*y43 - x3a*y21*y4a + x1a*y2a*y43) let fy = -W*Y*(x4a*y2a*y31 - x3a*y1a*y42 - x2a*y31*y4a + x1a*y3a*y42) let f = f0 + fx + fy; let g = H*(x3a*y21 - x4a*y21 + (-x1a + x2a)*y43) let h = W*(-x2a*y31 + x4a*y31 + (x1a - x3a)*y42) let i0 = H*W*(x3a*y42 - x4a*y32 - x2a*y43) let ix = H*X*(x4a*y21 - x3a*y21 + x1a*y43 - x2a*y43) let iy = W*Y*(x2a*y31 - x4a*y31 - x1a*y42 + x3a*y42) var i = i0 + ix + iy let epsilon = CGFloat(0.0001); if fabs(i) < epsilon { i = epsilon * (i > 0 ? 1 : -1); } return CATransform3D(m11: a/i, m12: d/i, m13: 0, m14: g/i, m21: b/i, m22: e/i, m23: 0, m24: h/i, m31: 0, m32: 0, m33: 1, m34: 0, m41: c/i, m42: f/i, m43: 0, m44: 1.0) 
    Intereting Posts