OpenCV 관련 서적엔 꼭 있는 내용이며, 그만큼 중요하고, 또 어려운 카메라 캘리브레이션에 대해 소개할까 한다. 책으로 공부하게 되면 거의 뒷부분에 카메라 왜곡, 스테레오 카메라 구현에서 이 개념이 함께 소개된다. 필자가 공부했던 "Learning OpenCV 제대로 배우기"(나방 책)에선, 처음에 핀홀 카메라에 대해서 설명하고, 다소 복잡한 선형대수가 나오며, 갑자기 뜬금없는 체스보드 판이 등장하여 그것으로 왔다 갔다 흔들면 왜곡이 없어진다고 한다. "이게 당최 무슨 소리지? 토 나온다." 라고 생각한 사람이 많을 것이다. 그렇지 않았으면 "카메라 캘리브레이션"을 검색하여, 굳이 이 글을 보고 있지 않았을 테니 말이다. 공부를 시작하는 대부분의 사람들이 그렇게 느낄 것이고 필자 또한 그렇게 느꼈다. 이 개념을 이해하기 위해 인터넷 자료도 많이 찾아다녔지만, 거의 모든 자료들이 체스보드 판만 들고 있었고, 개념 또한 쉽게 설명해주는 곳이 없었다. 그런 이유로 프로그래머 입장에서 카메라 캘리브레이션에 대해 정말 간단히 설명하고자 한다.
왜곡(Distortion)
Camera Calibration은 "카메라 보정" 이란 뜻이다. 한 마디로 카메라의 "어떤 결함 "을 바르게 고친다 라는 의미이다. 여기서 "어떤 결함 "이란 바로 "왜곡 "을 나타낸다. 다시 말해, Camera Calibration은 왜곡을 제거하는 작업을 말한다
카메라 왜곡은 카메라의 내부 파라미터와 외부 파라미터에 의해 발생한다. 카메라 내부 파라미터는 렌즈와 이미지 센서와의 거리인 초점거리, 광학축이 이미지 센서와 만나는 점인 주점이며, 카메라 외부 파라미터는 영상 좌표계와 실세계 좌표계 사이에 회전, 평행 이동 정도를 나타낸다.(뭔가 하나 더 있었는데 기억이 나지 않는다.)
하지만 그냥 이런 것이 있다고만 알아두자. 책에서는 이에 관한 내용을 되게 어렵게 설명하고 있는데, 입문자에게는 괜한 혼란만 가중시킬 뿐이다. OpenCV에선 이런 개념을 모르는 사람도 쉽게 사용할 수 있도록 API를 제공해주기 때문에, 굳이 개념을 이해하려 하지 않아도 된다.
결론적으로 말하고 싶은 것은 카메라 내부, 외부 파라미터는 제조 과정, 설치 환경에 따라 다르며, 이 파라미터 값을 구하는 것으로 왜곡을 보정할 수 있다는 것이다.
내부 파라미터, 외부 파라미터
위에서 말했듯, 카메라 내부 파라미터, 외부 파라미터를 이용하여 왜곡을 보정할 수 있다. 그렇다면 카메라 내부 파라미터와, 외부 파라미터는 어떻게 구하는 걸까? 아래의 그림을 보자.
책이나 카메라 캘리브레이션 관련 글에 많이 등장하는 체스보드 판이다. 왜 갑자기 체스보드 판이 등장한 것이며, 저 선들은 도대체 무엇이고, 이게 카메라 보정과 무슨 관련이 있을까? 여기서 가장 많이 당황했던 것 같다. 내가 공부했던 책에서는 체스보드 판이 왜, 무엇 때문에 체스보드 판이 등장했는지 설명해주지 않았다. 그 의도를 알았다면 훨씬 받아들이기 수월했을 텐데 말이다.
카메라 내부, 외부 파라미터는 실세계 좌표와 영상 좌표를 대응시키는 것으로 구할 수 있다. 예를 들어, 위 그림에서의 A 점을 보자. 체스보드 판 실세계에서의 간격이 1cm라고 한다면 A 점은 5번째 줄에 1번째 점이므로 실세계에서의 좌표는 (5cm, 1cm)라고 할 수 있다. 또 영상에서 A 점의 위치를 (X, Y)라고 한다면, A 점의 실세계에서의 위치 (5cm, 1cm)와 영상에서의 위치(X, Y)를 대응시킨다는 것이다.
이것을 대응시켜 카메라 내부 파라미터, 외부 파라미터를 구하는 것은 OpenCV 함수가 해줄 것이고, 우리는 그저 실세계와 영상에서의 점들의 좌표만 준비하면 된다. 실세계에서의 좌표는, 아마 프로그램 예제에선 체스보드 블록의 간격을 나타내는 상수로 나타냈을 것이다. 그리고 영상에서의 좌표는 cvFindChessboardCorners()라는 함수로 찾을 것이다.
그러니까 체스보드가 갑자기 등장한 이유는 영상에서의 점들의 좌표를 얻기 위함이었던 것이다. 굳이, cvFeatureToTrack() 함수로 특징점을 검출하지 않는 이유는 cvFindChessboardCorners() 점을 순서대로 저장하기 때문에, 실세계 좌표와 대응시키기에 더 수월하기 때문이다.(체스보드에 점을 연결한 선은 점의 순서를 나타내는 것.)
그렇다고 굳이 체스보드 판을 준비해서 할 필요는 없다. Finger Keyboard의 종이 키보드 같은 경우, 키보드 형태도 격자무늬와 유사뿐더러, 종이 키보드 검출 과정에서 각각의 키 버튼의 코너를 검출하기 때문에 이것을 이용했다. 다시 한번 말하지만, 실세계 좌표와 영상 좌표를 대응만 시켜주면 된다. 굳이 체스보드일 필요가 없다는 것이다.
위처럼 실세계 좌표와 영상 좌표를 구하였고, 이것을 이용하여 카메라 내부, 외부 파라미터를 OpenCV를 이용하여 구할 수 있다. 카메라 내부, 외부 파라미터는 변하는 값이 아니기 때문에, 한번 보정을 실시하여 파라미터 값을 저장해두면, 이후에는 이런 작업 없이 파라미터 값을 가져다 쓸 수 있다. OpenCV에선 파일 입출력 기능도 제공하기 때문에 XML 파일 형태로 저장해두면 편리하다.
위와 같이 카메라 내부, 외부 파라미터를 XML 형태로 저장하였다.
활용
사실 요즘 카메라들이 좋아져 왜곡 정도가 크지 않다. 설령 카메라 왜곡이 존재하더라도, 보정 작업을 위한 이미지 처리시간이 길기 때문에 성능적인 면도 고려해야 한다. 결론적으로 카메라 왜곡을 제거하기 위해 카메라 캘리브레이션을 하는 것은 의미가 없다. 다만 두 대의 카메라를 이용하여 3차원 공간을 구성할 경우, 카메라 내부, 외부 파라미터가 쓰인다. 이 내용은 더 어렵기 때문에 여기서 설명하진 않겠다. 사실 나도 잘 모른다.
Finger Keyborad에서 카메라 캘리브레이션 소스 코드는 아래 Github의 FkCameraCalibrator.cpp, FkPreProcessor.h 파일에 존재한다.
'개발자 > Computer Vision' 카테고리의 다른 글
[Computer Vision] OpenCV 기하학적(geometric) 변환 정리(활용 예제 및 그림 설명 포함) (0) | 2020.12.22 |
---|---|
OpenCV Rectangle 함수 에러 해결법 rectangle typeerror: function takes exactly 4 arguments (2 given) (0) | 2020.12.22 |
KNN 알고리즘, 숫자 인식예제 까지 (0) | 2020.09.28 |
[OpenCV] Threshold 처리 (0) | 2020.08.30 |
OpenCV 이미지 연산 (0) | 2020.07.13 |