2019년 9월 3일 화요일

공간 맵핑용 스테레오 이미지 센서 ZED 사용기

이 글은 간단한 RGBD 이미지 센서 ZED 사용기이다. 이 글에서 ZED를 동작시키기 위해 NVIDIA NANO를 사용하였다. NVIDIA NANO 설정에 대해서는 이 링크를 참고 바란다.

소개
ZED는 비전을 위한 이미지 센서로 듀얼렌즈가 장착된 카메라이다. 고화질 3D 비디오를 캡쳐할 수 있고, 깊이 인식이 가능하다. 이 카메라는 스테레오 비전 기술을 사용한다. 그러므로, 적외선 RGBD 방식에 비해 강한 햇빛에 큰 영향을 받지 않는다. ZED 센서의 특징(스펙)은 다음과 같다.
  • ZED 2는 최대 40m까지 스캔. ZED는 20m 범위에서 깊이 캡쳐 가능함. ULTRA 모드에서는 30m까지 가능함
  • 뎁스맵(depth map) 캡쳐 속도는 100 FPS(Frame per second0
  • 화각은 최대 90도(H) x 60도(V)
  • 센서는 실내외 및 실외에서 작동됨
  • 6DOF 지원
ZED 카메라 센서

ZED는 깊이 및 위치 추적시 ROS(Robot Operating System) 등을 사용한다. ZED의 이미지 처리와 소프트웨어 실행에는 많은 연산이 필요하므로, 보통, GPU가 장착된 임베디드 컴퓨터를 사용하는 것이 일반적이다. 임베디드 컴퓨터로는 NVIDIA의 NANO, TX2 등이 주로 사용된다.
NVIDIA NANO, TX2 성능 비교

ZED 홈페이지는 이 기기의 스펙과 활용 사례를 소개하고 있다. Getting Started 페이지에서는 ZED를 사용하기 위한 전반적인 내용을 요약 설명한다.

SDK 설치
다음 링크를 참고해 JetPack을 설치한다. JatPack은 NVIDIA 장치에 TensorRT, cuDNN, CUDA, VisionWorks, OpenCV를 손쉽게 설치해주는 개발도구 패키지이다. 참고로, 설치는 하루 이상 걸린다.
개발자를 위한 툴킷은 아래 링크에서 다운로드 받을 수 있다. NVIDIA NANO, TX2, TX1은 ZED SDK for Jetpack 버전을 다운로드 받아 설치한다. CUDA버전에 따라 설치해야 하므로, 미리 nvcc --version 명령으로 확인 후에 적당한 버전을 다운로드하도록한다. 참고로 CUDA가 설치되어 있다면, /usr/local/cuda/bin 에 nvcc파일이 있을 것이다.
ZED SDK 가 제대로 설치되었다면, 다음 폴더에서 실행파일을 확인할 수 있다.

이 중에 'ZED Diagnostic'을 실행해 ZED카메라가 정상동작하는 지 확인한다. 이상없으면 다음처럼 보일 것이다.

'ZED Explorer'를 실행하면 카메라 세팅에 따른 스테레오 이미지 확인 가능하다.

Depthmap 예제를 실행하면 스테레오 이미지에서 생성한 깊이맵을 확인할 수 있다.

SVOEditor를 실행하면, 공간맵핑된 메쉬를 확인할 수 있다.

SDK 기반 개발
ZED SDK를 이용한 개발은 ZED에서 제공된 Tutorial, 예제를 활용해 진행한다. 다음 github 에서 공간맵핑 소스코드를 다운로드 받는다.
그리고, 다음과 같이 빌드한다.
mkdir build
cd build
cmake ..
make

생성된 실행파일을 실행하면 다음 결과를 확인할 수 있다.

생성된 obj파일은 메쉬 파일이므로, 이를 보기 위해 다음과 같이 meshlab을 설치한다.
sudo apt-get install meshlab

meshlab을 실행해 생성된 obj파일을 로딩하면 다음과 같이 포인트 클라우드를 확인할 수 있다. 역시 생성된 데이터 결과물은 LiDAR와 같은 거리센서에 의해 얻어진 결과물에 비해 정확도가 낮다.
meshlab

핵심적인 소스코드 설명은 다음과 같다. 

#include <sl/Camera.hpp>
using namespace sl;
Mesh map;

Camera zed; 
SpatialMappingParameters spatial_mapping_parameters;

zed.enableTracking();

mapping = false;
while(scanningFlag)
{
  // GPU 메모리 내 이미지 검색
  zed.retrieveImage(image, VIEW_LEFT, MEM_GPU);

  // 공간 맵핑 비동기 요청 
  if(mapping)
  {
    if(zed.getSpatialMapRequestStatusAsync() == SUCCESS)
      zed.retrieveSpatialMapAsync(map);
  }

  if(mapping == false)
 {
    // 위치 추적 리셋
    Transform init_pose;
    zed.resetTracking(init_pose);
 
    // 공간맵핑 설정   
    parametersspatial_mapping_parameters.resolution_meter = SpatialMappingParameters::get(SpatialMappingParameters::MAPPING_RESOLUTION_MEDIUM);
    spatial_mapping_parameters.use_chunk_only = true;
    spatial_mapping_parameters.save_texture = false;
    spatial_mapping_parameters.map_type = SpatialMappingParameters::SPATIAL_MAP_TYPE_MESH;

    // 공간 맵핑 활성화
    zed.enableSpatialMapping(spatial_mapping_parameters);
    viewer.clearCurrentMesh();
    mapping = true;
  }
  else 
  {
    // 생성된 공간 맵 추출
    zed.extractWholeSpatialMap(map);
    MeshFilterParameters filter_params;
    filter_params.set(MeshFilterParameters::MESH_FILTER_MEDIUM);
                    
    // 메쉬 추출 필터 설정
    map.filter(filter_params, true);
    if(spatial_mapping_parameters.save_texture)  // 텍스처 저장 옵션 설정
      map.applyTexture(MESH_TEXTURE_RGB);

    // obj mesh 파일 저장
    string saveName = getDir() + "mesh_gen.obj";
    bool error_save = map.save(saveName.c_str());
  }
}

ROS 기반 개발
ROS기반에서 실시간 깊이 데이터 취득 및 시각화를 위해서 다음 링크를 참고해 ROS 및 관련 패키지들을 설정 및 빌드한다.
빌드 과정
ZED 파라메터에 대한 설명은 다음 링크를 참고한다. 파라메터는 ROS catkin_ws 폴더의 src/zed-ros-wrapper/zed_wrapper/params/common.yaml 에 저장되어 있다.
빌드 후 다음 명령을 실행하면, Stereo image, Depth map 기능이 수행된다.
roscore
roslaunch zed_wrapper zed.launch frame_rate:=30
Stereo image(rqt_image_view)
Depth map(rqt_image_view)

다음 명령을 실행하면, ZED ROS node들과 ROS Viz 가 수행된다. 만약, 카메라 이미지가 갱신되지 않는다면, RViz의 설정 중 Camera > Unreliable 를 off해 보길 바란다(기타, Point cloud issue 는 여길 참고하길 바란다).
killall -9 roscore
killall -9 rosmaster
roscore
roslaunch zed_display_rviz display_zed.launch
ZED Image(RViz)

이제, 다음 명령으로 포인트 클라우드 토픽을 확인해 보자(참고).
killall -9 roscore
killall -9 rosmaster
roscore
roslaunch zed_wrapper zed.launch
rosrun rviz rviz
Point cloud(RViz)

결과화면과 같이 포인트 클라우드 토픽이 잘 생성되는 것을 확인할 수 있다.

활용 예제
예제를 실행하려면, 2가지 방법이 있다. 설치된 SDK의 Samples 폴더에 각 예제들은 cpp, python 버전이 있다. 
cpp는 cmake, make 명령을 이용해 빌드해 사용한다. cmake 파일이 있는 폴더에서 다음 명령을 이용해 소스코드를 빌드하고 실행한다. 
mkdir build
cd build
cmake ..
make


파이썬의 경우 다음과 같이 도구를 설치하고 실행한다(참고).
sudo pip install --upgrade pip setuptools wheel
sudo pip install opencv-python 
sudo pip install PyOpenGL

예제 실행 결과는 다음과 같다. 
평면 검출
네트워크 영상 스트리밍(sender - receiver)
실시간 카메라 위치 추적
실시간 스캔 및 3차원 공간 모델 구성
스테레오 비전 SVO 포맷 저장 및 변환(SVO recording - repair - export)
뎁스맵 변환
실시간 3차원 포인트 클라우드 생성

ZED는 SVO파일에 스테레오 이미지, 3차원 변환을 위한 정보 및 IMU와 같은 메타데이터까지 저장하고, 이를 통해 다양한 작업을 할 수 있다(참고 - Using the Video API, Compression ModesSensors OverviewHow do I recalibrate my ZED stereo camera?, ZED Calibration). 

마무리
ZED는 스테레오 이미지를 이용해 깊이 맵을 얻는 방식으로, 공간 맵핑과 관련된 다양한 예제를 제공한다. 단, 직접 거리를 측정하는 방식이 아니므로, 정확도 문제가 있다. 키넥트와 같은 적외선 주사방식이 아니기 때문에 야외에서 깊이 맵을 얻을 수 있고, NVIDIA Jetson과 호환성이 좋아, 괜찬은 처리 성능을 보인다. 
좀 더 자세한 사용방법은 다음 예제를 참고하길 바란다.

댓글 5개:

  1. 잘 봤습니다. 3d가아닌 2D LIDAR와 ZED2 카메라의 Sensor fusion으로 mapping 정확도를 높일 수 있을까요?

    답글삭제
    답글
    1. 네. 정확도는 높일 수 있습니다. 다만, 서로 데이터 형태가 달라 약간 프로그래밍 해야 할 듯 합니다.

      삭제
  2. 제가 아주 궁금해하고 있던 차에 이미 사용을 해보시고 그 기록을 남겨주셔서 잘 참고합니다. 조만간 연락을 드리고 더 궁금한 것 여쭈어 보고 싶네요 ~~

    답글삭제
  3. 안녕하세요. Zed2 카메라를 이용하고있는데요. SDK 샘플코드 동작시킬때 텐서플로우 같은 AI 라이브러리를 사용해야 하나요?

    답글삭제
    답글
    1. 텐서플로우 필요 없습니다. 컴파일러 같은 개발 환경만 미리 설치해 놓으면 됩니다.

      삭제