단안 깊이 추정
단안 깊이 추정 (Monocular depth estimation)
단안 깊이 추정은 단일 이미지로부터 장면의 깊이 정보를 예측하는 컴퓨터 비전 작업입니다. 즉, 단일 카메라 시점에서 장면의 객체까지의 거리를 추정하는 과정입니다.
출처: 문서
본문
단안 깊이 추정은 3D 재구성, 증강 현실, 자율 주행, 로보틱스 등 다양한 응용 분야가 있습니다. 모델이 장면의 객체와 해당 깊이 정보 사이의 복잡한 관계를 이해해야 하므로 까다로운 작업이며, 이 관계는 조명 조건, 폐색(occlusion), 텍스처 같은 요인에 영향을 받을 수 있습니다.
두 가지 주요 깊이 추정 범주가 있습니다.
- 절대 깊이 추정(Absolute depth estimation): 이 작업 변형은 카메라로부터의 정확한 깊이 측정을 제공하는 것을 목표로 합니다. 이 용어는 미터나 피트 단위의 정밀한 측정으로 깊이를 제공하는 메트릭 깊이 추정(metric depth estimation)과 같은 의미로 사용됩니다. 절대 깊이 추정 모델은 실제 세계 거리를 나타내는 수치 값을 가진 깊이 맵을 출력합니다.
- 상대 깊이 추정(Relative depth estimation): 상대 깊이 추정은 정밀한 측정을 제공하지 않고 장면의 객체나 포인트의 깊이 순서를 예측하는 것을 목표로 합니다. 이 모델들은 A와 B 사이의 실제 거리 없이 장면의 어떤 부분이 서로에 대해 더 가깝거나 먼지 나타내는 깊이 맵을 출력합니다.
이 가이드에서는 최첨단 제로샷 상대 깊이 추정 모델인 Depth Anything V2와 절대 깊이 추정 모델인 ZoeDepth로 추론하는 방법을 살펴보겠습니다.
Depth Estimation 작업 페이지를 확인해 호환되는 모든 아키텍처와 체크포인트를 확인하세요.
시작하기 전에 최신 버전의 Transformers를 설치해야 합니다.
pip install -q -U transformers
깊이 추정 pipeline
깊이 추정을 지원하는 모델로 추론을 시도하는 가장 간단한 방법은 해당 pipeline()을 사용하는 것입니다. Hugging Face Hub의 체크포인트에서 pipeline을 만듭니다.
>>> from transformers import pipeline
from accelerate import Accelerator
>>> import torch
>>> device = Accelerator().device
>>> checkpoint = "depth-anything/Depth-Anything-V2-base-hf"
>>> pipe = pipeline("depth-estimation", model=checkpoint, device=device)
다음으로, 분석할 이미지를 선택합니다.
>>> from PIL import Image
>>> import requests
>>> url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg"
>>> image = Image.open(requests.get(url, stream=True).raw)
>>> image
이미지를 pipeline에 전달합니다.
>>> predictions = pipe(image)
pipeline은 두 개의 항목이 있는 딕셔너리를 반환합니다. 첫 번째는 predicted_depth라고 하며, 각 픽셀에 대한 깊이가 미터로 표현된 텐서입니다. 두 번째는 depth로, 깊이 추정 결과를 시각화한 PIL 이미지입니다.
시각화된 결과를 살펴보겠습니다.
>>> predictions["depth"]
손수 깊이 추정 추론
이제 깊이 추정 pipeline을 사용하는 방법을 보았으니, 같은 결과를 손수 재현하는 방법을 살펴보겠습니다.
먼저 Hugging Face Hub의 체크포인트에서 모델과 관련 프로세서를 로드합니다. 여기서는 앞과 같은 체크포인트를 사용하겠습니다.
>>> from transformers import AutoImageProcessor, AutoModelForDepthEstimation
>>> checkpoint = "Intel/zoedepth-nyu-kitti"
>>> image_processor = AutoImageProcessor.from_pretrained(checkpoint)
>>> model = AutoModelForDepthEstimation.from_pretrained(checkpoint).to(device)
리사이즈와 정규화 같은 필요한 이미지 변환을 처리해 줄 image_processor를 사용해 모델용 이미지 입력을 준비합니다.
>>> pixel_values = image_processor(image, return_tensors="pt").pixel_values.to(device)
준비된 입력을 모델에 전달합니다.
>>> import torch
>>> with torch.no_grad():
... outputs = model(pixel_values)
패딩을 제거하고 깊이 맵을 원본 이미지 크기에 맞게 리사이즈하도록 결과를 후처리하겠습니다. post_process_depth_estimation은 "predicted_depth"를 포함하는 딕셔너리 리스트를 출력합니다.
>>> # ZoeDepth dynamically pads the input image. Thus we pass the original image size as argument
>>> # to `post_process_depth_estimation` to remove the padding and resize to original dimensions.
>>> post_processed_output = image_processor.post_process_depth_estimation(
... outputs,
... source_sizes=[(image.height, image.width)],
... )
>>> predicted_depth = post_processed_output[0]["predicted_depth"]
>>> depth = (predicted_depth - predicted_depth.min()) / (predicted_depth.max() - predicted_depth.min())
>>> depth = depth.detach().cpu().numpy() * 255
>>> depth = Image.fromarray(depth.astype("uint8"))
원래 구현에서 ZoeDepth 모델은 원본 이미지와 뒤집힌 이미지 모두에서 추론을 수행하고 결과를 평균합니다. post_process_depth_estimation 함수는 뒤집힌 출력을 선택적 outputs_flipped 인자에 전달함으로써 이를 처리해 줍니다.
>>> with torch.no_grad():
... outputs = model(pixel_values)
... outputs_flipped = model(pixel_values=torch.flip(inputs.pixel_values, dims=[3]))
>>> post_processed_output = image_processor.post_process_depth_estimation(
... outputs,
... source_sizes=[(image.height, image.width)],
... outputs_flipped=outputs_flipped,
... )