이미지에서 관찰된 점집합이
데이터를 얻는 측정 과정에서 측정값
의 형태가 된다. 따라서 최소자승법은 이 likelihood를 최대화시키는 파라미터를 찾는 방법이 된다. 최소자승법은 피팅 파라미터를 주어진 데이터를 이용해서 표현할 수 있는 장점은 있지만, outliers에 대해서 매우 취약하다 (아래의 결과 그림을 참조). 이는 적은 수의 outlier도 χ2에 큰 기여를 할 수 있기 때문이다. 따라서 피팅을 좀 더 robust 하게 만들기 위해서는 outliers가 likelihood에 기여하는 정도를 줄여야 한다. 이를 위해서는 likelihood의 지수 인자를 큰 에러에서 덜 민감하게 반응하는 꼴로 바뀌어야 한다. 이를 만족하는 가장 간단한 것 방법 중 하나가 square-deviation 대신에 absolute-deviation을 이용하는 것이다:
그러나 이 식을 사용하는 경우에는 최소자승법과 다르게 기울기
수열
임을 알 수 있다. 그리고 absolute deviation 식을 절편
을 얻는데, 위에서 구한 기울기
double FitLine_LS(std::vector<double>& x, std::vector<double>& y, double *a, double *b);
// 최소자승법을 이용한 직선 추정:
// return (sigma[dy] / sigma[x]);
double FitLine_LS(std::vector<double>& x, std::vector<double>& y, double& a, double& b) {
double sx = 0, sy = 0, sxx = 0, sxy = 0;
for (int i = x.size(); i-->0;) {
sx += x[i]; sy += y[i];
sxx += x[i] * x[i]; sxy += x[i] * y[i];
};
const int n = x.size();
double det = n * sxx - sx * sx;
if (det == 0.) return -1; // vertical line;
a = (sxx * sy - sx * sxy) / det;
b = (n * sxy - sx * sy) / det;
double chi2 = 0;
for (int i = x.size(); i-->0;) {
double t = y[i] - (*a + *b * x[i]);
chi2 += t * t;
}
det /= n; //det -> var(x) * n;
// chi2 = var(dy) * n;
// (dy vs x의 편차비)
return sqrt(chi2 / det);
}
// 기울기(bb)가 주어진 경우에 y-절편(median = aa)값을 추정하고, 이 때 AD값을 얻는다.
double RhoFunc(std::vector<double>& x, std::vector<double>& y,
double bb, double& aa, double& abdev) {
std::vector<double> h(x.size());
for (int i = x.size(); i-->0;) h[i] = y[i] - bb * x[i];
std::sort(h.begin(), h.end());
// median;
const int med = h.size()/2;
aa = (h.size() & 1) ? h[med] : (h[med] + h[med-1])/2;
double sum = 0;
abdev = 0;
for (int i = x.size(); i-->0;) {
double d = y[i] - (bb * x[i] + aa);
abdev += fabs(d);
// sign-함수의 원점에서 모호함을 없애기 위해서 증폭을 시킴;
if (y[i] != 0.) d /= fabs(y[i]);
if (fabs(d) > DBL_EPSILON) // sign 함수의 모호함에서 벗어나면,
sum += (d >= 0 ? x[i] : -x[i]);
}
return sum; // return sum{xi * sign(yi - (b * xi + a))}
};
// y = a + b * x ;
// Least Absolute Deviation:
double FitLine_MAD (std::vector<double>& x, std::vector<double>& y,
double& a, double& b) {
// least square esimates for (aa, bb);
double aa, bb, abdev;
double sigb = FitLine_LS(x, y, aa, bb); // estimate: y=aa + bb*x;
double b1 = bb;
double f1 = RhoFunc(x, y, b1, aa, abdev);
/* bracket 3-sigma away in the downhill direction;*/
double b2 = fabs(3 * sigb);
b2 = bb + (f1 < 0 ? -b2 : b2);
double f2 = RhoFunc(x, y, b2, aa, abdev);
// if conditional added to take care of the case of a
// line input into this function. It is needed to avoid an
// infinite loop when (b1 == b2) (within floating point error)
if (fabs(b2 - b1) > (sigb + 0.005)) {
// bracketing;
while ((f1 * f2) > 0) {
bb = 2 * b2 - b1;
b1 = b2; b2 = bb;
f1 = f2; f2 = RhoFunc(x, y, b2, aa, abdev) ;
}
}
// refine until the error is a negligible number of std;
sigb *= 0.01;
while (fabs(b2 - b1)> sigb) {
// bisection;
bb = (b1 + b2) / 2.;
if ((bb == b1) || (bb == b2)) break ;
double f = RhoFunc(x, y, bb, aa, abdev) ;
if ((f * f1) >= 0) {
f1 = f; b1 = bb;
} else {
f2 = f; b2 = bb;
}
}
a = aa; b = bb;
return (abdev/x.size());
}
// 붉은 선--> 최소자승법에 의한 피팅.: outlier에 매우 취약한 구조.
// 파란 선--> least absolute deviation을 이용한 피팅: outlier에 매우 robust 하다.

'Image Recognition' 카테고리의 다른 글
RANSAC: Circle Fit (0) | 2008.07.21 |
---|---|
KMeans Algorithm (0) | 2008.07.19 |
EM: Binarization (0) | 2008.07.01 |
EM Algorithm: Line Fitting (0) | 2008.06.29 |
Gaussian Mixture Model (2) | 2008.06.07 |