The Savitzky–Golay method essentially performs a local polynomial regression (of degree k) on a series of values (of at least k+1 points which are treated as being equally spaced in the series) to determine the smoothed value for each point.
Savitzky–Golay 필터는 일정한 간격으로 주어진 데이터들이 있을 때(이들 데이터는 원래의 정보와 노이즈를 같이 포함한다), 각각의 점에서 주변의 점들을 가장 잘 피팅하는 k-차의 다항식을 최소자승법으로 찾아서 그 지점에서의 출력값을 결정하는 필터이다. 이 필터는 주어진 데이터에서의 극대나 극소, 또는 봉우리의 폭을 상대적으로 잘 보존한다.(주변 점들에 동등한 가중치를 주는 Moving Average Filter와 비교해 볼 수 있다).
간단한 예로, 2차의 다항식과 5개의 데이터 점
{(−2,d0),(−1,d1),(0,d2),(1,d3),(2,d4)}
을 이용해서 중앙에서의 값을 결정하는 방법을 살펴보자. 사용하려고 하는 다항식은
p(x)=a0+a1x+a2x2
이다. 다항식의 계수는 다항식의 값과 실제 데이터의 값과의 차이를 최소화시키도록 선택해야 한다. 즉, 최소자승의 원리를 적용하여서 구하면 된다. 계산된 다항식의 값과 실제 데이터 값 사이의 차의 제곱을 구하면:
이 식의 a0,a1,a2에 대한 극값을 가질 조건은(∂L/∂ai=0) 5a0+10a2=d0+d1+d2+d3+d410a1=−2d0–
이 식을 만족시키는 를 구하면, 필터의 출력(원도 중앙에서 값)이 결정된다.
필터출력필터출력
위에서 계수 , , 를 결정하는 방정식은 행렬로 정리하면 아래의 식과 같이 표현할 수 있다.
좌변의 5행 3열 행렬을 , , 로 놓으면, 이 행렬방정식은 형태로 쓸 수 있다. (design matrix)가 정방행렬이 아니므로 역행렬을 바로 구할 수 없지만, 을 최소로 하는 최소제곱해는 를 만족시켜야 하므로
로 주어짐을 알 수 있다.
이 식은 임의의 -차 다항식을 이용한 경우에도 사용할 수 있다. 이 경우 행렬(scattering matrix) 는 의 대칭행렬이 된다.행렬 는 다항식의 찻수와 피팅에 사용이 될 데이터의 구간의 크기가 주어지면 정해지므로, 윗 식에서 의 첫 행 (을 로 표현하는 식의 계수들)을 구하면 코드 내에서 결과를 lookup table로 만들어서 사용할 수 있다. 아래 표는 mathematica 를 이용해서 윈도 크기가 7 (7개 점)인 경우 2차 다항식을 사용할 때 계수를 구하는 과정이다.
2차 다항식일 때, 같은 방식으로 다양한 윈도 크기에 따른 계수를 구할 수 있다. *크기()에 따른 필터값 결정계수 (중앙에 대해 좌우대칭이다);
필터출력필터출력
std::vector<double> SavitzkyGolayFilter(std::vector<double>& data, double W[], int wsz){
constint hwsz = wsz >> 1;
wsz = (hwsz<<1) + 1;
std::vector<double> padded(data.size() + 2 * hwsz);
// reflective boundary conditions; // [hw]...[1][0][1][2]...[hw]....[n-1+hw][n-2+hw][n-3+hw]....[n-1];for (int i = 0; i < hwsz; i++) {
padded[i] = data[hwsz-i];
padded[i+data.size()+hwsz] = data[data.size()-2-i];
}
for (int i = data.size(); i-->0;) padded[i+hwsz] = data[i];
//std::vector<double> smoothed(data.size());
double wsum = 0;
for (int i = 0; i < wsz; i++) wsum += W[i];
for (int i = data.size(); i-->0;) {
double *ppad = &padded[i];
double fsum = 0;
for (int k = 0; k < wsz; k++) fsum += ppad[k] * W[k];
smoothed[i] = fsum / wsum;
}
return smoothed;
};
25 points
일반적인 찻수(order)에 대한 필터 계수 계산;
std::vector<double> sgFilterCoeffs(int width, int order/* = 2*/){
// ASSERT(width >= order+1);int hwidth = width >> 1;
width = (hwidth << 1) + 1; // width = odd number;// design matrix;std::vector<double> D((order+1) * width);
for (int i = 0; i < width; i++) {
double x = double(i) - hwidth; // -hwidth <= x <= hwidth;double *pD = &D[i*(order+1)];
pD[0] = 1;
for (int k = 1; k <= order; k++)
pD[k] = pD[k-1] * x;
};
// scattering matrix;std::vector<double> S((order+1)*(order+1)); // S=~D.D;for (int i = 0; i <= order; i++)
for (int j = i; j <= order; j++) {
double s = 0;
for (int k = 0; k < width; k++)
s += D[k*(order+1) + i] * D[k*(order+1) + j];
S[i*(order+1) + j] = s;
}
for (int i = 0; i <= order; i++)
for (int j = 0; j < i; j++)
S[i*(order+1) + j]= S[j*(order+1) + i];
// ccmath library;psinv(&S[0], order+1);
// filter coeffs = 0-th row fo S.~D;
std::vector<double> filter;
for (int i = 0; i < width; i++) {
double s = 0;
for (int k = 0; k <= order; k++)
s += S[k] * D[i*(order+1) + k];
filter.push_back(s);
}
return filter;
}
물체의 형상은 폴리곤이나 폴리곤의 집합으로 근사적으로 표현할 수 있다. 예를 들면 snake나 active shape model (ASM) 등에서 손 모양이나 얼굴의 윤곽, 또는 의료 영상 등에서 장기의 모양 등을 표현할 때 사용이 된다. 이러한 응용에서 주어진 형상을 기준으로 주어진 형상에 정렬을 시켜야 필요가 생긴다. 일반적으로 카메라를 써서 얻은 각 영상에서 추출한 정보들 사이에는 서로 사영 변환의 관계로 연결된다. 그러나 많은 경우에는 in-plane 변형만 고려해도 충분할 때가 많다. 이 경우에 가장 일반적인 형상의 변형은 affine 변환으로 표현된다. 회전(rotation), 평행 이동(translation), 크기 변환(scale transformation) 그리고 층 밀림(shear)을 허용하는 변환이다. 물론, 간단한 경우로는 shear를 제외할 수도 있고 (similarity transformation), 더 간단하게는 크기 변환을 제외할 수도 있다 (isometric transformation).
개의 꼭짓점을 갖는 두 개의 형상 , 이 affine 변환에 의해서 연결이 되는 경우에 각 꼭짓점 사이의 관계는
의 6개의 매개변수에 의해서 기술이 된다(평행 이동: 축 방향 2개, 회전: 1개, shear: 1개, 스케일: 축 방향 2개). Affine 변환에 의해서 평행인 두 직선은 변환 후에도 평행인 관계를 유지한다.
꼭짓점 위치는 실제로 다양한 영상처리 과정에 의해서 얻어지므로 필연적으로 노이즈를 포함하게 되어서 일종의 랜덤 변수로 생각해야 한다. 주어진 랜덤 변수에서 최적으로 매개변수를 추출하기 위해 최소자승법을 이용한다. Affine 변환된 좌표와 실제 측정된 좌표 사이의 거리 차이를 최소화하는 매개변수를 찾도록 하자:
Affine변환을 규정하는 매개변수를 구하기 위해서는 L을 각 매개변수에 대해서 미분해서 극값을 가질 조건을 구하면 된다:
∂L/∂a = -2 * ∑ (x'i - a * xi - b * yi - tx) * xi ; ∂L/∂b = -2 * ∑ (x'i - a * xi - b * yi - tx) * yi ; ∂L/∂c = -2 * ∑ (y'i - c * xi - d * yi - ty) * xi ; ∂L/∂d = -2 * ∑ (y'i - c * xi - d * yi - ty) * yi ; ∂L/∂tx = -2 * ∑ (x'i - a * xi - b * yi - tx) ; ∂L/∂ty = -2 * ∑ (y'i - c * xi - d * yi - ty);
아래의 그림은 지문에서 얻은 특징점을 가지고 변환을 한 것이다. 밑에 그림이 기준 template (붉은 점)이고 윗 그림은 이 기준 template와 입력된 지문의 특징점(노란 점+ 녹색점) 사이에 서로 메칭이 되는 특징점(노란색)을 찾고, 그것을 기준으로 두 지문 영상 간의 affine 파라미터를 찾아서 기준 template을 변환시킨 것이다. 이렇게 하면 새로 찾은 특징점 중에서 기준 template에 없는 특징점(녹색점)을 발견할 수 있고, 이 특징점을 기준 template에 추가하여서 좀 더 넓은 범위를 커버할 수 있는 template을 만들 수 있다. 물론 추가된 녹색점이 신뢰할 수 있는 것인가에 대한 판단을 하기 위해서는 추가적인 정보가 더 요구된다.