스테레오 비전은 인간의 눈이 물체의 깊이를 인식하는 방식을 모방한 기술입니다. 이는 두 개의 카메라를 사용하여 3D 환경에서 깊이 정보를 추출하는 과정으로, 로봇 비전, 자율주행차, 3D 재구성 및 증강 현실에 광범위하게 사용됩니다.
1. 스테레오 비전의 기초
스테레오 비전은 두 개의 카메라가 동시에 동일한 장면을 캡처하여 깊이 정보를 생성하는 과정입니다. 각 카메라의 시점 차이 때문에 각 카메라에서 찍힌 동일한 점의 위치가 서로 다르게 보이게 됩니다. 이 두 이미지 간의 차이를 분석하여 각 점의 깊이를 추정할 수 있습니다.
1.1. 삼각측량 (Triangulation)
삼각측량은 두 카메라의 위치와 각 카메라에서 캡처된 점의 위치 정보를 기반으로 깊이를 계산하는 기본적인 방법입니다. 두 카메라의 위치와 내적 관계를 이해하는 것이 중요합니다.
2. OpenCV 설치
OpenCV를 사용하기 위해서는 먼저 OpenCV 라이브러리를 설치해야 합니다. 아래의 명령어를 사용하여 OpenCV를 설치할 수 있습니다:
pip install opencv-python opencv-python-headless
3. 스테레오 비전 시스템 구축
스테레오 비전 시스템을 구축하는 과정은 다음과 같습니다:
- 카메라 캘리브레이션 (Camera Calibration)
- 스테레오 정합 (Stereo Matching)
- 깊이 맵 생성 (Depth Map Generation)
3.1. 카메라 캘리브레이션
카메라의 내부 매개변수와 왜곡 계수를 추정하는 과정이 필수적입니다. 이를 통해 카메라의 왜곡을 보정하고, 정확한 3D 좌표를 얻을 수 있습니다. OpenCV에서는 체스판 패턴을 사용하여 카메라를 캘리브레이션하는 방법을 제공합니다.
코드 예제: 카메라 캘리브레이션
import cv2
import numpy as np
import glob
# 체스판 패턴의 크기와 내부 코너 수
chessboard_size = (7, 6) # 내부 코너 수
square_size = 1.0 # 체스보드 정사각형의 실제 크기
# 3D 포인트와 2D 포인트를 저장할 리스트
objpoints = [] # 3D 포인트
imgpoints = [] # 2D 포인트
# 3D 포인트 생성
objp = np.zeros((chessboard_size[0] * chessboard_size[1], 3), np.float32)
objp[:, :2] = np.mgrid[0:chessboard_size[0], 0:chessboard_size[1]].T.reshape(-1, 2) * square_size
# 이미지 파일 경로
images = glob.glob('path_to_your_images/*.jpg')
for fname in images:
img = cv2.imread(fname)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 체스판 찾기
ret, corners = cv2.findChessboardCorners(gray, chessboard_size, None)
if ret:
imgpoints.append(corners)
objpoints.append(objp)
# 카메라 캘리브레이션
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
print("Camera Matrix:\n", mtx)
print("Distortion Coefficients:\n", dist)
3.2. 스테레오 정합
두 개의 카메라에서 촬영한 이미지 간의 대응 관계를 찾는 과정입니다. OpenCV에서는 `StereoBM` 및 `StereoSGBM` 알고리즘을 사용하여 스테레오 이미지를 처리할 수 있습니다.
코드 예제: 스테레오 정합
# 두 개의 이미지 로드
imgL = cv2.imread('left_image.jpg', cv2.IMREAD_GRAYSCALE)
imgR = cv2.imread('right_image.jpg', cv2.IMREAD_GRAYSCALE)
# StereoSGBM 객체 생성
stereo = cv2.StereoSGBM_create(minDisparity=0,
numDisparities=16,
blockSize=5,
P1=8 * 3 * blockSize**2,
P2=32 * 3 * blockSize**2,
disp12MaxDiff=1,
uniquenessRatio=15,
speckleWindowSize=0,
speckleRange=2,
mode=cv2.STEREO_SGBM_MODE_SGBM)
# Disparity 계산
disparity = stereo.compute(imgL, imgR).astype(np.float32) / 16.0
# Disparity 맵을 시각화
plt.imshow(disparity, 'gray')
plt.show()
3.3. 깊이 맵 생성
Disparity 맵을 기반으로 깊이 정보를 추출할 수 있습니다. 깊이는 disparity 값과 카메라의 내부 매개변수를 이용하여 계산할 수 있습니다.
코드 예제: 깊이 정보 추출
# 깊이 맵 계산 (단순한 비례 계산)
focal_length = mtx[0, 0] # 카메라의 초점거리
baseline = 0.54 # 카메라 간 거리 (미터)
# 깊이 맵 계산
depth_map = (focal_length * baseline) / disparity
depth_map[disparity == 0] = 0 # Disparity가 0인 부분은 깊이 정보가 없음
# 깊이 맵 시각화
plt.imshow(depth_map, cmap='plasma')
plt.colorbar()
plt.title('Depth Map')
plt.show()
4. 결론
스테레오 비전은 3D 환경에서 깊이 정보를 추출하는 강력한 기술입니다. OpenCV를 사용하면 이 과정을 매우 효율적으로 수행할 수 있으며, 다양한 응용 분야에서 meaningful한 결과를 얻을 수 있습니다. 본 강좌에서는 기본적인 스테레오 비전 시스템 구축 방법과 OpenCV를 이용한 코드 예제를 소개하였습니다.
세부적인 매개변수와 조정을 통해 각 응용 프로그램의 요구에 맞게 성능을 개선할 수 있습니다. 향후 더 발전된 기법인 머신러닝 기반의 스테레오 비전과 결합하여 더욱 정교한 시스템을 만들을 수 있습니다.
참고 자료
이 강좌가 도움이 되었길 바라며, 질문이나 더 알고 싶은 점이 있으면 댓글을 통해 문의해 주세요!