Estensione dell’immagine iPhone (inclinata)

Come si distorce un’immagine? Ad esempio, ogni angolo ha un punto di divisione con coordinate – p1, p2, p3, p4. Quindi, ho bisogno di impostare – p4.x + = 50, p4.y + = 30. Quindi questo angolo (p4) dovrebbe essere allungato in una prospettiva 2D e l’immagine dovrebbe essere distorta.

alt text http://sofit.miximages.com/image/scew.png

Ho provato ad usare CATransform3D , ma sembra che questo non possa essere fatto in questo modo, dal momento che è solo un cambiamento della prospettiva di visualizzazione (ruotare, avvicinare / allontanare un lato). Forse CGAffineTransform può essere utile?

Se conosci la risposta, scrivi un codice di esempio.

Grazie in anticipo

    Non ansible con CGAffineTransform. Una trasformazione affine può sempre essere scomposta in traduzioni, rotazioni, taglio e ridimensionamento. Tutti mappano i parallelogrammi in parallelogrammi, che la tua trasformazione non ha.

    Per la tua trasformazione, può essere fatto in due passaggi. Uno per convertire il quadrato in un trapezio.

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

    Un altro alla direzione verticale. È una regola di trasformazione ingenua

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

    dove c è la coordinata y del punto di intersezione delle linee che uniscono p1 e p3 e p2 e p4.

    Ora noti il ​​fattore x * y nella trasformazione. Questo indica che una tale trasformazione non è lineare. Pertanto, CATransform3D non può eseguire questo come una trasformazione 2D.

    Tuttavia, il vettore

     [x, y, z, w=1] 

    sarà convertito nel vettore 3D reale

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

    prima della proiezione se CA segue le normali regole grafiche di elaborazione 3D, in modo da poter “imbrogliare” utilizzando la trasformazione

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

    con le appropriate P, Q, R, S, T, U che mappano i 4 punti alle posizioni previste. (6 uniche coordinate e 6 variabili dovrebbero avere esattamente 1 soluzione nella maggior parte dei casi).

    Quando hai trovato queste 6 costanti, puoi creare un CATransform3D . Si noti che la definizione della struttura è

     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; 

    Quindi puoi cambiare direttamente gli elementi della matrice, invece di affidarti alle funzioni CATransform3DMake. (Potrebbe essere necessario eseguire una trasposizione a causa della convenzione sull’uso di vettori di riga o colonna.)


    Per ottenere la trasformazione per convertire un rettangolo ((X, Y), (W, H)) in qualsiasi quadrilatero ((x1a, y1a), (x2a, y2a); (x3a, y3a), (x4a, y4a)), usa questa funzione (potresti aver bisogno di una trasposizione):

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

    Trasformazione 3D su UIImage / CGImageRef

    Dovresti essere in grado di calcolare da solo la mapping di ciascun pixel. Non perfetto, ma fa il trucco …

    È disponibile su questo repository http://github.com/hfossli/AGGeometryKit/

    I file interessanti sono

    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


    Trasformazione 3D su UIView / UIImageView

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

    Quindi avrai il pieno controllo su ogni punto nel quadrilatero. 🙂

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

    Devi regolare m24 e m14 per ottenere una tale forma.

    Ho provato la meravigliosa risposta @KennyTM in Swift e ho ricevuto un errore “L’espressione era troppo complessa per essere risolta in tempi ragionevoli”.

    Quindi ecco una versione semplificata per 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)