Integrate C++ and Python in programming
Hybrid Programming
CMake
You should include python directory in CMakeLists.txt as
find_path(Third_python_ROOT HINTS "${Third_python_ROOT}" "$ENV{Third_python_ROOT} ")
......
include_directories(${Third_python_ROOT}/include)
......
target_link_libraries(${PROJECT_NAME} ${Third_python_ROOT}/libs/python39.lib) # python 3.9 as an example
Modify .h and .cpp file
You should include python header file in your header file as
#include <Python.h>
and here is an example of init
// init
Py_Initialize();
if (!Py_IsInitialized())
return;
// an example to run python command as a string
PyRun_SimpleString("import sys");
// an example to set python parameters
pyParams = PyDict_New();
//mind: Py_BuildValue 's' will automatically add " at beginning and end, so "\"" + ... + "\"" will result wrong !!!
PyDict_SetItemString(pyParams, "weights_path", Py_BuildValue("s", string(weights_path).c_str())); //string
PyDict_SetItemString(pyParams, "H", Py_BuildValue("i", H)); //int
PyDict_SetItemString(pyParams, "conf_thresh", Py_BuildValue("d", conf_thresh)); //double or float
PyDict_SetItemString(pyParams, "cuda", Py_True); //bool
// init threads
PyEval_InitThreads();
PyEval_ReleaseThread(PyThreadState_Get());
and here is an example of run a function
PyGILState_STATE state;
state = PyGILState_Ensure();
pModule = PyImport_ImportModule("..."); // ... is python file name
pFunc = PyObject_GetAttrString(pModule, "......"); // ...... is the function name in file ...
if (pModule && PyCallable_Check(pFunc))
{
PyObject* pArgs = PyTuple_New(1);
PyTuple_SetItem(pArgs, 0, pyParams);
PyObject* pReturn = PyEval_CallObject(pFunc, pArgs);
if (pReturn)
{
PyArrayObject* fea = (PyArrayObject*)pReturn;
// ---------- add here ----------
Py_DECREF(fea);
}
else {
cout << "python not valid return! error!" << endl;
}
}
and you should close the python module once you do not need
Py_Finalize();
Interact with numpy I/O parameters
You should include numpy directory in CMakeLists.txt as
include_directories(${Third_python_ROOT}/Lib/site-packages/numpy/core/include)
You should include numpy header file in your header file as
#include <numpy/arrayobject.h>
An example to receive the numpy return
if (pModule && PyCallable_Check(pFunc))
{
PyObject* pArgs = PyTuple_New(1);
PyTuple_SetItem(pArgs, 0, pyParams);
PyObject* pReturn = PyEval_CallObject(pFunc, pArgs);
if (pReturn)
{
PyArrayObject* fea = (PyArrayObject*)pReturn;
// --------------------
int fea_row = fea->dimensions[0], fea_col = fea->dimensions[1];
for (int idx_col = 0; idx_col < fea_col; idx_col++) {
double x = 0.0, y = 0.0, z = 0;
for (int idx_row = 0; idx_row < 2; idx_row++) {
if (idx_row == 0)
{
x = *(double*)(fea->data + idx_row * fea->strides[0] + idx_col * fea->strides[1]);
}
if (idx_row == 1)
{
y = *(double*)(fea->data + idx_row * fea->strides[0] + idx_col * fea->strides[1]);
z = *(double*)(fea->data + 2 * fea->strides[0] + idx_col * fea->strides[1]);
n_pts.push_back(cv::Point2f(x, y));
add_feature_num = add_feature_num + 1;
}
}
}
// --------------------
Py_DECREF(fea);
}
else {
cout << "python not valid return! error!" << endl;
}
}