C++言語

pybind11でPython関数の引数にC++のインスタンスを渡す方法

はじめに

画像解析やAIの分野では、Python 言語でアルゴリズム検討を行うケースが増えています。
一方、組込み機器や処理性能を考えると C 言語や C++ 言語の利用が一般的です。

Python で記述したアルゴリズムを C++ に書き換えるのが面倒だったり、
逆に C++ で記述されたプログラムを Python に書き換えるのも面倒。

そこで、C++ 言語と Python 言語を繋げるためのライブラリ pybind11 が登場しました。
今回は、C++ で定義したクラスのインスタンスを引数に、Python 側の関数を呼び出す方法を紹介します。

 

pybind11 とは?

pybind11 は、C 言語向けの Python ライブラリをラップしているヘッダーオンリーのライブラリで、
C++ の言語仕様を駆使して実装されています。
ドキュメントサンプルも充実しており、BSD ライセンスであることから、広く利用されています。

SANACHAN
SANACHAN
コードを見てみると分かりますが、読むのにまぁまぁ時間がかかります。

 

以下の手順で簡単にインストールすることが可能です。

 command
$ pip install pybind11

 

本記事の内容

Python から C++ 関数を呼び出すサンプルや、C++ から int などの標準型を引数に Python 側の関数を呼び出すサンプルは多いのですが、C++ で定義したクラスのインスタンスを引数に 、Python 側の関数を呼び出すサンプルが見つかりませんでした。

画像解析であれば cv::Mat を引数に、または独自に C++ で定義したクラスのインスタンスを渡したい。
ということで、本記事を書くことにしました。簡単なサンプルを紹介します。

動作環境は、以下の通りです。

 OS Version
$ cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.4 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.4 LTS"
VERSION_ID="20.04"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal
 Python環境
$ python3 --version
Python 3.8.10
$ python3 -m pybind11 --version
2.11.1
 コンパイラ
$ g++ -v
Target: x86_64-linux-gnu
Thread model: posix
gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.2)

 

サンプルの構成

各ファイルの構成は、以下のようにします。

 Structure of Files
/home/user/
|-  pymodule/
|        |- __init__.py
|        |- AnalyzeEngine.py
|- main.cpp
|- make.sh
|

 

C++ の Makefile

pybind11 関連のインクルードパス、コンパイルオプション、リンクすべきライブラリは、
以下のように記述することで取得できます。--embed を付けるのがポイントです。

SANACHAN
SANACHAN
undefined reference to Py_XXXX と言われたら、これが原因です。

スポンサーリンク

 

Python 側のコード

ディレクトリと関数の位置関係を定義します。

 

Python 側で実装されたアルゴリズムを実行するロジックを記述します。
今回は imgxy のプロパティを持つオブジェクトを引数でもらい、C++ 側から呼び出してもらう想定。

スポンサーリンク

 

C++ 側のコード

C++ 側で Python 側にデータを渡すためのクラス AnalyzeData を定義します。
Python 側でも使えるように PyAnalyzeData というクラスを C++ 側から Python 側へ実装します。

ポイント

C++ 側で Python 側のクラスを実装する場合は、PYBIND11_EMBEDDED_MODULE を使います。



スポンサーリンク

 

実行結果

 ビルド&実行
$ ./make.sh
$ ./pytest
<class 'PyAnalyzeData.PyAnalyzeData'>
['0', '1', '2']
640
480
Python returned [0]
SANACHAN
SANACHAN
C++側で実装した PyAnalyzeData クラスとして認識されていますね。

 

おわりに

C++ 側から Python の関数を呼び出す方法を検索し、引数を与えて呼び出す方法までは見つかりましたが、
C++ で定義したクラスのインスタンスを引数にする方法が見つかりませんでした。

pybind11 のコードを少し読んで実装しましたので、他に良い方法があれば教えてください。

 

こちらの記事もよく読まれています

  • この記事を書いた人
  • 最新記事
SANACHAN

SANACHAN

「生涯一エンジニア」を掲げ、大手グローバル企業でSE/PGとして8年勤め、キャリアアップ転職した現役のエンジニアです。世にあるメジャーな全プログラム言語(コボル除く)を自由に扱えます。一児の父。自分のため、家族のため、日々勉強してます。システムエンジニア、プログラミングに関する情報を蓄積している雑記帳です。

-C++言語
-, , , ,