-
[OpenCV] Camera CalibrationImage Geometry 2018. 2. 1. 18:56
카메라 캘리브레이션
목표
카메라의 왜곡, 카메라의 내부 매개변수, 외부 매개변수등을 배움
이러한 매개변수를 찾는 방법을 배우고, 영상 왜곡제거등을 배움
기본원리
값이 저렴한 핀홀 카메라들은 많은 영상 왜곡(distortion)을 가지고 있으며, 방사왜곡(radial distortion)과 접선왜곡(tangential distortion) 두 가지가 주된 왜곡의 종류입니다.
방사왜곡으로 인해 직선이 곡선으로 보이게 되고, 중심에서 멀어질수록 영향을 더 많이 받게됩니다. 예를들어, 아래의 이미지에서, 체스보드의 두 개의 에지는 빨간색 선으로 그려집니다. 하지만 체스보드의 경계부가 직선이 아니며, 빨간색 직선과 일치하지 않는것을 확인할 수 있습니다. 모든 직선들이 볼록해져 있습니다. 더 상세한 내용은 Distortion (optics)를 방문하시면 됩니다.
이 왜곡은 아래의 식으로 표현됩니다.
유사하게, 다른 왜곡인 접선왜곡은 렌즈가 이미지평면에 완벽하게 평행하게 정렬되지 않아서 발생합니다. 따라서 이미지의 일부영역이 실제보다 가깝게 보여질 수 있습니다. 이 왜곡은 아래의 식으로 표현됩니다.
요약하자면, 아래처럼 왜곡계수(distortion coefficients)로 알려져 있는 다섯개의 매개변수를 찾아야 합니다.
그리고 왜곡계수와 함께 카메라의 내부 매개변수(intrinsic parameter)와 외부 매개변수(extrinsic parameter)와 같은 정보를 더 찾아야 합니다. 내부 매개변수는 카메라에 특정지어 지며, 초점거리(focal length) fx, fy, 광학중심(optical centers) cx, cy등의 정보를 포함합니다. 또한 카메라 행렬로 불리며, 카메라에만 의존적이기 때문에 한 번 계산되면 다음절차를 위해 저장될 수 있습니다. 카메라행렬은 아래와 같이 3 x 3 행렬로 표현됩니다.
외부 매개변수는 3D 지점의 좌표(coordinates)를 좌표계(coordinate system)로 변환하는 회전과 이동벡터에 대응합니다.
스테레오 응용프로그램은 이러한 왜곡을 먼저 설정해야 합니다. 모든 매개변수를 찾기위해, 패턴(예를들면, 체스보드)을 가지는 잘 정의된 샘플 영상이 필요합니다. 샘플에서 특정한 지점(체스보드 정사각형의 모서리)을 찾습니다. 실세계 공간(world space)에서 모서리의 좌표를 알고 있고, 영상에서 모서리의 좌표를 알고 있습니다. 이 데이터와 함께 백그라운드에서 몇가지 수학적인 문제를 해결하여 왜곡계수를 얻을 수 있습니다. 이것이 전체 캘리브레이션 과정의 요약이며, 최소한 10개의 테스트 패턴이 필요합니다.
코드
카메라 캘리브레이션을 위해 적어도 10개의 테스트 패턴이 필요합니다. OpenCV는 몇 종류의 체스보드 영상(samples/cpp/left01.jpg -- left14.jpg)을 제공하므로, 그것을 활용할 것입니다. 이해를 위해 체스보드의 단 하나의 영상만을 고려하시기 바랍니다. 카메라 캘리브레이션을 위해 필요한 중요한 입력데이터는 3D 실세계 지점의 집합과 그것에 대응하는 2D 영상 지점입니다. 2D 영상 저점은 영상에서 쉽게 찾을 수 있습니다.(영상에서 이 지점는 두개의 검정색 정사각형이 닿는 위치에 존재합니다.)
실세계 공간에서 3D 위치는 어떨까요? 이 이미지는 고정형 카메라로부터 얻어지고, 체스보드는 다른 위치와 방향에 위치하게 됩니다. 따라서 X, Y, Z 값을 알아야 합니다. 그러나 단순하게, 체스보드는 XY평면에 고정되어(항상 Z=0이 됨) 있는것으로 볼 수 있고, 카메라는 그것에 따라 움직였다고 할 수 있다. 이러한 고려는 X, Y값만 찾도록 도와주게 됩니다.
이제 X, Y값에 대해, 우리는 단순하게 점의 위치를 정의하는 (0, 0), (1, 0), (2, 0) ... 로 점을 전달할 수 있다.
이 경우, 우리가 얻은 결과는 체스 보드 정사각형의 크기의 스케일이 된다.
그러나 우리가 정사각형의 크기를 안다면(예를들어 30mm라 하면), 우리는 (0, 0), (30, 0), (60, 0), ..., 을 전달할 수 있고, 결과를 mm단위로 얻을 수 있게된다. (이 경우, 그러한 이미지들을 촬여하지 않았기 때문에 우리는 정사각형의 크기를 모른다. 따라서 우리는 정사각형의 사이즈의 항을 전달한다)
3D 포인트들은 object points로 불리며, 2D 이미지 포인트들은 image points로 불린다.
설정
체스보드에서 패턴을 찾기위해cv2.findChessboardCorners() 함수를 사용한다. 어떤 종류의 패턴을 사용하는지 전달할 필요가 있다. 8 x 8 인지 5 x 5 인지 다른 종류의 패턴인지등..이 예제는 7 x 6 격자를 사용한다. (일반적으로 체스보드는 8 x 8 정사각형과 7 x 7 내부 모서리를 가진다). 이 함수는 패턴이 얻어져서 True이면 모서리 지점과 retval을 반환한다.
이러한 모서리는 순차적으로 위치한다.(좌에서 우로, 상에서 하로)
see also: 이 함수는 영상에서 모든 패턴을 찾지 못할 수 있습니다. 하나의 좋은 옵션은 코드를 작성하고, 카메라를 작동하여 필요한 패턴에 대해 각 프레임을 체크하는 것입니다. 패턴이 얻어지면 모서리를 찾고 그것을 목록에 저장하세요.
또한 일정한 간격을 제공하여 다음 프레임을 읽어들이기전에 체스보드를 다른 방향으로 조정할 수 있습니다. 이 절차를 필요한 수만큼의 좋은 패턴이 얻어질 때까지 계속 진행합니다. 심지어 여기에 제공되는 예제에서도, 14개의 영상이 좋은지, 얼마가 좋은것인지 알 수 없다. 그래서 우리는 모든 이미지를 읽어들이고 그 중에서 좋은 것을 획득합니다.
see also: 체스보드 대신, 우리는 원형 격자를 사용하여 패턴을 찾기위해 cv2.findCirclesGrid() 를 사용할 수 있습니다. 원형 격자를 사용하면 더 적은 수의 이미지로 충분한 것이 알려져 있습니다.
모서리를 찾았다면, 그 정확도를 cv2.cornerSubPix() 함수를 사용하여 올릴 수 있습니다. 그리고 cv2.drawChessboardCorners() 함수를 사용하여 패턴을 그릴 수 있습니다. 이러한 절차는 아래의 코드에 포함됩니다.
패턴을 포함하는 영상은 아래와 같이 그려집니다.
캘리브레이션
이제 우리는 object points와 image points를 가지고 있으며 캘리브레이션을 수행할 준비가 되었고, cv2.calibrateCamera() 함수를 사용합니다. 이 함수는 카메라 행렬, 왜곡 계수, 회전과 이동벡터등을 반환합니다.
왜곡제거
캘리브레이션을 통해 획득한 매개변수를 가지고 있으므로, 이미지를 획득하여 왜곡을 제거할 수 있습니다. OpenCV는 두 가지 방법을 제공하며 두 가지를 모두 살펴볼 것입니다. 그 전에, 우리는 cv2.getOptimalNewCameraMatrix() 함수를 사용하여 자유 스케일링 매개변수에 기반하여 카메라행렬을 구체화(수정, 개선)할 수 있습니다. 만약에 스케일 매개변수 alpha=0 이면, 함수는 최소한의 불필요한 픽셀을 가지는 왜곡해제된 이미지를 리턴합니다. 그래서 그것은 이미지 코너에서 몇몇픽셀들을 제거할 수 있다.
만약 alpha=1이면, 모든 픽셀들은 몇몇 검정색 extra 이미지와함게 유지된다. 또한 결과를 크롭하는데 사용될 수 있는 ROI를 리턴한다. 그래서 우리는 새로운 이미지를 얻는다(이 경우 left12.jpg . 그것은 이 챕터의 첫번째 이미지 입니다.)
1. cv2.undistort() 사용예
이것은 최단 경로입니다. 함수를 호출하고 위에서 얻어진 ROI를 사용하여 결과를 크롭합니다.
2. remapping 사용예
이것은 곡션경로입니다. 먼저 왜곡된 이미지에서 비왜곡된 이미지로의 맵핑함수를 찾습니다. 그 후 remap 함수를 사용합니다.
두 방법은 동일한 결과를 만들어냅니다. 아래의 결과를 보세요.
결과영상에서 모든 에지가 직선인것을 볼 수 있습니다. 이제 향후의 사용을 위해 Numpy 쓰기 함수(np.savez, np.savetxt 등)를 사용하여 카메라 행렬과 왜곡 계수를 저장할 수 있습니다.
재투영 에러
재투영 에러는 발견된 매개변수가 얼마나 정확한지에 대한 좋은 추정을 제공합니다. 이것은 가능한 0에 가까워야 합니다. 내부, 왜곡, 회전과 이동행렬이 주어지면, 우리는 먼저 cv2.projectPoints() 함수를 사용하여 object point를 image point로 변환합니다. 그 후에 모서리 검출 알고리즘과 변환을 통해 얻은 것 사이의 절대 norm 을 계산합니다. 평균 에러를 찾기위해 우리는 모든 캘리브레이션 이미지에 대해 에러의 산술 평균을 계산합니다.
REFERENCE