2022년 5월 3일 화요일

플러그인 개발을 위한 자바 스크립트와 C++ 연동 및 실행 방법

이 글은 자바스크립트(Javascript)와 C++ 연동 방법에 대한 내용을 간략히 공유한다. 가끔, 플러그인 등을 개발할 때, 외부 스크립트 코드와 연동해야할 경우가 있다. 이와 관련해, 필요한 내용이 무엇인지 알아본다.

자바스크립트 동작 방식은 다음과 같다.
자바스크립트 내부 구조
자바스크립트 실행 상태 예시

아래는 C++에서 자바스크립트를 호출하는 방법을 보여준다. 
#include "quickjspp.hpp"
#include <iostream>

class MyClass
{
public:
    MyClass() {}
    MyClass(std::vector<int>) {}

    double member_variable = 5.5;
    std::string member_function(const std::string& s) { return "Hello, " + s; }
};

void println(qjs::rest<std::string> args) {
    for (auto const & arg : args) std::cout << arg << " ";
    std::cout << "\n";
}

int main()
{
    qjs::Runtime runtime;
    qjs::Context context(runtime);
    try
    {
        // C++클래스 정의 
        auto& module = context.addModule("MyModule");
        module.function<&println>("println");
        module.class_<MyClass>("MyClass")
                .constructor<>()
                .constructor<std::vector<int>>("MyClassA")
                .fun<&MyClass::member_variable>("member_variable")
                .fun<&MyClass::member_function>("member_function");

        // 자바스크립트 모듈 임포트
        context.eval(R"xxx(
            import * as my from 'MyModule';
            globalThis.my = my;
        )xxx", "<import>", JS_EVAL_TYPE_MODULE);

        // 자바스크립트 코드 호출 및 실행.
        // C++에서 정의된 클래스를 자바스크립트에서 생성, 호출할 수 있다.
        context.eval(R"xxx(
            let v1 = new my.MyClass();
            v1.member_variable = 1;
            let v2 = new my.MyClassA([1,2,3]);
            function my_callback(str) {
              my.println("at callback:", v2.member_function(str));
            }
        )xxx");

        // callback
        auto cb = (std::function<void(const std::string&)>) context.eval("my_callback");
        cb("world");
    }
    catch(qjs::exception)
    {
        auto exc = context.getException();
        std::cerr << (std::string) exc << std::endl;
        if((bool) exc["stack"])
            std::cerr << (std::string) exc["stack"] << std::endl;
        return 1;
    }
}

이 코드 실행을 위해서는 quickjspp 라이브러리가 필요하다. 아래 링크를 참고해 설치하고, 실행하면 된다. 

레퍼런스

라이다와 카메라 데이터 퓨전 기술을 이용한 3D 객체 인식, 거리, 위치 자동 추출 기술 개발 방법

이 글은 라이다와 카메라 데이터 퓨전 기술을 이용한 3차원 객체 인식, 거리, 위치 자동 추출 기술 개발 방법에 대한 소개이다. 

각자 발전된 라이다와 카메라 데이터 처리 기술은 각각의 장단점을 혼합해 사용된다. 데이터 퓨전 기술을 통해, 카메라 이미지에서는 정밀한 객체 세그먼트 정보를 얻고, 퓨전된 라이다로부터, 정확한 객체 거리 및 위치를 추출할 수 있다. 이를 잘 이용하면, 실내외 객체의 종류, 거리, 위치, 크기를 정확히 얻을 수 있다.

이 글은 특성이 서로 다른 각 데이터의 혼합(fusion) 및 중첩(superposition) 기술을 간략히 정리한다.
Fusion using camera and LiDAR

머리말
센서 퓨전 분야는 라이다와 카메라 센서 같이 이기종 센서의 장점만을 취해, 퓨전된 데이터셋을 얻을려는 시도에서 무인 자율차 등 다양한 분야에서 시도되었다. 

센서 퓨전을 통해, 라이다에서는 정확한 거리나 위치, 카메라에서는 풍부한 객체 세그먼트 정보를 얻을 수 있다. 그러므로, 센서 퓨전은 각 데이터를 하나의 좌표계로 정렬하는 것이 목적이 된다.
센서 퓨전 결과

본문
이 글은 자율차 개발 시 사용되고 있는 센서 퓨전 연구 사례(링크)를 기반으로 설명한다. 이 연구 사례는 센서 퓨전 연구를 위해, 기존 무인자율차 데이터 학습용 KTTI 데이터셋을 사용한다. 

우선, 다음과 같이, 벨로다인 라이다, 카메라를 장착한 차량(로버 등 마운팅 대상은 관계 없다)이 있다고 가정한다. 

모든 센서에서 얻은 값은 특정 센서 기준으로 데이터를 변환해야 한다. 이 경우, 카메라를 기준으로 다른 센서들의 데이터를 변환한다. 그러므로, 이를 변환하기 위한, 각 센서의 캘리브레이션(조정) 파라메터가 필요하다. 이 파라메터는 기준 센서 중심으로 데이터 변환 시 사용된다. 
Calibration for superposition 예시(라이다, 스테레오 카메라 경우)

카메라의 경우, 다음과 같이 2차원 이미지와 3차원 이미지 간에 캘리브레이션 파라메터 관계가 존재한다. 수식을 간단히 설명하면, 이 행렬은 3차원 데이터를 2차원 픽셀 좌표계로 변환한다. 행렬들은 광학적 카메라 렌즈 관련 파라메터(intrinsic properties. 스케일 관련), 외부적 카메라 속성(extrinsic properties. 위치, 회전 행렬) 행렬로 조합되어 있다. 

이는 일반적으로 우리가 3차원 게임을 할때 나타나는 3차원 객체들을 2차원 픽셀 좌표계로 맵핑된 스크린을 보는 방식과 개념상 동일한 좌표변환행렬이다. 이 부분에 대한 자세한 내용은 컴퓨터 그래픽스 좌표변환행렬을 참고하라.

u,v = P x Coordinate Transformation Matrix [4x4]

좌표변환행렬을 구성하는 파라메터는 다음과 같은 체커보드를 이용한 캘리브레이션 파라메터 추출 알고리즘을 통해 쉽게 얻을 수 있다.

파라메터 획득 후, 아래 공식으로 카메라 이미지 공간으로 다른 센서 값들을 맵핑한다.

Y(2D) = P x R0 x R|t x X (3D)

여기서,  
Y: 2차원 포인트(픽셀)
P: [3x4]행렬. Intrinsic calibration matrix
R0: [3x3]행렬. stereo rectification matrix
R|t = 벨로다인 데이터공간에서 카메라공간 데이터변환 행렬: [3x4]
X: [3x1]행렬. 3차원 포인트

일단, P는 카메라 제조사에서 pre-calibration되므로, 수행할 필요가 없다. 
R0는 스테레오 카메라에만 해당한다. 모노 카메라를 사용하므로 필요가 없다. 
R|t는 실험을 통해, 획득해야 한다. 앞의 라이다와 카메라 위치일 때, 동일 장면을 스캔한다. 스캔된 두 장면의 세개 이상의 포인트를 얻는다. 
LP={L1, L2, L3}
CP={C1, C2, C3} 

LP는 3D, CP는 2D이다. 이를 통해, 이동 및 변환 행렬을 계산할 수 있다. 이제, 동차행렬의 스케일 요소를 이용해, 정확히 라이다 이미지와 카메라 이미지 데이터를 정렬할 때의 파라메터를 계산한다. 이 과정을 통해, R|t 동차행렬을 얻을 수 있다.

이 수식을 이용해, 라이다 데이터를 카메라 이미지 공간으로 변환하였으면, 다양한 객체 검출 모델을 사용해 객체 추출한다. 이 경우, YOLO 딥러닝 모델을 사용하였다(YOLO 참고). 

결과는 다음과 같다. 이로써 객체 종류, 위치, 거리를 자동으로 얻을 수 있다. 
객체 탐지, 위치 및 거리 확인 결과

상세한 소스는 여기 링크를 참고한다. 

마무리
이 글에서는 벨로다인 라이다와 카메라 이미지와 같은 이기종 센서로 부터 퓨전 데이터를 생성한 후, 객체 인식, 위치 및 거리를 인식하는 과정을 살펴보았다. 

레퍼런스