OpenCV

OpenCV는 사실상의 표준 오픈소스 컴퓨터 비전 라이브러리이며, SLAM 작업에서는 매일 손을 뻗게 되는 도구함입니다. C++로 작성되어 있고 거의 완전한 Python 바인딩(pip install opencv-python)을 제공하므로, 같은 API가 빠른 프로토타이핑과 프로덕션 프론트엔드 모두에 쓰입니다.

SLAM에 있어 가장 중요한 OpenCV의 부분들은 다음과 같습니다.

Python으로 작성한 최소한의 특징 매칭 파이프라인은 다음과 같습니다.

import cv2

orb = cv2.ORB_create(2000)
kp1, des1 = orb.detectAndCompute(img1, None)
kp2, des2 = orb.detectAndCompute(img2, None)

matcher = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = sorted(matcher.match(des1, des2), key=lambda m: m.distance)

pts1 = cv2.KeyPoint_convert(kp1, [m.queryIdx for m in matches])
pts2 = cv2.KeyPoint_convert(kp2, [m.trainIdx for m in matches])
E, inliers = cv2.findEssentialMat(pts1, pts2, K, method=cv2.RANSAC)
_, R, t, _ = cv2.recoverPose(E, pts1, pts2, K, mask=inliers)

파이프라인을 계속 진행하면: 3D 점들의 지도를 가지고 있다면, 새 프레임을 추적하는 것은 PnP 문제가 됩니다 — 그리고 이 패턴(투영, 매칭, solvePnPRansac, 정제)은 특징 기반 SLAM의 추적 스레드가 하는 일과 본질적으로 같습니다.

# pts3d: Nx3 map points, pts2d: Nx2 matched pixel observations
ok, rvec, tvec, inliers = cv2.solvePnPRansac(
    pts3d, pts2d, K, distCoeffs,
    reprojectionError=2.0, iterationsCount=100)
R, _ = cv2.Rodrigues(rvec)          # world-to-camera rotation
# triangulate new points from two calibrated views
P1 = K @ np.hstack([np.eye(3), np.zeros((3, 1))])
P2 = K @ np.hstack([R, tvec])
X_h = cv2.triangulatePoints(P1, P2, pts1.T, pts2.T)
X = (X_h[:3] / X_h[3]).T            # homogeneous -> Euclidean

한계도 알아두어야 합니다: OpenCV는 프론트엔드 빌딩 블록을 제공하지만 SLAM 백엔드는 제공하지 않습니다. 번들 조정, 포즈 그래프, 팩터 그래프는 Ceres, g2o, GTSAM에 있습니다. OpenCV의 역할은 이미지를 입력받아 대응점과 초기 자세를 출력하는 것입니다.

흔한 함정들

SLAM에서의 의미

거의 모든 오픈소스 SLAM 시스템 — ORB-SLAM, VINS-Mono, 그리고 수많은 연구용 프로토타입 — 은 이미지 처리, 특징 추출, 기하학적 솔버를 위해 OpenCV를 사용합니다. 이 라이브러리에 익숙해지면 그런 코드베이스들을 읽을 수 있고, 완전한 시각적 오도메트리 파이프라인(검출, 매칭, RANSAC, PnP)을 오후 한나절에 만들 수 있습니다 — 이것이 레벨 2에서 권장되는 실습 과제입니다.

관련 문서