5.22. 렌즈 및 원근 보정

두 가지 종류의 기하 보정은 사각형 대 사각형 매핑으로는 불가능한 방식으로 이미지를 워핑합니다. 렌즈 보정(lens correction) 은 실제 광각 렌즈가 만들어내는 방사형 왜곡을 되돌립니다. 즉 프레임의 모서리 부근에서 장면의 직선을 눈에 띄는 곡선으로 휘게 만드는 어안(fisheye) 팽창을 보정합니다. 원근 보정(perspective correction) 은 렌즈가 장면에 수직으로 향하지 않을 때 발생하는 키스톤 효과를 되돌립니다. 즉 현실 세계의 알려진 사각형을 이미지에서 비(非)사각형 블롭으로 바꾸어 버리는 사다리꼴 워핑을 보정합니다. 두 보정 모두 촬영이 끝난 후에, 광학적 원인에서 비롯된 효과를 되돌립니다.

5.22.1. 방사형 렌즈 왜곡

실제 렌즈 효과 자료에서는 저렴한 광각 렌즈가 만들어내는 배럴(barrel) 왜곡을 설명합니다. 프레임 중앙 부근의 픽셀은 핀홀 모델이 예측하는 위치와 대체로 일치하지만, 가장자리 부근의 픽셀은 광축으로부터의 방사 거리의 제곱에 비례하여 커지는 양만큼 바깥쪽으로 휘어집니다. 프레임 가장자리 근처를 지나는 장면 속의 직선은 촬영된 이미지에서 눈에 띄게 곡선을 이루며, 직선이 직선으로 유지된다고 가정하는 고전적인 머신 비전 알고리즘 – AprilTag 코너 검출, 에지 추종, 라인 추종 내비게이션 – 은 모두 모서리 부근에서 잘못된 결과를 냅니다.

lens_corr() 은 이 왜곡을 되돌립니다. 이 메서드는 역 매핑을 수행합니다. 모든 출력 픽셀은 렌즈가 그 위치로부터 바깥쪽으로 휘게 만들었을 입력의 위치에서 샘플링되며, 그 결과는 기하학적으로 곧은 이미지가 됩니다.

img.lens_corr(strength=1.8)

strength 매개변수는 이 보정의 핵심입니다. 이는 렌즈가 얼마나 강하게 휘는지를 나타내는 단일 숫자입니다. 1.0 에 가까운 값은 적당히 넓은 렌즈에 대한 약한 보정이며, 약 2.0 까지의 값은 강한 어안 렌즈에 적당합니다. 기본값 1.8 은 기본 제공되는 OpenMV Cam 렌즈에 대한 합리적인 시작점입니다. 특정 렌즈에 맞는 올바른 값은 몇 가지를 시도해 보고 이미지를 관찰하면서 찾는 문제입니다.

두 개의 보조 매개변수는 보통 기본값 그대로 두어도 괜찮습니다. zoom (기본값 1.0)은 출력을 스케일링합니다. 1보다 큰 값은 렌즈 보정이 모서리를 더 바깥쪽으로 밀어내는 방식을 보상하기 위해 바깥쪽으로 크롭하며, 더 작은 값은 이미지 가장자리에 빈 픽셀을 포함하는 대신 보정된 장면을 더 많이 보이도록 남겨둡니다. x_corry_corr 은 보정의 중심을 이미지의 기하 중심에서 이동시키는데, 이는 렌즈가 센서 위에 광학적으로 중심이 맞지 않은 경우(드문 경우지만 알아둘 만한 가치가 있습니다)에 유용합니다.

전형적인 파이프라인은 다음과 같습니다. 캡처한 다음, lens_corr() 을 한 번 실행하여 기하 구조를 곧게 펴고, 그 결과를 가지고 애플리케이션이 실제로 수행하는 작업을 실행합니다.

5.22.2. 3D 회전 보정

또 다른 종류의 기하 왜곡은 센서 평면이 장면 평면과 평행하지 않을 때 발생하는 원근 워핑입니다. 고전적인 사례는 아래에서 올려다본 표지판이나 자동차 번호판입니다. 표지판의 윗부분은 아랫부분보다 렌즈에서 더 멀리 떨어져 있으므로 더 작게 투영되고, 촬영된 이미지에는 윗변이 아랫변보다 짧은 사다리꼴로 사각형이 나타납니다.

해결책은 캡처된 프레임에 3D 회전 을 적용하여 센서 평면이 장면 평면과 평행하도록 가상으로 재정렬하는 것입니다. 그 수학은 AprilTag 검출이 태그의 네 모서리로부터 태그의 자세(pose)를 복원하는 데 사용하는 것과 동일한 원근 매핑을 거꾸로 실행한 것입니다. 즉 회전이 주어지면, 이 연산은 모든 출력 픽셀을 그 회전이 비롯되었을 입력 위치로 다시 매핑합니다.

rotation_corr() 은 그 보정을 수행합니다:

img.rotation_corr(x_rotation=10.0, y_rotation=0.0, z_rotation=0.0)

세 개의 회전 매개변수는 도(degree) 단위이며, 이미지를 중심으로 한 가상 카메라의 x, y, z 축을 기준으로 한 회전을 나타냅니다. x_rotation 은 카메라를 위 또는 아래로 기울입니다(지면 높이에서 벽을 찍은 사진에 대한 자연스러운 보정). y_rotation 은 카메라를 좌우로 패닝합니다. z_rotation 은 카메라를 광축을 중심으로 회전시킵니다(수평이 맞지 않은 마운트에 대한 자연스러운 보정).

x_translationy_translation 은 회전 없이 가상 카메라를 측면으로 이동시킵니다. zoom (기본값 1.0)은 출력을 스케일링합니다. fov (기본값 60.0)는 투영을 계산하는 데 사용되는 카메라의 수직 시야각을 나타냅니다. 기하 구조의 일관성을 유지하려면 이 값이 실제 렌즈와 일치해야 합니다.

임의의 기울기와 패닝 조합의 경우, 0이 아닌 여러 회전이 한 번의 호출에서 합성됩니다. 연산 순서는 구현 내부에 고정되어 있습니다. 애플리케이션은 각도만 제공하면 결과가 나옵니다.

5.22.3. 알려진 사각형 정류(rectifying)

rotation_corr() 의 가장 흔하게 유용한 형태는 corners= 키워드입니다. 이는 입력 이미지에서 알려진 사각형의 모서리를 나타내는 네 개의 (x, y) 튜플 리스트를 받습니다. 이 메서드는 참 사각형을 그 특정한 네 점으로 매핑했을 3D 회전을 계산하고, 그 회전의 역(inverse) 을 이미지 전체에 적용하여, 알려진 사각형이 다시 직사각형이 된 결과를 반환합니다:

plate_corners = [(45, 80), (300, 60), (310, 180), (40, 200)]
img.rotation_corr(corners=plate_corners)

고전적인 용도는 정확히 이름이 시사하는 그대로입니다. 비스듬한 각도에서 촬영한 자동차 번호판(또는 다른 임의의 사각형 특징)입니다. 상류 단계가 번호판을 검출하여 캡처된 이미지에서 네 모서리 위치를 보고하고, 그 모서리들을 rotation_corr() 에 전달하면 번호판이 참 직사각형으로 자리 잡은 이미지가 생성되어, 다음에 올 문자 인식이나 템플릿 매칭 단계에 바로 사용할 수 있습니다.

네 모서리 형태가 애플리케이션이 해결하려는 문제를 해결할 때, 이는 여섯 매개변수 형태보다 훨씬 더 유용합니다. 애플리케이션은 어떤 회전 각도도 추정할 필요가 없습니다. 메서드에 네 점만 넘겨주면 나머지는 메서드가 알아서 처리합니다. 여섯 매개변수 형태는 장면에서 식별 가능한 사각형이 보이지 않고 외부 지식(예를 들어 보정된 마운팅 각도)으로부터 회전을 수동으로 조정해야 할 때 유용합니다.