본문 바로가기

카테고리 없음

천정의 마커 인식을 통한 로봇의 위치인식

OpenCV Marker Recognition 글에서 카메라로 특정한 패턴의 마크를 인식하는 프로그램을 만든 적이 있습니다. 이번에는 이 프로그램을 실내용 모바일 로봇의 주행에 사용하려 합니다. 천정에 마크를 붙이고 로봇에 장착된 카메라로 마크를 봄으로 마크의 위치를 계산하고 역으로 로봇의 위치를 계산하는 방법입니다. 이 때 마크의 위치는 미리 알고 있어야 합니다. 왜냐하면, 우리는 단지 마크를 기준으로 로봇의 위치를 계산할 수 있기 때문입니다.

다음 절차를 따라 진행해 보시기 바랍니다:

 

1. 다음 소스코드를 다운로드 받고 특정 폴더에 압축을 풀어줍니다. 이 코드는 윈도우즈에서 실행되며, 컴파일 하려면 Visual Studio C++ 2008이 필요합니다. 

marker_recog.zip
0.08MB

 

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축이 화상의 넓은 폭으로 로봇이 경로를 따라 가면서 경로상에 설치된 마커를 더 오랫동안 볼 수 있기 때문입니다.

카메라 좌표를 그려보면 다음과 같습니다.

 

카메라에서 보는 영상과는 y축이 반대인 것을 주의하십시오.
 
7. 천정에 마커를 붙입니다. 마커를 붙일 때는 카메라에서 다음과 같이 보이도록 붙이시기 바랍니다. 바닥의 전역 좌표계를 기준으로 본다면, 천정의 마커는 바닥에 붙어있는 마커의 거울상이 됩니다. (여기서 실제로 마커는 바닥에 붙어있지 않지만, 마커를 내려다 보았을 때 y축이 반대이기 때문에 거울상을 만들면 y축이 정방향으로 보이게 됩니다. 그러니 마커를 천정에 붙이고 바닥의 거울상이라 생각하면, 바닥의 마커는 정상상이 됩니다.)
 

 

실제로 마커의 좌표계는 다음과 같습니다.  

 

8. 로봇이 회전되지 않은 상태(전역 좌표계를 기준으로 로봇의 theta가 0인 상태)로 로봇의 x, y 위치를 바꾸어 봅니다. 그리고 marker_recog 프로그램에서 Camera의 x, y, z 위치를 확인합니다.
 
9. 로봇을 회전한 상태로 로봇의 x, y 위치를 바꾸어 봅니다. 그리고 marker_recog 프로그램에서 Camera의 x, y, z 위치를 확인해 보십시오. 아마도 x, y, z가 전역 좌표계를 기준으로 잘 나올 것입니다. 그리고 로봇의 회전각도 올바르게 측정될 것입니다.
 
10. 인식률을 높이기 위해서는 반사지를 사용하여 마커를 제작해 보시기 바랍니다.
 

 

 

 
* 다음은 소스코드에 대한 간략한 설명입니다. 

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 파일에 들어있습니다. 필요하시다면, 이 소스코드를 편집하시기 바랍니다.