git clone --recursive https://github.com/naver/dust3r
cd dust3r
# 이미 dust3r를 클론한 경우:
# git submodule update --init --recursive
conda create -n dust3r python=3.11 cmake=3.14.0
conda activate dust3r
conda install pytorch torchvision pytorch-cuda=12.1 -c pytorch -c nvidia # 시스템에 맞는 cuda 버전을 사용하세요.
pip install -r requirements.txt
# 선택사항: 추가 패키지를 설치하여:
# - HEIC 이미지 지원 추가
# - 일부 데이터셋 전처리에서 깊이 맵을 렌더링하는 데 사용되는 pyrender 추가
# - visloc.py에 필요한 패키지 추가
pip install -r requirements_optional.txt
# DUST3R는 RoPE 위치 임베딩을 사용하며, 이를 위해 CUDA 커널을 컴파일하여 실행 시간을 단축할 수 있습니다.
cd croco/models/curope/
python setup.py build_ext --inplace
cd ../../../
모델명 | 훈련 해상도 | 헤드 | 인코더 | 디코더 |
---|---|---|---|---|
DUSt3R_ViTLarge_BaseDecoder_224_linear.pth | 224x224 | Linear | ViT-L | ViT-B |
DUSt3R_ViTLarge_BaseDecoder_512_linear.pth | 512x384, 512x336, 512x288, 512x256, 512x160 | Linear | ViT-L | ViT-B |
DUSt3R_ViTLarge_BaseDecoder_512_dpt.pth | 512x384, 512x336, 512x288, 512x256, 512x160 | DPT | ViT-L | ViT-B |
이 모델들을 훈련할 때 사용한 하이퍼파라미터는 'Our Hyperparameters' 섹션에서 확인할 수 있습니다.
특정 모델을 다운로드하려면, 예를 들어 DUSt3R_ViTLarge_BaseDecoder_512_dpt.pth
:
mkdir -p checkpoints/
wget https://download.europe.naverlabs.com/ComputerVision/DUSt3R/DUSt3R_ViTLarge_BaseDecoder_512_dpt.pth -P checkpoints/
참고:
mode=GlobalAlignerMode.PairViewer
).python3 demo.py --model_name DUSt3R_ViTLarge_BaseDecoder_512_dpt
# --weights를 사용하여 로컬 파일에서 체크포인트를 로드하세요, 예: --weights checkpoints/DUSt3R_ViTLarge_BaseDecoder_512_dpt.pth
# --image_size를 사용하여 선택한 체크포인트에 맞는 해상도를 선택하세요. 512 (기본값) 또는 224
# --local_network를 사용하여 로컬 네트워크에서 접근 가능하게 만들거나, --server_name을 사용하여 URL을 수동으로 지정하세요.
# --server_port를 사용하여 포트를 변경하세요, 기본적으로 7860부터 사용 가능한 포트를 검색합니다.
# --device를 사용하여 다른 장치를 사용하세요, 기본값은 "cuda"입니다.
./docker
디렉토리로 이동하여 다음 명령을 실행하세요:cd docker
bash run.sh --with-cuda --model_name="DUSt3R_ViTLarge_BaseDecoder_512_dpt"
cd docker
bash run.sh --model_name="DUSt3R_ViTLarge_BaseDecoder_512_dpt"
기본적으로 demo.py
는 --local_network
옵션과 함께 실행됩니다.
웹 UI에 접근하려면 http://localhost:7860/로 이동하세요 (또는 네트워크에서 접근하려면 localhost를 머신 이름으로 변경하세요).
run.sh
는 docker-compose-cuda.yml
또는 docker-compose-cpu.yml
설정 파일을 사용하여 docker-compose를 실행한 다음, entrypoint.sh
를 사용하여 데모를 시작합니다.
from dust3r.inference import inference
from dust3r.model import AsymmetricCroCo3DStereo
from dust3r.utils.image import load_images
from dust3r.image_pairs import make_pairs
from dust3r.cloud_opt import global_aligner, GlobalAlignerMode
if __name__ == '__main__':
device = 'cuda'
batch_size = 1
schedule = 'cosine'
lr = 0.01
niter = 300
model_name = "naver/DUSt3R_ViTLarge_BaseDecoder_512_dpt"
# 필요한 경우 로컬 체크포인트 경로를 model_name에 지정할 수 있습니다.
model = AsymmetricCroCo3DStereo.from_pretrained(model_name).to(device)
# load_images는 이미지 목록 또는 디렉토리를 받을 수 있습니다.
images = load_images(['croco/assets/Chateau1.png', 'croco/assets/Chateau2.png'], size=512)
pairs = make_pairs(images, scene_graph='complete', prefilter=None, symmetrize=True)
output = inference(pairs, model, device, batch_size=batch_size)
# 이 단계에서, raw dust3r 예측을 가지고 있습니다.
view1, pred1 = output['view1'], output['pred1']
view2, pred2 = output['view2'], output['pred2']
# 여기서 view1, pred1, view2, pred2는 길이가 2인 리스트의 딕셔너리입니다.
# -> 대칭화를 하기 때문에 (im1, im2)와 (im2, im1) 쌍을 가지고 있습니다.
# 각 view에는 다음이 포함됩니다:
# 정수 이미지 식별자: view1['idx']와 view2['idx']
# 이미지: view1['img']와 view2['img']
# 이미지 크기: view1['true_shape']와 view2['true_shape']
# 데이터 로더에 의해 출력된 인스턴스 문자열: view1['instance']와 view2['instance']
# pred1과 pred2는 신뢰도 값을 포함합니다: pred1['conf']와 pred2['conf']
# pred1은 view1['img'] 공간에서 view1['img']의 3D 포인트를 포함합니다: pred1['pts3d']
# pred2는 view2['img'] 공간에서 view1['img']의 3D 포인트를 포함합니다: pred2['pts3d_in_other_view']
# 다음으로 global_aligner를 사용하여 예측을 정렬합니다.
# 작업에 따라 raw 출력을 그대로 사용해도 될 수 있습니다.
# 입력 이미지가 두 개뿐인 경우, GlobalAlignerMode.PairViewer를 사용할 수 있습니다: 출력만 변환됩니다.
# GlobalAlignerMode.PairViewer를 사용하는 경우, compute_global_alignment를 실행할 필요가 없습니다.
scene = global_aligner(output, device=device, mode=GlobalAlignerMode.PointCloudOptimizer)
loss = scene.compute_global_alignment(init="mst", niter=niter, schedule=schedule, lr=lr)
# scene에서 유용한 값을 가져옵니다:
imgs = scene.imgs
focals = scene.get_focals()
poses = scene.get_im_poses()
pts3d = scene.get_pts3d()
confidence_masks
= scene.get_masks()
# 재구성 시각화
scene.show()
# 두 이미지 간의 2D-2D 매칭 찾기
from dust3r.utils.geometry import find_reciprocal_matches, xy_grid
pts2d_list, pts3d_list = [], []
for i in range(2):
conf_i = confidence_masks[i].cpu().numpy()
pts2d_list.append(xy_grid(*imgs[i].shape[:2][::-1])[conf_i]) # imgs[i].shape[:2] = (H, W)
pts3d_list.append(pts3d[i].detach().cpu().numpy()[conf_i])
reciprocal_in_P2, nn2_in_P1, num_matches = find_reciprocal_matches(*pts3d_list)
print(f'found {num_matches} matches')
matches_im1 = pts2d_list[1][reciprocal_in_P2]
matches_im0 = pts2d_list[0][nn2_in_P1][reciprocal_in_P2]
# 몇 가지 매칭을 시각화합니다.
import numpy as np
from matplotlib import pyplot as pl
n_viz = 10
match_idx_to_viz = np.round(np.linspace(0, num_matches-1, n_viz)).astype(int)
viz_matches_im0, viz_matches_im1 = matches_im0[match_idx_to_viz], matches_im1[match_idx_to_viz]
H0, W0, H1, W1 = *imgs[0].shape[:2], *imgs[1].shape[:2]
img0 = np.pad(imgs[0], ((0, max(H1 - H0, 0)), (0, 0), (0, 0)), 'constant', constant_values=0)
img1 = np.pad(imgs[1], ((0, max(H0 - H1, 0)), (0, 0), (0, 0)), 'constant', constant_values=0)
img = np.concatenate((img0, img1), axis=1)
pl.figure()
pl.imshow(img)
cmap = pl.get_cmap('jet')
for i in range(n_viz):
(x0, y0), (x1, y1) = viz_matches_im0[i].T, viz_matches_im1[i].T
pl.plot([x0, x1 + W0], [y0, y1], '-+', color=cmap(i / (n_viz - 1)), scalex=False, scaley=False)
pl.show(block=True)
device
에 맞게 설정합니다.이미지 쌍에서 특징을 추출
두 이미지의 특징 벡터를 가져옴
global_aligner
를 사용하여 예측 결과를 정렬GlobalAlignerMode.PairViewer
모드를 사용하면 두 이미지 간의 매칭 결과만 변환하고, 정렬을 건너뜁니다.scene.show()
를 통해 3D 포인트와 이미지를 확인할 수 있음find_reciprocal_matches
함수를 사용하여 두 이미지 간의 2D-2D 특징 매칭을 수행kapture_import_7scenes.py
스크립트를 사용하여 각 시퀀스를 kapture 모델로 변환할 수 있습니다.1) Microsoft 웹사이트에서 7-scenes를 다운로드하세요.
cd /<mydatasets>/7-scenes
curl http://download.microsoft.com/download/2/8/5/28564B23-0828-408F-8631-23B1EFF1DAC8/heads.zip -o heads.zip
2) 모든 파일을 압축 해제하세요.
unzip heads.zip
cd heads
# 모든 내부 zip 파일을 압축 해제
find . -iname "*.zip" -print0 | xargs -n1 -0 -I {} unzip {}
rm *.zip ../heads.zip # 모든 zip 파일을 삭제 (선택 사항)
장면의 디렉토리 구조는 다음과 같습니다:
<scene>
├── <scene>.png
├── <seq-##>
│ ├── frame-000000.color.png
│ ├── frame-000000.depth.png
│ ├── frame-000000.pose.txt
│ ├── frame-000001.color.png
│ ├── frame-000001.depth.png
│ ├── frame-000001.pose.txt
│ ├── frame-000002.color.png
..
├── TestSplit.txt
└── TrainSplit.txt
TestSplit.txt
와 TrainSplit.txt
파일에는 각각 쿼리 또는 매핑에 사용할 시퀀스가 포함되어 있습니다.3) kapture로 가져오기
kapture_import_7scenes.py -i /<mydatasets>/7-scenes/stairs -o /<mykaptures>/7-scenes/stairs/mapping -p mapping
참고:
매핑과 쿼리를 분할하지 않고 가져올 수도 있습니다.
이 경우 모든 데이터가 단일 데이터셋으로 병합됩니다.
또한 단일 시퀀스를 직접 경로를 지정하여 가져올 수도 있습니다 (예: /<mydatasets>/7-scenes/stairs/seq-01
).
모든 장면/분할을 한 번에 처리하려면, GNU parallel을 사용하세요:
parallel \
kapture_import_7scenes.py -v info -i /<mydatasets>/7-scenes/{1} /<mykaptures>/7-scenes/{1}/{2} -p {2} \
::: chess fire heads office pumpkin redkitchen stairs ::: query mapping
7-scenes 데이터를 kapture 포맷으로 변환한 후, 이미지 쌍을 생성하는 방법을 설명합니다. 아래에 제시된 두 가지 툴을 사용합니다.
이 두 스크립트를 사용하여 데이터셋을 변환하고 이미지 쌍을 생성할 수 있습니다.
데이터셋 변환:
extract_kapture.py
스크립트를 사용하여 7-scenes 데이터를 kapture 포맷으로 변환합니다.
python extract_kapture.py --input_dir /<mydatasets>/7-scenes/ --output_dir /<mykaptures>/7-scenes/
이미지 쌍 생성:
변환된 데이터셋에서 이미지 쌍을 생성하려면, kapture_compute_image_pairs.py
스크립트를 사용합니다.
python kapture_compute_image_pairs.py -i /<mykaptures>/7-scenes/ -o /<mykaptures>/7-scenes/pairsfile.txt
이 과정을 통해 7-scenes 데이터를 kapture 포맷으로 변환하고, 이미지 쌍을 생성할 수 있습니다.
[2024-08-15 15:19:06] T: [[ 0.3197652 ]
[ 0.00537205]
[-0.03373383]]
T: [[ 0.3197652 ]
[ 0.00537205]
[-0.03373383]]