visual Studio 2015 - MFC/C++ MIL 라이브러리를 사용해서 작성한 코드 일부분을 가져왔습니다.
카메라로 찍은 영상을 버퍼에 올리고(흑백),
해당 픽셀의 좌우 2개, 즉, 5 픽셀 값의 평균값을 계산해서 다시 버퍼를 셋팅합니다.
(평균값을 사용하는 이유는 중간에 픽셀값이 튀거나 어두운 픽셀이 있다면 정확한 라인을 찾기 힘들기 때문입니다.)
해당 픽셀 좌우를 비교하여 일정값 이상이면 그 좌표를 저장하는 방식으로 모든 좌표를 저장합니다.
최소자승법에 사용할 좌표를 얻었으니 이제 선을 찾아봅시다!
최소자승법 식 구현
위 식을 그대로 구현하기만 하면 됩니다!
(....?)
일단 변수 선언 부터
//최소자승법 - 직선 시작 - 모두 double
double sigma_Lx, sigma_Ly, sigma_Rx, sigma_Ry;
sigma_Lx = sigma_Ly = sigma_Rx = sigma_Ry = 0.0;
double Rx_bar, Ry_bar, Lx_bar, Ly_bar;
Rx_bar = Ry_bar = Lx_bar = Ly_bar = 0.0;
//왼쪽 기울기
double La_slope_up, La_slope_down;
//오른쪽 기울기
double Ra_slope_up, Ra_slope_down;
정확하게 측정하기 위해 버퍼 기준으로 왼쪽에서 오른쪽 탐색, 오른쪽에서 왼쪽으로 탐색했습니다.
slope는 기울기이며 up은 분자, down은 분모를 뜻합니다.
1. 각 X, Y, XY의 합과 그 합의 평균을 구한다.
//점들에 대한 x, y값들의 합
for (int y = sy; y < ey; y++)
{
if (fi_Mode == L)
{
sigma_Lx += nLP[y]; // ∑L-X
sigma_Ly += y; // ∑L-Y
}
else if (fi_Mode == R)
{
sigma_Rx += nRP[y]; // ∑R-X
sigma_Ry += y; // ∑R-Y
}
}
int nCnt = ey - sy; // y의 갯수
Lx_bar = sigma_Lx / nCnt; // Lx값들의 평균
Ly_bar = sigma_Ly / nCnt; // Ly값들의 평균
Rx_bar = sigma_Rx / nCnt; // Rx값들의 평균
Ry_bar = sigma_Ry / nCnt; // Ry값들의 평균
ㅇㅋ
2. 직선의 기울기, y절편 구하기
// 2 - 1. 왼쪽 직선
CString sLine_Left, sLine_Right;
if (fi_Mode == L)
{
for (int y = sy; y < ey; y++)
{
//기존 최소자승법에서 x,y를 바꾸고 계산 - 이유는 기울기가 높아질수록 오차가 매애애애애애우 크기때문.
//기존 x,y
//La_slope_up += (y - Ly_bar) * (nLP[y] - Lx_bar);
//La_slope_down += (nLP[y] - Lx_bar) * (nLP[y] - Lx_bar);
//x,y 스왑
La_slope_up += (nLP[y] - Lx_bar) * (y - Ly_bar); //
La_slope_down += (y - Ly_bar) * (y - Ly_bar);
}
La_slope = La_slope_up / La_slope_down;
La_slope = 1 / La_slope;
Ly_axis_intercept = Ly_bar - (La_slope * Lx_bar);
sLine_Left.Format(L"Left Edge Line : %.2lfx - y + (%.21f) = 0", La_slope, Ly_axis_intercept);
/*double zz = La_slope * Lx_bar - Ly_bar + Ly_axis_intercept;// 검증용*/
}
// 2 - 1. 오른쪽 직선
else if (fi_Mode == R)
{
for (int y = sy; y < ey; y++)
{
//기존 x,y
//Ra_slope_up += (y - Ry_bar) * (nRP[y] - Rx_bar);
//Ra_slope_down += (nRP[y] - Rx_bar) * (nRP[y] - Rx_bar);
Ra_slope_up += (nRP[y] - Rx_bar) * (y - Ry_bar);
Ra_slope_down += (y - Ry_bar) * (y - Ry_bar);
}
Ra_slope = Ra_slope_up / Ra_slope_down;
Ra_slope = 1 / Ra_slope;
Ry_axis_intercept = Ry_bar - (Ra_slope * Rx_bar);
sLine_Right.Format(L"Right Edge Line : %.2lfx - y + (%.21f) = 0", Ra_slope, Ry_axis_intercept);
/*double zzz = Ra_slope * Rx_bar - Ry_bar + Ry_axis_intercept; // 검증용*/
}
이렇게 직선의 방정식을 뽑아냈습니다.
사실 최소자승법보다 더 정확하게 라인을 검출할 수 있는 방법이 있습니다만
기회가 된다면 또 포스팅하겠습니다.(응 비전 안해)