C ++プロジェクトがPythonスクリプトを呼び出す(VS2017)

最近、プロジェクトのニーズにより、x265でPythonスクリプトを呼び出し、一般的な使用プロセスを記録する必要があります。

1つ、コンパイル

x265 / VTM / HMをコンパイルするときは、CMakeLists.txtに次のステートメントを追加する必要があります。

# python3
include_directories("D:/Anaconda/include/")
link_libraries("D:/Anaconda/libs/python36.lib")

Anacondaをダウンロードしたので、ここに含める必要があるのはAnacondaの下のパスです。追加後、通常どおりコンパイルします

2つ目は、C ++がPythonスクリプトを呼び出すことです。

コンパイルが完了したら、VS2017でプロジェクトを開きます

1.Pythonヘッダーファイルを追加します

#include<Python.h>

2. pythonライブラリ関数を使用する前に、pythonインターフェイスを初期化する必要があります

Py_Initialize();

同様に、Pythonスクリプトを呼び出した後、Pythonインターフェイスを解放することを忘れないでください。

Py_Finalize();

 注:初期化と解放のこれら2つの関数は、プログラム全体で1回しか呼び出すことができないため、プログラム全体の最初と最後に配置する必要があります。複数の呼び出しがある場合は、アクセスの競合が発生する可能性があります。 dllが見つかりません。など。

 3.Pythonスクリプトの下で作業パスを切り替えます

	PyRun_SimpleString("import sys");
	PyRun_SimpleString("import os");
	PyRun_SimpleString("os.chdir('./Net')");
	PyRun_SimpleString("sys.path.append('./')");

ここでは、os.chdirを使用してPythonスクリプトが配置されているパス切り替えてから、sys.path.append( './')を使用して現在のディレクトリを作業パス追加します

呼び出しが完了したら、os.chdirを使用して前の作業ディレクトリ切り替えます

4.モジュールと関数をロードします

	m_pMod = PyImport_ImportModule("testnet");
	if (!m_pMod)
	{
		PyErr_Print();
	}

    m_pFunc = PyObject_GetAttrString(m_pMod, "run");
	if (!m_pFunc)
	{
		PyErr_Print();
	}

ここで呼び出すPythonスクリプトの名前はtestnet.pyファイルなので、PyImport_ImportModule関数を使用してPythonファイルを呼び出し、次にPyObject_GetAttrStringを使用て対応する関数呼び出します。ここで、runテストネットで定義されたPython関数名です。 .pyファイル

注:スクリプトと関数を引用するたびに、 PyErr_Print()関数を使用してエラーをチェックする必要があります。

5.パラメーターを設定し、パラメーターをpython関数に渡し、python関数を呼び出します。

	PyObject *pReturn = NULL;
	PyObject *pInputRec = PyList_New(TuWidth * TuHeight);
	PyObject *pParam = PyTuple_New(3);

	for (int row = 0; row < TuHeight; row++)
	{
		for (int col = 0; col < TuWidth; col++)
		{
			PyList_SetItem(pInputRec, row * TuWidth + col, Py_BuildValue("i", NNRecon[row * TuWidth + col]));
		}
	}
	PyTuple_SetItem(pParam, 0, pInputRec);
	PyTuple_SetItem(pParam, 1, Py_BuildValue("i", TuWidth));
	PyTuple_SetItem(pParam, 2, Py_BuildValue("i", TuHeight));
	pReturn = PyEval_CallObject(m_pFunc, pParam);//调用python中函数
	PyList_Check(pReturn);

我々が使用することができPyList_Newの、Pythonのリストを定義する関数をPyTuple_Newの、Pythonのタプルを定義する関数をPy_BuildValueする」に加え、「I」は、PythonオブジェクトへのC ++タイプ番号を変換する変換フォーマット(整数)の機能をi "次の形式があります。

  • "s"(string)[char *]:C文字列をPythonオブジェクトに変換します。C文字列が空の場合は、NONEを返します。
  • "s#"(string)[char *、int]:C文字列とその長さをPythonオブジェクトに変換します。C文字列がnullポインターの場合、長さは無視され、NONEが返されます。
  • "z"(文字列またはなし)[char *]:作用同 "s"。
  • "z#"(文字列またはなし)[char *、int]:作用同 "s#"。
  •  "i"(integer)[int]:C型intをPythonintオブジェクトに変換します。
  • "b"(整数)[char]:作用同 "i"。
  • "h"(整数)[short int]:作用同 "i"。
  • "i"(integer)[long int]:タイプCのlongをPyhonのintオブジェクトに変換します。
  • "c"(長さ1の文字列)[char]:Cタイプのcharを長さ1のPython文字列オブジェクトに変換します。
  • "d"(float)[double]:PythonでCdoubleを浮動小数点オブジェクトに変換します。
  • "f"(float)[float]:作用同 "d"。
  • 「O&」(オブジェクト)[コンバーター、何でも]:変換関数を使用して任意のデータ型をPythonオブジェクトに変換し、これらのデータは変換関数のパラメーターとして使用されます

PyList_SetItem関数を使用して、リスト内の要素の値を設定します。最初のパラメーターは設定するリスト、2番目のパラメーターはリストのインデックス値、3番目のパラメーターは設定する値を示します。同様に、PyTuple_SetItem関数はタプルに値を設定できます

パラメータを設定した後、PyEval_CallObject関数を使用してPython関数を呼び出し、パラメータを渡します。最初のパラメータは呼び出される関数を参照し、2番目のパラメータは関数のパラメータを参照します。

私が定義したrun関数はPythonリストを返すため、Pythonの戻り値を取得した後、PyList_Check関数を呼び出して、それがPythonリスト(リスト)であるかどうかを判断します。

6.戻り値を解析し、PythonオブジェクトをC ++タイプに変換します

	for (int row = 0; row < TuHeight; row++)
	{
		for (int col = 0; col < TuWidth; col++)
		{
			PyArg_Parse(PyList_GetItem(pReturn, row * TuWidth + col), "i", &NNRecon[row * TuWidth + col]);
		} 
	}

PyList_GetItem関数は、Pythonリスト内の対応するインデックスの値を取得できます。最初のパラメーターはPythonリストを表し、2番目のパラメーターはインデックスを表します。

使用PyArg_ParseのC ++型の値にPythonオブジェクトを変換する機能。最初のパラメータは、Pythonオブジェクトを表し、2番目のパラメータは、変換されたC ++型のフォーマットを示し、3番目のパラメータは、変換された値に割り当てられた変数(アンパサンドを追加しなければならない)であります

7、終わり

Py_DECREF(pInputRec);
Py_DECREF(pReturn);
Py_DECREF(pParam);
Py_Finalize();

Python呼び出し全体が終了したら、 Py_DECREF(PyObject*)函数释放资源,方便python对象垃圾回收。

 

 

おすすめ

転載: blog.csdn.net/BigDream123/article/details/112549128