OpenCV Marker Recognition 글에서 카메라로 특정한 패턴의 마크를 인식하는 프로그램을 만든 적이 있습니다. 이번에는 이 프로그램을 실내용 모바일 로봇의 주행에 사용하려 합니다. 천정에 마크를 붙이고 로봇에 장착된 카메라로 마크를 봄으로 마크의 위치를 계산하고 역으로 로봇의 위치를 계산하는 방법입니다. 이 때 마크의 위치는 미리 알고 있어야 합니다. 왜냐하면, 우리는 단지 마크를 기준으로 로봇의 위치를 계산할 수 있기 때문입니다.
다음 절차를 따라 진행해 보시기 바랍니다:
1. 다음 소스코드를 다운로드 받고 특정 폴더에 압축을 풀어줍니다. 이 코드는 윈도우즈에서 실행되며, 컴파일 하려면 Visual Studio C++ 2008이 필요합니다.
2. 로지텍 화상 카메라를 구매합니다. 제가 사용한 카메라 모델번호는 C920 입니다. 구매한지가 오래된 제품이라 최근에는 더 좋은 카메라가 많이 나와있을 것 같습니다.
3. 다음 글을 참조하여 로지텍 카메라를 캘리브레이션 합니다.
xxx
4. 캘리브레이션이 끝나면 Distortion.xml 파일과 Intrinsics.xml 파일이 생성됩니다. 이 두 파일을 .\marker_recog\marker_recog 폴더에 복사합니다. (캘리브레이션이 올바르게 되지 않으면 마커의 x, y, z 위치가 정확하게 계산되지 않습니다. 그러니 카메라나 렌즈가 바뀌거나 이미지의 해상도가 바뀌는 경우에는 필히 캘리브레이션이 진행되어야 합니다.)
5. Visual Studio 2008로 marker_recog 프로젝트를 실행하여 마커가 인식되는지 확인합니다. 그리고 되도록 마커의 원점이 카메라 영상 중심에 오도록 하고 카메라 렌즈부터 마커 까지의 거리를 재 봅니다. 제가 테스트 했을 때, Laser 거리계로 잰 거리는 1.34m이고 marker_recog 프로그램이 측정한 거리는 1.36 정도로 2cm 정도 오차가 있습니다. 만일 캘리브레이션을 정확히 하면 z축의 거리도 좀 더 정확해 질 것으로 생각합니다.
6. 다음 그림을 참조하여 카메라를 로봇에 설치합니다. 카메라의 x축이 로봇의 전면부를 보도록 설치합니다. 왜냐하면 x축이 화상의 넓은 폭으로 로봇이 경로를 따라 가면서 경로상에 설치된 마커를 더 오랫동안 볼 수 있기 때문입니다.
카메라 좌표를 그려보면 다음과 같습니다.
8. 로봇이 회전되지 않은 상태(전역 좌표계를 기준으로 로봇의 theta가 0인 상태)로 로봇의 x, y 위치를 바꾸어 봅니다. 그리고 marker_recog 프로그램에서 Camera의 x, y, z 위치를 확인합니다.
1. 영상을 입력 받고 마커 인식을 처리하는 부분은 marker_recogDlg.cpp 파일의
void Cmarker_recogDlg::OnTimer(UINT_PTR nIDEvent) 함수 입니다.
이 함수를 잘 살펴보시면 됩니다.
2. 마커는 여러 개를 동시에 인식할 수 있습니다. 인식된 마커는 marker_recogDlg.cpp 파일의
void onTimer() 함수 내의 다음 부분입니다.
if (_markRecog->_markers.size()) {
DrawMarkerAxis (_markRecog->_markers[0]);
}
프로그램에서는 인식된 마커 하나만 텍스트로 출력하도록 하였으나, 실제로 인식된 마커 정보는 모두 가지고 있습니다. 다음과 같이 고치면 인식된 모든 마커를 탐색하게 됩니다.
for (int i=0; i<_markRecog->_markers.size(); i++) {
DrawMarkerAxis (_markRecog->_markers[i]);
}
3. 마커의 좌표를 카메라 좌표로 변환하는 부분은 marker_recogDlg.cpp 파일의
void Cmarker_recogDlg::DrawMarkerAxis (sMarkerInfo &mi) 함수입니다.
마커의 위치를 x,y,z 변수에 담아 theta로 회전하는 것이 전부입니다.
4. 마커의 위치를 정확히 계산하려면 마커의 크기를 설정해야 합니다.
이 부분은 marker_recogDlg.cpp 파일의 BOOL Cmarker_recogDlg::OnInitDialog() 함수에서 CMarkerDetection 클래스의 인스턴스를 생성하면서 생성자의 인자로 넘어갑니다.
_markRecog = new CMarkerDetection (0.146f, 0.146f);
5. OpenCV 라이브러리는 stdafx.cpp 파일에 설정되어 있습니다. 만일 다른 버전의 OpenCV를 사용한다면, 여기서 lib 파일의 이름을 수정하시기 바랍니다.
#pragma comment(lib,"opencv_calib3d245d.lib")
#pragma comment(lib,"opencv_core245d.lib")
#pragma comment(lib,"opencv_highgui245d.lib")
#pragma comment(lib,"opencv_imgproc245d.lib")
6. 마커 인식 알고리즘을 구현한 소스코드는 대부분 MarkerDetection.cpp 파일과 MarkerDetection.h 파일에 들어있습니다. 필요하시다면, 이 소스코드를 편집하시기 바랍니다.