Datasets documentation
깊이 추정
깊이 추정
Depth estimation datasets는 이미지 내 모든 픽셀의 카메라로부터의 상대적 거리, 즉 깊이(depth)를 근사하도록 모델을 학습하는 데 사용됩니다. 이러한 데이터셋이 가능하게 하는 응용 분야는 주로 시각적 기계 인식(visual machine perception) 및 로봇공학에서의 인식(perception) 영역에 있습니다. 응용 사례로는 자율주행 차량을 위한 도로 매핑이 있습니다. 이 가이드에서는 depth estimation dataset에 변환(transformations)을 적용하는 방법을 보여 드립니다.
시작하기 전에 albumentations의 최신 버전이 설치되어 있는지 확인하세요:
pip install -U albumentations
Albumentations는 컴퓨터 비전을 위한 데이터 증강을 수행하는 Python 라이브러리입니다. 이미지 분류, 객체 감지, 분할, 키포인트 추정과 같은 다양한 컴퓨터 비전 작업을 지원합니다.
이 가이드는 다양한 실내 장면에서 RGB 카메라와 깊이 카메라로 촬영된 비디오 시퀀스로 구성된 NYU Depth V2 데이터셋을 사용합니다. 이 데이터셋은 3개 도시의 장면으로 이루어져 있으며, 이미지와 함께 해당 이미지의 깊이 맵을 레이블로 제공합니다.
데이터셋의 train 분할을 로드하고 예시를 확인해 보세요:
>>> from datasets import load_dataset
>>> train_dataset = load_dataset("sayakpaul/nyu_depth_v2", split="train")
>>> index = 17
>>> example = train_dataset[index]
>>> example
{'image': <PIL.PngImagePlugin.PngImageFile image mode=RGB size=640x480>,
'depth_map': <PIL.TiffImagePlugin.TiffImageFile image mode=F size=640x480>}데이터셋에는 두 개의 필드가 있습니다:
image:uint8데이터 유형을 가진 PIL PNG 이미지 객체.depth_map:float32데이터 유형을 가진 PIL Tiff 이미지 객체로, 이미지의 깊이 맵입니다.
여기서 깊이 맵은 float32 데이터를 포함하는 다양한 데이터 타입을 지원하기 때문에 TIFF 형식을 사용합니다.
다만 JPEG/PNG 형식은 uint8 또는 uint16 데이터만 저장할 수 있다는 점을 언급할 가치가 있습니다.
따라서 JPEG/PNG로 저장된 깊이 맵이 있는 경우, Image(mode="F") 타입을 사용하여 일반 깊이 맵처럼 단일 채널 float32로 로드하세요:
>>> from datasets import Image
>>> train_dataset = train_dataset.cast_column("depth_map", Image(mode="F"))다음으로, 다음 명령어로 이미지를 확인해 보세요:
>>> example["image"]
깊이 맵을 보기 전에, PIL은 float32 이미지를 표시할 수 없으므로 .convert('RGB')를 사용하여 데이터 유형을 uint8로 변환해야 합니다. 이제 해당 깊이 맵을 확인해 보세요:
>>> example["depth_map"].convert("RGB")
모두 검은색입니다! 깊이 맵을 올바르게 시각화하려면 색을 추가해야 합니다. 이를 위해 plt.imshow()를 사용하여 표시할 때 자동으로 색을 적용하거나, plt.cm를 사용하여 색이 있는 깊이 맵을 만든 후 표시할 수 있습니다. 이 예제에서는 후자를 사용했는데, 나중에 색이 있는 깊이 맵을 저장/쓰기할 수 있기 때문입니다. (아래 유틸리티는 FastDepth 저장소에서 가져왔습니다).
>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>> cmap = plt.cm.viridis
>>> def colored_depthmap(depth, d_min=None, d_max=None):
... if d_min is None:
... d_min = np.min(depth)
... if d_max is None:
... d_max = np.max(depth)
... depth_relative = (depth - d_min) / (d_max - d_min)
... return 255 * cmap(depth_relative)[:,:,:3]
>>> def show_depthmap(depth_map):
... if not isinstance(depth_map, np.ndarray):
... depth_map = np.array(depth_map)
... if depth_map.ndim == 3:
... depth_map = depth_map.squeeze()
... d_min = np.min(depth_map)
... d_max = np.max(depth_map)
... depth_map = colored_depthmap(depth_map, d_min, d_max)
... plt.imshow(depth_map.astype("uint8"))
... plt.axis("off")
... plt.show()
>>> show_depthmap(example["depth_map"])
여러 개의 서로 다른 이미지와 해당 깊이 맵을 시각화할 수도 있습니다.
>>> def merge_into_row(input_image, depth_target):
... if not isinstance(input_image, np.ndarray):
... input_image = np.array(input_image)
...
... d_min = np.min(depth_target)
... d_max = np.max(depth_target)
... depth_target_col = colored_depthmap(depth_target, d_min, d_max)
... img_merge = np.hstack([input_image, depth_target_col])
...
... return img_merge
>>> random_indices = np.random.choice(len(train_dataset), 9).tolist()
>>> plt.figure(figsize=(15, 6))
>>> for i, idx in enumerate(random_indices):
... example = train_dataset[idx]
... ax = plt.subplot(3, 3, i + 1)
... image_viz = merge_into_row(
... example["image"], example["depth_map"]
... )
... plt.imshow(image_viz.astype("uint8"))
... plt.axis("off")
albumentations를 사용하여 몇 가지 증강을 적용합니다. 증강 변환에는 다음이 포함됩니다:
- 무작위 수평 플리핑
- 무작위 크롭
- 무작위 밝기 및 대비
- 무작위 감마 보정
- 무작위 색조 채도
>>> import albumentations as A
>>> crop_size = (448, 576)
>>> transforms = [
... A.HorizontalFlip(p=0.5),
... A.RandomCrop(crop_size[0], crop_size[1]),
... A.RandomBrightnessContrast(),
... A.RandomGamma(),
... A.HueSaturationValue()
... ]추가로, 대상 키 이름을 더 잘 반영할 수 있도록 매핑을 정의합니다.
>>> additional_targets = {"depth": "mask"}
>>> aug = A.Compose(transforms=transforms, additional_targets=additional_targets)additional_targets가 정의된 경우, mask 대신 aug의 depth 인자에 대상 깊이 맵을 전달할 수 있습니다. 아래에 정의된 apply_transforms() 함수에서 이 변경 사항을 확인할 수 있습니다.
이미지와 깊이 맵에 변환을 적용하는 함수를 생성합니다:
>>> def apply_transforms(examples):
... transformed_images, transformed_maps = [], []
... for image, depth_map in zip(examples["image"], examples["depth_map"]):
... image, depth_map = np.array(image), np.array(depth_map)
... transformed = aug(image=image, depth=depth_map)
... transformed_images.append(transformed["image"])
... transformed_maps.append(transformed["depth"])
...
... examples["pixel_values"] = transformed_images
... examples["labels"] = transformed_maps
... return examplesset_transform() 함수를 사용하여 데이터셋의 배치에 변환을 온더플라이로 적용하여 디스크 공간을 덜 사용하도록 할 수 있습니다:
>>> train_dataset.set_transform(apply_transforms)pixel_values와 labels에 인덱싱하여 예시 이미지의 변환이 제대로 수행되었는지 확인할 수 있습니다:
>>> example = train_dataset[index]
>>> plt.imshow(example["pixel_values"])
>>> plt.axis("off")
>>> plt.show()
이미지의 대응하는 깊이 맵에 동일한 변환을 시각화합니다:
>>> show_depthmap(example["labels"])
이전 random_indices를 재사용하여 여러 학습 샘플을 시각화할 수도 있습니다:
>>> plt.figure(figsize=(15, 6))
>>> for i, idx in enumerate(random_indices):
... ax = plt.subplot(3, 3, i + 1)
... example = train_dataset[idx]
... image_viz = merge_into_row(
... example["pixel_values"], example["labels"]
... )
... plt.imshow(image_viz.astype("uint8"))
... plt.axis("off")