2차원 이미지의 기하학적인 변형중에서 일정하게 이동을 시키고, 일정각도 회전 및 전체적인 크기의 변화를 주는 변환이 similarity transformation이다. 이 변화은 두 직선이 이루는 각도를 보존하고 길이비를 변경시키지 않는다. 이 변환보다도 더 일반적인 2차원의 기하학적인 변환은 affine transformation이다. 이것은 한쪽 방향으로의 밀림(sheer)도 허용한다. 그러다 두 직선의 각도는 변환후에도 변하지 않는다.
similarity transformation은 전체적인 크기를 바꾸는 스케일 파리미터(s) 1개와 회전각도(θ) 1개 그리고 x, y축으로의 이동을 나타내는 파라미터 2 (tx, ty)개를 합해서 총 4개의 파라미터가 필요하다. 이 파라미터에 의해서 원본 이미지의 (x,y)점이 변환된 이미지의 (u,v)에 대응한다고 하면, 이들간의 관계는 아래의 식으로 주어진다.

    u =  s*cos(θ)*x - s*sin(θ)*y + tx ;
    v =  s*sin(θ)*y + s*cos(θ)*y + ty;

 이 따라서 원본영상의 2 점에 대응하는 정보만 주어지면 파라미터(s, θ, tx, ty)를 유일하게 결정할 수 있다. 

    (x1, y1) -----> (u1, v1)
    (x2, y2) -----> (u2, v2)

그러나 많은 경우에는 기준점을 잡는데 에러등을 고려하여서 일반적으로 원본 영상의 N(>=2)개의 점에 대응하는 정보를 주게되는데, 이 경우에 변환관계식은 overdetermined되어서 해를 구할 수 없는 경우도 있다. 이 경우에는 최소자승법을 써서 변환점과 변환식에 의해서 의해서 주어지는 값의 차이를 최소화시키는 파라미터를 구해서 쓰면 된다.

L =  ∑ |ui - (s*cos(θ)*xi - s*sin(θ)*yi + tx)|^2 + |vi - (s*sin(θ)*xi + s*cos(θ)*yi + ty)|^2,           (i=1,...,N)

                        (s, θ, tx, ty) = arg min (L)

이 식을 최소화사키는 파라미터는  (a= s*cos(θ), b=s*sin(θ)로 놓으면)  a, b, tx, ty에 대해서 미분하여서 0인 조건을 만족시키면 된다.

a에 대한 미분 :   ∑ (ui - (a*xi - b*yi + tx))*(-xi) + (vi - (b*xi + a*yi + ty))*(-yi) = 0,   
b에 대한 미분 :   ∑ (ui - (a*xi - b*yi + tx))*(yi) + (vi - (b*xi + a*yi + ty))*(-xi) = 0,   
tx에 대한 미분 :  ∑ (ui - (a*xi - b*yi + tx)) = 0.
ty에 대한 미분 :  ∑ (vi - (b*xi + a*yi + ty)) = 0

따라서, Su = ∑ ui, Sv = ∑ vi, Sux = ∑ ui*xi, Suy = ∑ ui*yi, Svx = ∑ vi*xi, Svy = ∑ vi*yi , Sx = ∑ xi, Sy=∑ yi, Sxx = ∑ xi*xi, Sxy = ∑ xi*yi, Syy=∑ yi*yi 라고 하면,

-Sux  + a * Sxx - b * Sxy + tx * Sx - Svy + b*Sxy + a*Syy + ty *Sy = 0; 
  Suy - a * Sxy + b * Syy - tx * Sy -Svx + b*Sxx + a*Sxy + ty*Sx = 0;
  Su - a* Sx + b*Sy - tx * N = 0;
  Sv - b* Sx - a*Sy - ty * N = 0;

의 4개의 식을 얻으므로 4원(a,b,tx,ty) 1차 연립방정식을 풀면 된다. 이식의 답은 쉽게 구할 수 있고, 아래의 코드는 이것을 구현한 것이다. 물론, 점이 2개인 경우에는 파라미터는 유일하게 정해지고, 이보다도 더 간단한 식으로 주어진다.

//dstPt = (ST)(srcPt)
BOOL SimilarTransParams(POINT *srcPts, POINT *dstPts, int n, double ST[4]) {
    double Sx, Sy, Sxx, Syy;
    double Su, Sv, Sxu, Sxv, Syu, Syv ;
    Sx = Sy = Sxx = Syy = 0;
    Su = Sv = Sxu = Sxv = Syu = Syv = 0;
    for (int i = 0; i < n; i++) {
        double x = srcPts[i].x ;
        double y = srcPts[i].y ;
        double u = dstPts[i].x ;
        double v = dstPts[i].y ;
        Sx += x ;
        Sy += y ;
        Sxx += (x*x) ;
        Syy += (y*y) ;
        Su += u ;
        Sv += v ;
        Sxu += (x*u) ;
        Syv += (y*v) ;
    }
    double Z = Sxx + Syy ;
    double C1 = Sxu + Syv ;
    double C2 = Sxv - Syu ;
    double A[16] , invA[16] ;
    A[0]  = Sx; A[1]  = -Sy;  A[2]  =   n; A[3] = 0.;
    A[4]  = Sy; A[5]  =  Sx;  A[6]  =  0.; A[7] = n ;
    A[8]  = Z ; A[9]  =  0.;  A[10] =  Sx; A[11] = Sy;
    A[12] = 0.; A[13] =  Z;   A[14] = -Sy; A[15] = Sx;
    InvertMatrix4x4_d(A, invA) ;
    double R[4] ;
    R[0] = Su ; R[1] = Sv; R[2] = C1; R[3] = C2 ;
    // ax = scale * cos(angle) ;
    double ax = invA[0]*R[0]  + invA[1]*R[1]  + invA[2]*R[2]  + invA[3]*R[3];
    // ay = scale * sin(angle) ;
    double ay = invA[4]*R[0]  + invA[5]*R[1]  + invA[6]*R[2]  + invA[7]*R[3];
    // x-translation ;
    double tx = invA[8]*R[0]  + invA[9]*R[1]  + invA[10]*R[2] + invA[11]*R[3];
    // y-translation ;
    double ty = invA[12]*R[0] + invA[13]*R[1] + invA[14]*R[2] + invA[15]*R[3];
    ST[0] = ax ;
    ST[1] = ay ;
    ST[2] = tx ;
    ST[3] = ty ;

    return TRUE ;
}
InvertMatrix4x4()는 4x4행렬의 역행렬을 구한다(OpenCV에서)

더보기

2개의 대응점만 주어진 경우 (x1,y1), (x2, y2)-->(u1,v1), (u2,v2);
bool SimilarTransParams(double x1, double y1, double x2, double y2,
                                     double u1, double v1, double u2, double v2,
                                     double ST[4])
{
    double x21=x2-x1;
    double y21=y2-y1;
    double u21=u2-u1;
    double v21=v2-v1;
    double det=x21*x21 + y21*y21;
    if(det==0.) return false;
    double a=( x21*u21 + y21 * v21)/det ;
    double b=( x21*v21 - y21 * u21)/det ;
    double tx = u1 - a*x1 + b*y1;
    double ty = v1 - b*x1 - a*y1;
    ST[0]=a; ST[1]=b; ST[2]=tx; ST[3]=ty;
    return true;
};
얼굴인식용 training data set을 만들기위해서 얼굴을 정렬시키는데 사용한 예:
- 양 눈의 위치 변환: (70,93), (114, 84) --> (30,45), (100,45)로 변환( linear interpolation사용)
- 실제로 사용되는 변환은 정해진 dst영역으로 매핑하는 src영역을 찾아야 하므로, 역변환이 필요하다.
- 필요한 역변환은 src와 dst의 역할만 바꾸면 쉽게 구할 수 있다.

'Image Recognition' 카테고리의 다른 글

Active Shape Model :: Face  (1) 2009.12.27
Active Shape Model (ASM)  (2) 2009.12.25
Similarity Transformation  (1) 2009.12.14
Eigenface  (0) 2009.12.12
Retinex 알고리즘 관련 자료.  (1) 2009.04.29
Spline Based Snake  (0) 2008.08.15
Posted by helloktk