iPhone: Создание игр для iOS (iPhone и iPad)
GameDev.ru / Сообщества / iPhone / Форум / CATransform3D искажение по точкам

CATransform3D искажение по точкам

Advanced: Тема повышенной сложности или важная.
kZUraXПостоялецwww22 фев. 201221:00#0
Изображение
Я хочу сделать картинку, которую можно искажать и проецировать путем перетягивания точек в углах (как в фотошопе "проекция" или как-то так называлась, Ctrl зажимать надо было). Вроде как нашел идеальный пример http://stackoverflow.com/questions/2351586/iphone-image-stretching-skew - именно то что мне надо, но я никак не могу применить его у себя. У меня получаются огромные бессмысленные искажения, а матрица, которую я генерирую, содержит 7-ми значные цифры... (даже если не менять положение точек)

Я взял за аксиому то, что код примера ошибок не содержит, а значит я скармливаю какие-то неправильные параметры... Может кто понимает во всем этом, и может уточнить что именно значит конкретный параметр (я мог плохо перевести) или их нужно как-то подготовить (или какие-то правки внести из-за перевернутой оси координат)?

Или может кто-то просто сталкивался с такой задачей или знает как это сделать в принципе?
Делать через OpenGL я не хочу, т.к. приложение уже сформировано, и там все завязано на UIViewImage – будет много правок.

если надо будет по-позже кину исходники как я делаю.

AslanПостоялецwww23 фев. 201211:42#1
kZUraX
код в примере не разбирал, я бы решал так:

Находишь точку пересечения диагоналей на экране, обозначим ее P(x,y). Без ограничения общности, можем считать, что z этой точки=1, т.е. ее координаты в 3д : (x,y,1). Обозначим u, v - вектора, равные половинам сторон искомого четырехугольника
Выражаем через них углы четырехугольника, пользуемся соотношением:
X=x/z
Y=y/z
где (X,Y) - проекция точки (x,y,z) на экран
Получаем систему из 8 ур-й (где x1,y1,... - известные координаты точек проекций)
1: x-ux-vx=x1(1-uz-vz)
2: y-uy-vy=y1(1-uz-vz)
3: x-ux+vx=x2(1-uz+vz)
4: y-uy+vy=y2(1-uz+vz)
5: x+ux+vx=x3(1+uz+vz)
6: y+uy+vy=y3(1+uz+vz)
7: x+ux-vx=x4(1+uz-vz)
8: y+uy-vy=y4(1+uz-vz)

1:,3:=> 2*vx=x2(1-uz+vz)-x1(1-uz-vz)
5:,7:=> 2*vx=x3(1+uz+vz)-x4(1+uz-vz)
x1(1-uz-vz)-x2(1-uz+vz)+x3(1+uz+vz)-x4(1+uz-vz)=0
9: (x1-x2+x3-x4)+uz*(-x1+x2+x3-x4)+vz*(-x1-x2+x3+x4)=0

2:,4:=> 2*vy=y2(1-uz+vz)-y1(1-uz-vz)
6:,8:=> 2*vy=y3(1+uz+vz)-y4(1+uz-vz)
y1(1-uz-vz)-y2(1-uz+vz)+y3(1+uz+vz)-y4(1+uz-vz)=0
10: (y1-y2+y3-y4)+uz*(-y1+y2+y3-y4)+vz*(-y1-y2+y3+y4)=0

9:,10: =>Нашли uz,vz

добавляем условие перпендикулярности u, v
ux*vx+uy*vy+uz*vz=0

kZUraXПостоялецwww23 фев. 201213:50#2
Aslan, я наверное что-то упустил, но я так и не понял для чего мне найденные u, v - что с ними нужно делать?
если это координаты текстурной UV развертки, то я написал, что не хотел бы сводиться к OpenGL. По крайней мере пока..
AslanПостоялецwww23 фев. 201213:58#3
kZUraX
ты невнимательно читаешь, я примерно написал математический ход решения
kZUraXПостоялецwww23 фев. 201217:17#4
Aslan
спасибо конечно, но я не смог извлечь пользу из твоего ответа =( .

другой вопрос:
эта структура CATransform3D(использованием которой я бы хотел ограничиться) представляет собой матрицу 4х4:

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

Так вот, как мне из матрицы трансвормации вичислить положение углов прямоугольника (типо картинки)?
допустим у меня есть матрица трансформации 4х4, anchor, width, height и я хочу узнать куда проецируется каждый из углов этого прямоугольника?
Должно помочь при отладке

kZUraXПостоялецwww23 фев. 201220:32#5
так, с другим вопросом вроде разобрались... можно не отвечать на него)
kZUraXПостоялецwww27 фев. 201220:38#6
порывшись в интернете по теме, нашел определение того, что мне нужно, сейчас могу немного конкретизировать вопрос.
Это называется Гомография, отличное и короткое описание есть тут: http://se.math.spbu.ru/SE/YearlyProjects/2011/YearlyProjects/2011… ov_report.pdf

Там же была ссылка на функционал из OpenCV, который это реализует. Функция getPerspectiveTransform принимает 4 исходных точки изображения и 4 преобразованных, и возвращает 3х3 матрицу преобразования которое им соответствует.

Вот эта функция из OpenCV

/* Calculates coefficients of perspective transformation
 * which maps (xi,yi) to (ui,vi), (i=1,2,3,4):
 *
 *      c00*xi + c01*yi + c02
 * ui = ---------------------
 *      c20*xi + c21*yi + c22
 *
 *      c10*xi + c11*yi + c12
 * vi = ---------------------
 *      c20*xi + c21*yi + c22
 *
 * Coefficients are calculated by solving linear system:
 * / x0 y0  1  0  0  0 -x0*u0 -y0*u0 \ /c00\ /u0\
 * | x1 y1  1  0  0  0 -x1*u1 -y1*u1 | |c01| |u1|
 * | x2 y2  1  0  0  0 -x2*u2 -y2*u2 | |c02| |u2|
 * | x3 y3  1  0  0  0 -x3*u3 -y3*u3 |.|c10|=|u3|,
 * |  0  0  0 x0 y0  1 -x0*v0 -y0*v0 | |c11| |v0|
 * |  0  0  0 x1 y1  1 -x1*v1 -y1*v1 | |c12| |v1|
 * |  0  0  0 x2 y2  1 -x2*v2 -y2*v2 | |c20| |v2|
 * \  0  0  0 x3 y3  1 -x3*v3 -y3*v3 / \c21/ \v3/
 *
 * where:
 *   cij - matrix coefficients, c22 = 1
 */
cv::Mat cv::getPerspectiveTransform( const Point2f src[], const Point2f dst[] )
{
    Mat M(3, 3, CV_64F), X(8, 1, CV_64F, M.data);
    double a[8][8], b[8];
    Mat A(8, 8, CV_64F, a), B(8, 1, CV_64F, b);

    for( int i = 0; i < 4; ++i )
    {
        a[i][0] = a[i+4][3] = src[i].x;
        a[i][1] = a[i+4][4] = src[i].y;
        a[i][2] = a[i+4][5] = 1;
        a[i][3] = a[i][4] = a[i][5] =
        a[i+4][0] = a[i+4][1] = a[i+4][2] = 0;
        a[i][6] = -src[i].x*dst[i].x;
        a[i][7] = -src[i].y*dst[i].x;
        a[i+4][6] = -src[i].x*dst[i].y;
        a[i+4][7] = -src[i].y*dst[i].y;
        b[i] = dst[i].x;
        b[i+4] = dst[i].y;
    }

    solve( A, B, X, DECOMP_SVD );
    ((double*)M.data)[8] = 1.;

    return M;
}

тут вроде все ясно, кроме Сингулярного разложения (singular value decomposition, SVD), я его так и не смог понять и даже просто стянуть из OpenCV (уж слишком оно там плотно зашито).
Может кто-нить знает функцию, которая мне его сделает ( да глупо звучит немного =) ) ? или хотя бы объяснит(только не надо ссылку на вики) ?

я ещё нашел функцию которая делает svd:

int svd(int m,int n,int withu,int withv,double eps,double tol,
        double **a,double *q,double **u,double **v);
(полностью)

но в ней я не понимаю какие она параметры принимает. может это кто-нибудь подскажет?

AslanПостоялецwww28 фев. 201210:35#7
kZUraX
SVD для квадратной матрицы - представление матрицы в виде M=C(-1)*D*C, где C-матрица, составленная из собств-х векторов, D-диагональная (по диагонали - собств. значения). За общим определением - читай Вики или линейную алгебру
В OpenCV для калибровки камеры брались проекции точек с известными координатами (например узлы прямоугольной сетки, углы шахматной доски) и искалась нужная проекция решением ИЗБЫТОЧНОЙ системы лин. ур-й, методом наименьших квадратов, через SVD, подробности в Компьютерное зрение. Современный подход
Поищи метод Якоби для SVD, готовую реализацию

Вообще это скорее не то что нужно тебе, там используется МНОГО точек, чем больше, тем меньше ошибка.  Там гдето их мин. число указанно, не помню, но больше 3-4 уж точно. Надо думать

kZUraXПостоялецwww1 мар. 201218:59#8
Всем спасибо за участие ( Aslan :) , нашел решения для silverlight тут. Оно идеально подходит.

Если кому-нибудь будет нужно, вот функция:

-(void) setNewTransform
{
    // Scale transform
    MatrixNA S = New(1.0 / scW, 0, 0, 0, 1.0 / scH, 0, 0, 0, 1);
        
    // See http://www.charlespetzold.com/blog/2007/08/250638.html for math that follows

    // Where: p1 - UL, p2 - UR, p3 - LL, p4 - LR      - Corner points
    //        scW, scH    - Width, Height of image/layer
    
    // Affine transform
    double offsetX = p1.x;
    double offsetY = p1.y;
    double m11 = (p2.x - offsetX) / 1;
    double m12 = (p2.y - offsetY) / 1;
    double m21 = (p3.x - offsetX) / 1;
    double m22 = (p3.y - offsetY) / 1;
    
    MatrixNA A = New(m11, m12, 0, m21, m22, 0, offsetX, offsetY, 1);
    
    // Non-Affine transform
    double den = m11 * m22 - m12 * m21;
    double a = (m22 * p4.x - m21 * p4.y + m21 * offsetY - m22 * offsetX) / den;
    double b = (m11 * p4.y - m12 * p4.x + m12 * offsetX - m11 * offsetY) / den;
    
    m11 = a / (a + b - 1);
    m22 = b / (a + b - 1);
    double m13 = m11 - 1;
    double m23 = m22 - 1;
    
    MatrixNA B = New(m11, 0, m13, 0, m22, m23, 0, 0, 1);
    
    // Product of three transforms
    //MatrixNA M = S * B * A;    
    MatrixNA M = Mul(&S, &B);   
    M = Mul(&M, &A);           
    
    // Draw matrix
    
    CATransform3D trans;    // = picView.layer.transform;    
    trans.m11 = M.m11, trans.m12 = M.m12, trans.m13 = 0, trans.m14 = M.m13; 
    trans.m21 = M.m21, trans.m22 = M.m22, trans.m23 = 0, trans.m24 = M.m23;
    trans.m31 = 0,     trans.m32 = 0,     trans.m33 = 1, trans.m34 = 0;
    trans.m41 = M.m31, trans.m42 = M.m32, trans.m43 = 0, trans.m44 = M.m33; 
    
    [picView layer].transform = trans;        
}

/ Форум / iPhone: Создание игр / Программирование

Тема в архиве.

2001—2018 © GameDev.ru — Разработка игр