rozciąganie obrazu iPhone ' a (skew)

Jak wykrzywić obrazek? Na przykład każdy róg ma punkt CG z coordami - p1, p2, p3, p4. Następnie muszę ustawić-p4.x+ = 50, p4.y+ = 30. Tak więc ten róg (p4) powinien być rozciągnięty w perspektywie 2D i obraz powinien być zniekształcony.

Alt text http://www.polar-b.com/scew.png

Próbowałem użyć CATransform3D , ale wydaje się, że nie można tego zrobić w ten sposób, ponieważ jest to tylko zmiana perspektywy widzenia (obróć, zbliż/dalej z jednej strony). Może CGAffineTransform może się przydać?

Jeśli znasz odpowiedź, Napisz przykładowy kod.

Z góry dzięki

Author: andand, 2010-02-28

4 answers

Niemożliwe z CGAffineTransform. Transformata afiniczna zawsze może być rozłożona na przekłady, rotacje, ścinanie i skalowanie. Wszystkie one mapują paralelogramy w paralelogramy, których twoja transformacja nie robi.

Dla Twojej transformacji można to zrobić w dwóch krokach. Jeden do przekształcenia kwadratu w trapez.

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

Inny w kierunku pionowym. Zasada transformacji naiwnej to

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

Gdzie C jest współrzędną y punktu przecięcia linii łączenie p1 i p3 oraz p2 i p4.

Teraz zwróć uwagę na współczynnik X * y w transformacji. Oznacza to, że taka transformacja jest , a nie liniowa. Dlatego też CATransform3D nie może tego wykonać jako transformata 2D.

Jednak wektor

[x, y, z, w=1]

Zostanie przekonwertowany na rzeczywisty wektor 3D

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

Przed projekcją, jeśli CA przestrzega zwykłych reguł Grafiki obliczeniowej 3D, możesz więc "oszukać" używając transformacji

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

Z odpowiednimi P, Q, R, S, T, U to mapuje 4 punkty do oczekiwanych lokalizacji. (6 unikalnych współrzędnych i 6 zmiennych powinno mieć dokładnie 1 rozwiązanie w większości przypadków.)

Kiedy znajdziesz te 6 stałych, możesz stworzyć CATransform3D. Zauważ, że definicja struktury to

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;

Można więc bezpośrednio zmieniać elementy macierzy, zamiast polegać na funkcjach CATransform3DMake. (Może być konieczne wykonanie transpozycji ze względu na konwencję używania wektorów wierszy lub kolumn.)


To uzyskaj transformatę, aby przekształcić prostokąt ((X, Y), (W, H)) na dowolny czworokąt ((x1a, y1a), (x2a, y2a); (x3a, y3a), (x4a, y4a)), użyj tej funkcji (może być potrzebna transpozycja):

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]];
}
 81
Author: kennytm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-01 15:55:06

Transformacja 3D na UIImage / CGImageRef

Powinieneś być w stanie samodzielnie obliczyć odwzorowanie każdego piksela.. Nie idealnie, ale działa...

Jest on dostępny w tym repozytorium http://github.com/hfossli/AGGeometryKit/

Ciekawe pliki is

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


Transformacja 3D na UIView / UIImageView

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

Wtedy będziesz miał pełne kontrola nad każdym punktem w czworoboku. :)

 7
Author: hfossli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:29:31
struct CATransform3D
{
   CGFloat m11, m12, m13, m14;
   CGFloat m21, m22, m23, m24;
   CGFloat m31, m32, m33, m34;
   CGFloat m41, m42, m43, m44;
};
Aby uzyskać taki kształt, musisz dopasować m24 i m14.
 3
Author: jothikenpachi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-26 20:58:09

Wypróbowałem wspaniałą odpowiedź @ KennyTM w języku Swift i dostałem błąd "wyrażenie było zbyt złożone, aby można je było rozwiązać w rozsądnym czasie".

Oto uproszczona wersja 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)
 2
Author: Yonat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-05 16:07:56