오늘은 3D 맵을 만들기에 필요한 Depth Estimation(깊이 추정)에 대해 알아보려고 한다. Depth Estimation이란?
Depth Estimation은 2D 이미지에서 각 픽셀의 깊이(depth)를 추정하여 3D 정보를 복원하는 기술로,
기존에 알아본 두 대의 카메라를 사용하여 깊이 정보를 알아낸 Stereo Matching 방식과는 달리 한 대의 카메라를 사용하여 사진을 보고 깊이 정보를 알아내는 방식인 Monocular Depth Estimation에 대해 더 알아볼 예정이다. 우리가 한 눈을 감고도 지금까지의 수많은 경험을 토대로 대략 거리의 감을 잡을수 있는 것과 같은 방식이라 할수 있다. 하지만 우리가 한 눈을 감고 다닐 때 일상생활에 불편함을 느끼듯이 어째서 이러한 방식을 써야 할때가 있는지 궁금하기도 하다. 이에 대해 Stereo Matching 방식과 비교해보고 간단하게 어떤 코드를 사용하는지 알아보자.
오늘 알아보기
Depth Estimation 기법
대표적인 Depth Estimation 모델
실습 코드 및 응용 사례
Depth Estimation 기법
Stereo Matching
Stereo Matching은 두 개의 카메라(스테레오 카메라)를 사용하여 깊이 정보를 얻는 방법이다. 두 이미지 사이의 시차(disparity)를 계산하여 깊이를 추정한다.
장점 - 정확한 깊이 정보를 제공하며, 하드웨어 비용이 비교적 낮다.
단점 - 텍스처가 부족한 영역이나 반사면에서는 정확도가 떨어질 수 있다.
Monocular Depth Estimation
단일 이미지에서 깊이를 예측하는 방법으로, 딥러닝 기반 모델이 주로 사용된다. 학습된 신경망이 이미지의 구조적 특징을 분석하여 깊이를 추론한다.
장점 - 단일 카메라만으로 깊이 정보를 얻을 수 있어 하드웨어 비용이 절감된다.
단점 - 정밀도가 스테레오 방식보다 낮을 수 있으며, 데이터셋에 의존적이다.
기타 기법
LiDAR - 레이저 기반 센서를 활용하여 정확한 깊이 측정을 수행한다. 자율주행과 지도 제작에 주로 활용된다.
Time-of-Flight (ToF) - 광 신호의 왕복 시간을 측정하여 깊이를 추정하는 방식이다. ToF 카메라는 스마트폰의 얼굴 인식 및 AR 기능에 사용된다.
대표적인 Depth Estimation 모델
MiDaS
- MiDaS는 단일 이미지에서 깊이를 예측하는 모델로, 다양한 데이터셋에서 학습되었다. 다양한 장면에 대해 일반화 성능이 뛰어나며, 실시간 응용이 가능하다.
DPT (Depth Prediction Transformer)
- DPT는 Transformer 기반의 Depth Estimation 모델로, MiDaS보다 더 정교한 깊이 예측이 가능하다. 주로 고해상도 이미지에서 우수한 성능을 보인다.
NeRF (Neural Radiance Fields)
- NeRF는 여러 장의 2D 이미지를 입력으로 받아 3D 장면을 복원하는 기법이다. 신경망을 활용하여 복잡한 장면을 렌더링할 수 있다.
실습 코드 및 응용 사례
MiDaS를 활용한 Monocular Depth Estimation
다음은 MiDaS를 사용하여 단일 이미지에서 깊이를 추정하는 코드이다.
import torch
import cv2
import numpy as np
from torchvision.transforms import Compose
from midas.model_loader import load_model
# 모델 로드 함수
def load_midas_model():
model, transform = load_model("DPT_Large") # MiDaS의 DPT_Large 모델을 로드한다.
model.eval() # 모델을 추론 모드로 설정한다.
return model, transform
# Depth Estimation 수행 함수
def estimate_depth(model, transform, image_path):
image = cv2.imread(image_path) # 이미지를 로드한다.
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # OpenCV는 BGR 형식이므로 RGB로 변환한다.
image = transform(image).unsqueeze(0) # 이미지를 모델 입력 형식에 맞게 변환한다.
with torch.no_grad(): # 그래디언트 계산을 비활성화하여 성능을 최적화한다.
depth = model(image) # 깊이 맵을 추정한다.
depth = depth.squeeze().cpu().numpy() # 결과를 numpy 배열로 변환한다.
return depth
# 모델을 로드하고 샘플 이미지의 깊이 맵을 예측한다.
model, transform = load_midas_model()
depth_map = estimate_depth(model, transform, "sample_image.jpg")
# 결과를 정규화하고 시각화한다.
depth_map = (depth_map - depth_map.min()) / (depth_map.max() - depth_map.min()) # 정규화
cv2.imshow("Depth Map", depth_map)
cv2.waitKey(0)
cv2.destroyAllWindows()
이 코드는 MiDaS의 DPT_Large 모델을 이용하여 단일 이미지의 깊이를 예측하는 과정으로, OpenCV를 통해 시각화할 수 있다.
Unreal Engine과 Depth Estimation 연계
Unreal Engine에서는 Scene Capture Component를 이용하여 Depth 정보를 추출할 수 있다. 이 데이터를 활용하여 3D 재구성 및 AR/VR 애플리케이션을 개발할 수 있다.
ROS 기반 Depth Estimation 활용
로봇 운영 체제(ROS)에서 RGB-D 카메라와 결합하여 SLAM(Simultaneous Localization and Mapping)에 적용할 수 있다. 이를 통해 실시간으로 환경을 3D로 매핑하는 것이 가능하다.