3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

C++版SDKをPythonモジュール化する手順

Last updated at Posted at 2021-07-23

はじめに

C++版のSDKは公開されているけれどPython版がない、という時のために、具体例をもとにPythonバインディングを書く最低限の手順をまとめてみました。今回は、DJI社から公開されているThermal SDKをモジュール化してみます。

pybind11

pybind11は、C++とPythonをバインドするためのライブラリです。詳しい使い方はこちらをご参照ください。

手順

pybind11のインストール

必要に応じて、venv等で仮想環境を構築して実施してください。

$ pip install pybind11

パッケージフォルダの構成

予め前述のサイトからdji_thermal_sdk_v1.0_20201110.zipをダウンロードしておきます。

$ mkdir -p Thermal-SDK-Python/src
$ cd Thermal-SDK-Python
$ unzip dji_thermal_sdk_v1.0_20201110.zip
$ mv dji_thermal_sdk_v1.0_20201110/ sdk

バインディングの実装

今回は、rjpegという名前のモジュールを作成します。PYBIND11_MODULEマクロを使用してクラスや関数を定義していきます。

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

namespace py = pybind11;

PYBIND11_MODULE(rjpeg, m) {
    m.doc() = "Thermal SDK for Python";
    ...
}

enum の定義

pybind11::enum_<>を使用して定義します。以下に一例を書きます。

PYBIND11_MODULE(rjpeg, m) {
    ...
    py::enum_<dirp_verbose_level_e>(m, "dirp_verbose_level_e")
    .value("DIRP_VERBOSE_LEVEL_NONE", DIRP_VERBOSE_LEVEL_NONE)
    .value("DIRP_VERBOSE_LEVEL_DEBUG", DIRP_VERBOSE_LEVEL_DEBUG)
    .value("DIRP_VERBOSE_LEVEL_DETAIL", DIRP_VERBOSE_LEVEL_DETAIL)
    .value("DIRP_VERBOSE_LEVEL_NUM", DIRP_VERBOSE_LEVEL_NUM)
    .export_values();
}

struct/classの定義

pybind11::class_<>を使用して定義します。以下に一例を書きます。メンバ変数の配列はそのままでは登録できないので、stl::vectorを使用してstruct/classを定義し直しています。詳細は公式ドキュメントをご参照ください。

PYBIND11_MODULE(rjpeg, m) {
    ...
    py::class_<dirp_resolotion_t>(m, "dirp_resolotion_t")
    .def_readwrite("width", &dirp_resolotion_t::width)
    .def_readwrite("height", &dirp_resolotion_t::height);
}

関数の定義

def()関数に関数名、関数エントリポイント、説明を渡して定義します。引数や戻り値によっては元の関数をそのまま使えないor Pythonとして適切でない場合があるので、その場合はWrapper関数を作成します。インスタンスを戻り値とする場合、C++のメモリ管理を考慮する必要があります。詳細は、Return value policiesをご参照ください。

PYBIND11_MODULE(rjpeg, m) {
    ...
    m.def("dirp_create_from_rjpeg", &__dirp_create_from_rjpeg, "Create a new DIRP handle with specified R-JPEG binary data");
}

setup.pyの作成

インストール用のスクリプトを作成します。SDKのlibdirp.soをリンクしています。

setup.py
from setuptools import setup
from setuptools import find_packages
from pybind11.setup_helpers import Pybind11Extension, build_ext
from pybind11 import get_cmake_dir

import inspect
import os
import platform
import shutil
import sys

__version__ = "0.0.1"

def get_dirp_dir():
    system = platform.system().lower()
    arch = 'x64' if platform.architecture()[0] == '64bit' else 'x86'
    return 'sdk/tsdk-core/lib/' + system + '/release_' + arch

ext_modules = [
    Pybind11Extension(
        "rjpeg",
        ["src/rjpeg_module.cpp"],
        package_dir='rjpeg',
        define_macros = [('VERSION_INFO', '"' + __version__ + '"')],
        include_dirs=['sdk/tsdk-core/api'],
        library_dirs=[get_dirp_dir()],
        libraries=['dirp']
        ),
]

setup(
    name="rjpeg",
    version=__version__,
    author="Satoshi Tsutsumi",
    author_email="satoshi.tsutsumi@gmail.com",
    url="https://github.com/SatoshiTsutsumi/Thermal-SDK-Python",
    description="Thermal SDK for Python",
    long_description="",
    ext_modules=ext_modules,
    install_requires=['pybind11>=2.7'],
    extras_require={"test": "pytest"},
    cmdclass={"build_ext": build_ext},
    zip_safe=False
)

実行例

以下に、RJPEG形式の画像を読み込んで表示する例を示します。APIをそのままラップしたので画像を表示するのが手間です。もう少し使いやすいAPIにした方が良いかもしれません。
以下はThermal SDKに含まれるdataset/H20T/DJI_0001_R.JPGを表示した結果です。

import numpy as np
from PIL import Image
from rjpeg import *

# Register app
dirp_register_app("DJI_TSDK")

with open("sdk/dataset/H20T/DJI_0001_R.JPG ", "rb") as f:
        # Get DIRP handle
        buf = f.read()
        h = dirp_create_from_rjpeg(buf, len(buf))

        # Get resolution
        resol = dirp_get_rjpeg_resolution(h)
        
        # Get colored image
        color_img_buf = dirp_process(h)
        color_img_array = np.array(color_img_buf, dtype=np.uint8)
        color_img_array = color_img_array.reshape([resol.height, resol.width, 3])
        color_img = Image.fromarray(color_img_array)
        color_img.show()

DJI_001_R.JPG.JPG

参照

上記のソースコードを公開しています。pybind11は初心者なので、ご指摘歓迎です。

Thermal-SDK-Python

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?