카테고리 없음

실시간으로 NVIDIA FoundationStereo 사용하기

Wood Pecker 2026. 5. 7. 22:00

1. 개요 

    NVIDIA에서 발표한 FoundationStereo Model을 이용하여 윈도우즈 환경에서 실시간 스테레오 매칭을 테스트 해본다. 

    Astra Pro는 Depth 해상도가 많이 부족하여 형체 인식도 잘 안된다. 새로운 시도를 하여 보았고 결과는 만족스러웠다. 

 

2. 스테레오 카메라 모듈
   입력 이미지를 얻기 위해 아래와 같은 제품을 구매하였다. 가격은 4만원 조금 넘는다.  
     듀얼 렌즈 USB 웹캠 2560*720 30fps Windows Linux Android Raspberry Pi

3.라이브러리 설치 
   설치는 간단하다. Github에서 다운 받는다. 학습된 훈련 데이터(pretrained model)를  다운로드 받는다.
   11-33-40/model_best_bp2.pth  또는 23-51-11/ model_best_bp2.pth 
   https://github.com/NVlabs/FoundationStereo

 


4. 테스트 코드 작성

    scripts/test.py 파일을 다음과 같이 작성한다.

import os,sys
import argparse
import imageio
import torch
import logging
import cv2
import numpy as np
import open3d as o3d
code_dir = os.path.dirname(os.path.realpath(__file__))
sys.path.append(f'{code_dir}/../')
from omegaconf import OmegaConf
from core.utils.utils import InputPadder
from Utils import set_logging_format, set_seed, vis_disparity, depth2xyzmap, toOpen3dCloud
from core.foundation_stereo import FoundationStereo

# 경로 설정
code_dir = os.path.dirname(os.path.realpath(__file__))
sys.path.append(f'{code_dir}/../')

from core.utils.utils import InputPadder
from Utils import set_logging_format, set_seed, vis_disparity
from core.foundation_stereo import FoundationStereo


def run_realtime_stereo(args, model):
    # 웹캠 연결 (0번 카메라)
    cap = cv2.VideoCapture(0)

    # 웹캠 해상도 설정 (카메라가 지원하는 최대 SBS 해상도로 설정 가능)
    # cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
    # cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

    if not cap.isOpened():
        logging.error("웹캠을 열 수 없습니다.")
        return

    logging.info("실시간 스테레오 시작 (종료하려면 'q'를 누르세요)")

    with torch.no_grad():  # 추론 시 그래디언트 계산 비활성화
        while True:
            ret, frame = cap.read()
            if not ret:
                break

            # 1. SBS 영상 분리 (가로 절반)
            h, w, _ = frame.shape
            half_w = w // 2
            left_cv = frame[:, :half_w]
            right_cv = frame[:, half_w:]

            # 2. 전처리 (BGR -> RGB 변환 및 Scale 조정)
            img0 = cv2.cvtColor(left_cv, cv2.COLOR_BGR2RGB)
            img1 = cv2.cvtColor(right_cv, cv2.COLOR_BGR2RGB)

            if args.scale < 1:
                img0 = cv2.resize(img0, None, fx=args.scale, fy=args.scale)
                img1 = cv2.resize(img1, None, fx=args.scale, fy=args.scale)

            H, W = img0.shape[:2]
            img0_ori = img0.copy()

            # 3. 텐서 변환 및 패딩
            img0 = torch.as_tensor(img0).cuda().float()[None].permute(0, 3, 1, 2)
            img1 = torch.as_tensor(img1).cuda().float()[None].permute(0, 3, 1, 2)

            padder = InputPadder(img0.shape, divis_by=32)
            img0, img1 = padder.pad(img0, img1)

            # 4. 모델 추론 (Mixed Precision 사용)
            with torch.amp.autocast('cuda', enabled=True):
                disp = model.forward(img0, img1, iters=args.valid_iters, test_mode=True)

            # 5. 결과 후처리
            disp = padder.unpad(disp.float())
            disp = disp.data.cpu().numpy().reshape(H, W)

            # 시차(Disparity) 맵 시각화
            vis_disp = vis_disparity(disp)  # 유틸리티 함수 사용

            # 6. 화면 출력 (왼쪽 원본 + 시차 맵 합치기)
            # vis_disp는 RGB이므로 다시 BGR로 바꿔서 원본 cv 이미지와 합침
            vis_disp_bgr = cv2.cvtColor(vis_disp, cv2.COLOR_RGB2BGR)

            # 크기 맞추기 (scale 조절된 경우 원본 크기로 복구하여 합침)
            left_show = cv2.resize(left_cv, (W, H))
            combined_view = np.hstack([left_show, vis_disp_bgr])

            cv2.imshow('FoundationStereo Real-time (Press Q to quit)', combined_view)

            if cv2.waitKey(1) & 0xFF == ord('q'):
                break

    cap.release()
    cv2.destroyAllWindows()


if __name__ == "__main__":
    # 기본 설정값 구성
    parser = argparse.ArgumentParser()
    parser.add_argument('--ckpt_dir', default='../pretrained_models/11-33-40/model_best_bp2.pth', type=str)
    parser.add_argument('--scale', default=0.5, type=float, help='실시간 성능을 위해 0.5 권장')
    parser.add_argument('--valid_iters', type=int, default=8, help='실시간을 위해 반복 횟수 줄임 (기본 32)')
    parser.add_argument('--hiera', default=0, type=int)

    # 임시 args 생성하여 cfg 로드
    temp_args = parser.parse_known_args()[0]

    set_logging_format()
    set_seed(0)
    torch.autograd.set_grad_enabled(False)

    # 설정 파일 로드 및 병합
    ckpt_path = temp_args.ckpt_dir
    cfg = OmegaConf.load(f'{os.path.dirname(ckpt_path)}/cfg.yaml')
    for k in temp_args.__dict__:
        cfg[k] = temp_args.__dict__[k]
    args = OmegaConf.create(cfg)

    # 모델 초기화
    logging.info(f"모델 로딩 중: {ckpt_path}")
    model = FoundationStereo(args)
    ckpt = torch.load(ckpt_path, weights_only=False, map_location='cuda')
    model.load_state_dict(ckpt['model'])
    model.cuda()
    model.eval()

    # 실시간 루프 실행
    run_realtime_stereo(args, model)


5. 실행결과 
   스테레오 매칭 결과가 실시간으로 잘 수행된다.  실제 응용에도 잘 적용될 수 있을 것이다. 

 

반응형