Loading [MathJax]/jax/output/CommonHTML/jax.js

영상에 담고 있는 object을 간단히 근사를 할 때 타원으로 많이 기술한다(e.g: head tracking). 타원으로 기술하면 장축의 방향으로 object의 기울어진 방향을, 장축과 단축의 길이로 object의 크기를 가늠할 수 있다. object의 픽셀 분포에서 형상에 대한 정보는 2차 moment를 계산해서 얻을 수 있다. 이는 타원이 2차 곡선이기 때문에 가능하다. 그리고 질량중심을 원점으로 잡으면 2차 central moment를 계산해야 한다. 그런데 통계적인 의미를 부여하기 위해서는 central moment를 object의 픽셀로 나눈 normalized central moment로 구성한 covariance matrix를 사용하면 된다.

Σ=(˜μ20˜μ11˜μ11˜μ02),˜μpqμpqμ00,(p+q=2) 

(Note: μ00로 정규화를 하지 않더라도 문제는 없다).

Σ는 영상에서 object pixel의 x 뱡향 분산(μ20: x축에 대한 회전관성), y 방향 분산(μ02: y축에 대한 회전관성), x-y의 correlation을 나타낸다. Σ가 대칭행렬이므로 두 개의 음이 아닌 고윳값을 가진다. 

λ1=˜μ20+˜μ022+(˜μ20˜μ02)2+4˜μ2112,λ2=˜μ20+˜μ022(˜μ20˜μ02)2+4˜μ2112

큰 고유값에 해당하는 고유벡터의 방향이 타원의 장축 방향에 해당하고 (픽셀 변동이 심하므로) , 작은 고윳값의 고유벡터 방향은 단축 방향이다. 그리고 고윳값은 각각 장축과 단축의 반지름의 제곱에 비례한다(˜μpq는 단위가 거리 제곱이다). object의 orientation인 타원의 장축 방향은 

θ=12tan1(2˜μ11˜μ20˜μ02)=12tan1(2μ11μ20μ02)

로 계산된다. (https://kipl.tistory.com/58)

 

타원의 orientation 각도를 구했으므로 두 주축을 나타내는 단위벡터는

major axis: (cosθ,sinθ),minor axis: (sinθ,cosθ)

로 쓸 수 있다. 그리고 이 두 축에 대한 object의 회전관성은 정의에 의해서 다음 식으로 구할 수 있다: (ˉx,ˉy)=center of mass

major axis: Imin=(x,y)object|(xˉx)sinθ+(yˉy)cosθ|2=μ20+μ022μ20μ022cos(2θ)μ11sin(2θ)

minor axis: Imax=(x,y)object|(xˉx)cosθ+(yˉy)sinθ|2=μ20+μ022+μ20μ022cos(2θ)+μ11sin(2θ)

(note: object의 orientation 각은 Imin을 최소화시키는 값이다)

 

표준 타원의 장축 반지름이 a고 단축 반지름이 b일 때 (x2/a2+y2/b2=1) 2차 central moment(회전관성)는 간단한 계산에 의해서

μ(e)20=π4a3b,μ(e)02=π4ab3,μ(e)11=0

으로 구해짐을 알 수 있다.

 

주어진 타원이 object을 잘 피팅하려면 타원의 두 축에 대한 회전관성이 각각 object의 주축에 대한  회전관성과 같은 값을 가져야 할 것이다:

Imin=μ(e)20,Imax=μ(e)02

이 두 식을 풀면 타원의 장축과 단축의 반지름을 구할 수 있다. 

a=(4π)1/4(I3maxImin)1/8,b=(4π)1/4(I3minImax)1/8

 

보통 object을 타원 피팅할 때 윤곽선 정보를 이용하는데, 이 방법은 윤곽선을 추출할 필요가 없어서 편리하다. 단 내부에 빈 곳이 있는 object의 경우 회전관성을 감소시키므로 좋은 결과를 기대할 수 없다. 영상이 다수의 object를 담고 있을 때는 connected component labeling을 한 후 각각의 component에 대해서 fitting을 수행하면 된다.

void getEllipse(CRaster& raster) {
    const double four_pi = 1.0 / atan(1.0);
    CSize sz = raster.GetSize();
    double xsum = 0, ysum = 0;
    double x2sum = 0, y2sum = 0, xysum = 0;
    int count = 0;
    for (int y = 0; y < sz.cy; y++) {
        BYTE *p = (BYTE *)raster.GetLinePtr(y);
        for (int x = 0; x < sz.cx; x++) {
            if (*p++) {
                count++;
                xsum += x;      ysum += y;
                x2sum += x * x; y2sum += y * y; 
                xysum += x * y;
            }
        }
    }
    if (!count) return;
    double xm = xsum / count;
    double ym = ysum / count;
    double m20 = x2sum - xm * xm * count;
    double m02 = y2sum - ym * ym * count;
    double m11 = xysum - xm * ym * count;
    double theta2 = atan2(2 * m11, m20 - m02);
    double ct = cos(theta2), st = sin(theta2);
    double Imin = 0.5 * (m20 + m02) - 0.5 * (m20 - m02) * ct - m11 * st;
    double Imax = 0.5 * (m20 + m02) + 0.5 * (m20 - m02) * ct + m11 * st;
    double major = pow(four_pi, 0.25) * pow(Imax * Imax * Imax / Imin, 0.125);
    double minor = pow(four_pi, 0.25) * pow(Imin * Imin * Imin / Imax, 0.125);
    drawEllipse(raster, mx, my, major, minor, theta2 / 2);
}
728x90

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

Circle Fitting: Pratt  (0) 2022.01.20
Best-fit Ellipse 2  (0) 2022.01.18
Image Moments  (0) 2021.12.04
Orientation 추정  (0) 2021.11.30
Poisson Image Editing  (0) 2021.08.03
,

원뿔을 평면으로 잘랐을 때 나타나는 곡선인 conic section은 직교 좌표계에서 (x,y)에 대한 2차 형식으로 쓰인다.

F(x,y)=ax2+bxy+cy2+dx+ey+f=0

이 conic section이 타원을 기술할 때 parameter {a,b,c,d,e,f}를 이용해서 타원의 중심, 장축과 단축의 길이, 그리고 회전각에 대한 공식을 구해보자. 2차 항을 행렬을 써서 표현하면

(x,y)(ab/2b/2c)(xy)+=0

따라서, 적절한 회전 변환을 하면 두 좌표의 곱으로 주어지는 xy-항을 없앨 수 있다. 회전 변환을 시행하면 행렬은 eigenvalue를 성분으로 하는 대각 행렬이 된다. 회전 변환이 determinant를 보존하므로 determinant는 행렬의 두 eigenvalue의 곱으로 주어짐을 알 수 있다.

(ab/2b/2c)(λ100λ2)det=acb2/4

회전 후의 방정식이 타원의 방정식(원점이 이동된)을 기술하기 위해서는 det>0 이어야 한다 (회전시킨 후 식에서 x2y2의 계수는 두 eigenvalue로 주어지므로 같은 부호를 가져야 한다.)

F=ellipseb24ac<0

conic section F가 타원을 기술한다면, 다음과 같이 평행이동을 시켜서 타원의 중심 (x0,y0)이 원점에 놓이게 하고, 회전변환을 시켜서 xy 항을 없애도록 하자.

xx0+xcosθysinθ,yy0+xsinθ+ycosθ

여기서 회전각 θx을 기준으로 측정된다. F에 적용해서 xy-항이 없어지는 조건과 1차 항이 사라지도록 하는 조건을 찾으면 타원의 중심 (x0,y0)θ는 

tan2θ=bacellipse center:  (x0,y0)=(2cdbeb24ac,2aebdb24ac)

로 주어짐을 확인할 수 있다. Eigenvalue의 제곱근의 역수가 두 축의 반지름을 결정하므로 음수가 되어서는 안된다 (둘 중 하나가 0이면 직선이고, 둘 모두 0이면 한 점에 해당). 이는 대칭행렬의 고유값이 항상 0보다 작지 않다는 사실에서 기인한다. 위에서 구한 회전각 θ를 이용해서 두 고유값을 표현하면 ,

λ1=acos2θ+bcosθsinθ+csin2θ

λ2=asin2θbcosθsinθ+ccos2θ

위의 회전변환식을 대입했을 떄 나머지 상수항은 (첫 번째 등호는 계산해서 확인할 수 있음)

ax20+bx0y20+cy20+dx0+ey0+f=f(ax20+bx0y0+cy20)scale1

로 주어짐을 알 수 있다. 따라서 회전시킨 타원은 표준형 꼴

λ1x2+λ2y2=scale1

로 표현된다. 이 표준형 타원의 두 축의 반지름은 각각

rx=scale1λ1,ry=scale1λ2 로 주어진다.

// conic_params(a, b, c, d, e, f): ax^2 + bxy + cy^2 + dx + ey + f = 0;
// ellipse_params(radius_x, radius_y, center_x, center_y, tilt_angle w.r.t x-axis);
bool conic_to_ellipse(double conic_params[6], double ellipse_params[5]) {
    const double a = conic_params[0];
    const double b = conic_params[1];
    const double c = conic_params[2];
    const double d = conic_params[3];
    const double e = conic_params[4];
    const double f = conic_params[5];
    // get ellipse orientation w.r.t x-axis;
    const double theta = 0.5 * atan2(b, a - c);
    // get scaled x/y radius;
    const double ct = cos(theta);
    const double st = sin(theta);
    const double ap = a * ct * ct + b * ct * st + c * st * st;
    const double cp = a * st * st - b * ct * st + c * ct * ct;
    // get center of ellipse;
    const double cx = (2 * c * d - b * e) / (b * b - 4 * a * c);
    const double cy = (2 * a * e - b * d) / (b * b - 4 * a * c);
    // get scale factor
    const double val = a * cx * cx + b * cx * cy + c * cy * cy;
    const double scale_inv = val - f;
    if (scale_inv / ap <= 0 || scale_inv / cp <= 0) {
        TRACE("Error! ellipse parameters are imaginary\n");
        return 0;
    }
    ellipse_params[0] = sqrt(scale_inv / ap);
    ellipse_params[1] = sqrt(scale_inv / cp);
    ellipse_params[2] = cx;
    ellipse_params[3] = cy;
    ellipse_params[4] = theta;
    return 1;
};
728x90
,