C++ の学習: Advanced C++ (6) C++ コードで Python クラスを呼び出す方法、Python でクラスのオブジェクトをインスタンス化する方法、および conda の深層学習環境を C++ プロジェクトにインポートする方法

目次

1.適用シナリオ

2. シナリオ: maskrcnn 深層学習ネットワークを使用したセマンティック セグメンテーション

3. CMake が Python インタープリターを構成する

4. C++では、Pythonでクラスのオブジェクトをインスタンス化し、クラスでメソッドを呼び出します

4.1 Python 環境の初期化

4.2 python クラスのオブジェクトをインスタンス化する


1.適用シナリオ

        Visual SLAM やオブジェクトの検出と認識では、コードとディープ ラーニングを組み合わせることがよくあります。ただし、ディープラーニングのコードのほとんどは python で、SLAM のコードのほとんどは C++ で作成されています. C++ と python の間のリンク ブリッジを確立する方法は非常に重要です. この記事では、ディープ ラーニング用の python モジュールをインポートするように CMake を構成する方法を紹介します.学習とそれらを C++ コードにインポートする方法 Python のクラスのメソッド。

2. シナリオ: maskrcnn 深層学習ネットワークを使用したセマンティック セグメンテーション

        ビジュアル SLAM で maskrcnn ディープ ラーニング セマンティック セグメンテーション ネットワークを呼び出して、動的オブジェクトを削除します。

        まず、深層学習ネットワーク maskrcnn が確実に実行できるように、さまざまなツリーと人のデータセットをトレーニングしました.pycharm で実行した場合の効果は次のとおりです。

        元の画像は人物の写真で、この画像のマスクがここに返されます。! ! ここで、私の深層学習ネットワークが実行できることをお伝えしたいと思います (つまり、C++ から python を呼び出すときは、python コードが実行できることを確認する必要があります)。

        このコードでは、クラスORBSLAM3_with_masknetを定義しています。

        このクラスの初期化関数は、入力画像パスと出力画像パスの 2 つのパラメーターを渡します。

    def __init__(self, input_image_path, out_put_image):
        self.outImage = None
        self.input_image_path = input_image_path
        self.output_image_path = out_put_image

        このクラスは、最初のメソッドをsaveImagetoORBSLAM3として定義します。入力パラメーター (self) はありません。その機能は、入力画像パスの画像を検出してマスクし、マスク情報を class の変数 self.outImage に保存することです

        このクラスは、パラメーター (self) を渡さずに最初のメソッドshowimageを定義します。その機能は、マスク イメージ self.outImage を表示することです。

        このクラスに問題がないことを確認するために、メイン関数でこのクラスをインスタンス化し、メソッドを呼び出します。

if __name__ == '__main__':
    my_object = ORBSLAM3_with_masknet("/home/xxxxx/Desktop/slam/mask_rcnn/333.JPG",
                                      "/home/xxxxx/Desktop/slam/mask_rcnn/")
    my_object.saveImagetoORBSLAM3()
    my_object.showimage()

        操作は次のとおりです。実行できます。

3. CMake が Python インタープリターを構成する

        システムのデフォルトの python パスは、conda 仮想環境の深層学習環境ではなく、環境変数の下の python であるため、CMake を設定して、conda 仮想環境の深層学習環境に SLAM プロジェクトをリンクする必要があります。

        私のコンダの pytorch 環境は、トーチ仮想環境にあります。つまり、ディレクトリ /home/anaconda3/envs の下のトーチにあります。

        コードで具体的に宣言しない場合、システムが参照する Python パスを見てみましょう。

find_package(PythonLibs REQUIRED)
if (NOT PythonLibs_FOUND)
    message(FATAL_ERROR "PYTHON LIBS not found.")
else()
    message("PYTHON LIBS were found!")
    message("PYTHON LIBS DIRECTORY: " ${PYTHON_LIBRARY})
endif()

        プロジェクトを構成しましょう。

        参照されている python 環境がシステム環境にあることがわかります

PYTHON LIBS DIRECTORY: /usr/lib/x86_64-linux-gnu/libpython3.6m.so の python3.6。これにより、python クラスを初期化できない、セグメンテーション違反、その他の非常に頭痛の種のエラーなど、コードが実行されます。 conda 仮想環境を python 環境変数として設定するには、次の 2 行を追加します。

set(PYTHON_LIBRARY /home/liuhongwei/anaconda3/envs/torch/lib/libpython3.8.so)
set(PYTHON_INCLUDE_DIR /home/liuhongwei/anaconda3/envs/torch/include/python3.8)
find_package(PythonLibs REQUIRED)
if (NOT PythonLibs_FOUND)
    message(FATAL_ERROR "PYTHON LIBS not found.")
else()
    message("PYTHON LIBS were found!")
    message("PYTHON LIBS DIRECTORY: " ${PYTHON_LIBRARY})
endif()

        最初の行は、conda 仮想環境にある Python インタープリターのダイナミック リンク ライブラリの場所であり、次の図に示すように、すべてのマシンが同じです。

        2 行目は、python ライブラリ ファイルの場所です。

        次に、ビルドに進みました。ディープ ラーニング仮想環境へのリンクに成功しました。

        さらに、python 深層学習環境を見つけたばかりですが、python 深層環境をプロジェクトにロードするために、ここでは include_directories キーワードを使用して、プロジェクトに必要なすべてのライブラリをインポートします。

include_directories(
        ${EIGEN3_INCLUDE_DIR}
        ${Pangolin_INCLUDE_DIRS}
        /home/xxx/anaconda3/envs/torch/include/python3.8/
        /home/xxx/anaconda3/envs/torch/lib/python3.8/site-packages/numpy/core/include/numpy
        ${Boost_INCLUDE_DIRS}
)

        最後に、これらのライブラリをプログラムにリンクします。

add_executable(ExtractDynamic main.cpp)
target_link_libraries(ExtractDynamic ${PYTHON_LIBRARY})

        すべてのコードは次のとおりです。

cmake_minimum_required(VERSION 3.25)
project(ExtractDynamic)

set(CMAKE_CXX_STANDARD 17)

set(PYTHON_LIBRARY /home/xxx/anaconda3/envs/torch/lib/libpython3.8.so)
set(PYTHON_INCLUDE_DIR /home/xxx/anaconda3/envs/torch/include/python3.8)
find_package(PythonLibs REQUIRED)
if (NOT PythonLibs_FOUND)
    message(FATAL_ERROR "PYTHON LIBS not found.")
else()
    message("PYTHON LIBS were found!")
    message("PYTHON LIBS DIRECTORY: " ${PYTHON_LIBRARY})
endif()

find_package(Eigen3 3.1.0 REQUIRED)
find_package(Pangolin REQUIRED)
find_package(Boost REQUIRED COMPONENTS thread)
if(Boost_FOUND)
    message("Boost was found!")
    message("Boost Headers DIRECTORY: " ${Boost_INCLUDE_DIRS})
    message("Boost LIBS DIRECTORY: " ${Boost_LIBRARY_DIRS})
    message("Found Libraries: " ${Boost_LIBRARIES})
endif()

include_directories(
        #${PROJECT_SOURCE_DIR}
        ${EIGEN3_INCLUDE_DIR}
        ${Pangolin_INCLUDE_DIRS}
        /home/xxx/anaconda3/envs/torch/include/python3.8/
        /home/xxx/anaconda3/envs/torch/lib/python3.8/site-packages/numpy/core/include/numpy
        ${Boost_INCLUDE_DIRS}
)

message("PROJECT_SOURCE_DIR: " ${PROJECT_SOURCE_DIR})

add_executable(ExtractDynamic main.cpp)
target_link_libraries(ExtractDynamic ${PYTHON_LIBRARY})

        このようにして、CMake 環境が構成されました。

4. C++では、Pythonでクラスのオブジェクトをインスタンス化し、クラスでメソッドを呼び出します

4.1 Python 環境の初期化

    std::cout << "Initializing the OutDynamicNet..." << std::endl;

    // 转换字符串
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
    std::wstring pythonHome = converter.from_bytes("/home/liuhongwei/anaconda3/envs/torch");

    // 设置 深度学习网络目录
    std::string masknet;
    setenv("PYTHONPATH","/home/liuhongwei/Desktop/slam/mask_rcnn",1);
    masknet = getenv("PYTHONPATH");


    // 设置python的解释器的目录,初始化python环境
    Py_SetPythonHome(pythonHome.c_str());
    Py_Initialize();
    if(Py_IsInitialized())
    {
        std::cout << "Python Inititalize Succeess" << std::endl;
    }

        Python 環境の初期化を完了するためのヘッダー ファイルを導入します。

#include <Python.h>
#include <locale>
#include <codecvt>

        pythonHome は仮想環境のディレクトリを保存します. この文字列変換作業は必ず行わなければならないことに注意してください! ! ! ! そうしないと、エラーが報告されます...私はこの分野で1週間立ち往生しており、さまざまなブログや参考書を調べて初めてわかりました...

        if文でpython環境の初期化が成功したかどうかを判定!! 注: この python 環境は、CMake で設定された python 環境と同じである必要があります。そうでない場合、初期化は成功しません。

        私たちは実行します:

4.2 python クラスのオブジェクトをインスタンス化する

    PyObject * pModule = NULL;
    PyObject * pDict = NULL;
    PyObject * pInstance = NULL;
    PyObject * pClass = NULL;
    PyObject * deal = NULL;

    // 引入python文件 /xxxx/predict.py
    pModule = PyImport_ImportModule("predict");
    if(pModule != NULL)
    {
        std::cout << "Module imported successfully" << std::endl;
    }
    else
    {
        std::cout << "Failed to import module" << std::endl;
    }
    assert(pModule != NULL);


    // 获取predict可以引用的类
    pDict = PyModule_GetDict(pModule);
    assert(pDict != NULL);

    // 获取ORBSLAM3_with_masknet类,并判断类是否可引用
    pClass = PyDict_GetItemString(pDict,"ORBSLAM3_with_masknet");
    if(pClass != NULL && PyCallable_Check(pClass))
    {
        std::cout << "Class imported successfully" << std::endl;
    }
    else
    {
        std::cout << "Failed to import class" << std::endl;
    }

saveImagetoORBSLAM3クラス        を含むこのフォルダーの下に predict.py ファイルをインポートします。このクラスには、セマンティック セグメンテーションの実現に役立つメソッドがあります。

        前に pythonHome 変数を設定したので、pModule は python ファイルを取得し、それが正常に開かれたかどうかをチェックします (失敗は環境の問題、コードの問題、またはパスの問題です...)。        

        次に、PyModule_GetDict メソッドを使用して、この python ファイルで参照できるクラスを取得します。

        Get the class we need to use through the PyDict_GetItemString method. パラメーターは、参照できるクラスのオブジェクトと、クラスが使用可能かどうかを判断するためにインポートするクラスの名前です。

    pInstance = PyObject_CallFunction(pClass,"ss","/home/xxx/Desktop/slam/mask_rcnn/333.JPG","/home/xxx/Desktop/slam/mask_rcnn/");
    assert(pInstance != NULL);

    PyObject * pFunc = PyObject_GetAttrString(pInstance,"saveImagetoORBSLAM3");
    assert(pFunc!=NULL);

    PyObject * pResult1 = PyObject_CallMethod(pInstance,"__init__","ss","/home/xxx/Desktop/slam/mask_rcnn/333.JPG","/home/xxx/Desktop/slam/mask_rcnn/");
    assert(pResult1!=NULL);

        PyObject_CallFunction メソッドを介して、pClass (ORBSLAM3_with_masknet) が指すクラスをインスタンス化します。ここでは、初期化のために 2 つのパスが渡されるため、データ型は ss で、2 つのアドレス文字列が渡されます。

    def __init__(self, input_image_path, out_put_image):
        self.outImage = None
        self.input_image_path = input_image_path
        self.output_image_path = out_put_image

        次に、PyObject_GetAttrString を介して ORBSLAM3_with_masknet クラスのメソッドを実行します。

        終了!! ! 完全なコードは次のとおりです。

#include <iostream>
#include <Python.h>
#include <locale>
#include <codecvt>
int main()
{

    std::cout << "Initializing the OutDynamicNet..." << std::endl;

    // 转换字符串
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
    std::wstring pythonHome = converter.from_bytes("/home/xxx/anaconda3/envs/torch");

    // 设置 深度学习网络目录
    std::string masknet;
    setenv("PYTHONPATH","/home/xxx/Desktop/slam/mask_rcnn",1);
    masknet = getenv("PYTHONPATH");


    // 设置python的解释器的目录,初始化python环境
    Py_SetPythonHome(pythonHome.c_str());
    Py_Initialize();
    if(Py_IsInitialized())
    {
        std::cout << "Python Inititalize Succeess" << std::endl;
    }

    PyObject * pModule = NULL;
    PyObject * pDict = NULL;
    PyObject * pInstance = NULL;
    PyObject * pClass = NULL;
    PyObject * deal = NULL;

    // 引入python文件 /home/xxx/Desktop/slam/mask_rcnn/predict.py
    pModule = PyImport_ImportModule("predict");
    if(pModule != NULL)
    {
        std::cout << "Module imported successfully" << std::endl;
    }
    else
    {
        std::cout << "Failed to import module" << std::endl;
    }
    assert(pModule != NULL);


    // 获取predict可以引用的类
    pDict = PyModule_GetDict(pModule);
    assert(pDict != NULL);

    // 获取ORBSLAM3_with_masknet类,并判断类是否可引用
    pClass = PyDict_GetItemString(pDict,"ORBSLAM3_with_masknet");
    if(pClass != NULL && PyCallable_Check(pClass))
    {
        std::cout << "Class imported successfully" << std::endl;
    }
    else
    {
        std::cout << "Failed to import class" << std::endl;
    }

    // 初始化类
//    const char * ImagePath = ;
//    const char * OutPutPath = ;
    pInstance = PyObject_CallFunction(pClass,"ss","/home/xxx/Desktop/slam/mask_rcnn/333.JPG","/home/liuhongwei/Desktop/slam/mask_rcnn/");
    assert(pInstance != NULL);



    PyObject * pFunc = PyObject_GetAttrString(pInstance,"saveImagetoORBSLAM3");
    assert(pFunc!=NULL);

    PyObject * pResult1 = PyObject_CallMethod(pInstance,"__init__","ss","/home/xxx/Desktop/slam/mask_rcnn/333.JPG","/home/xxx/Desktop/slam/mask_rcnn/");
    assert(pResult1!=NULL);
    PyObject * pResult2 = PyObject_CallMethod(pInstance,"saveImagetoORBSLAM3",NULL);
    assert(pResult2!=NULL);


//    deal = PyObject_CallMethod(pInstance, "saveImagetoORBSLAM3",NULL);
//    if(deal != NULL)
//    {
//        std::cout << "Class imported successfully" << std::endl;
//    }
//    else
//    {
//        std::cout << "Failed to import class" << std::endl;
//    }
//    assert(deal!=NULL);

    std::cout << "Creating net instance..." << std::endl;
    return 0;
}

        結果を見てみましょう。

おすすめ

転載: blog.csdn.net/qq_41694024/article/details/130220025
おすすめ