zoukankan      html  css  js  c++  java
  • C++调用python(二)


    一、基本使用方法
    二、调用简单语句
    三、调用函数
    四、调用类
    五、调用SSD目标检测算法
    六、遇到的错误


    三、调用函数

    3.1 无参

    -CMakeLists.txt

    cmake_minimum_required(VERSION 3.9)
    
    project(say_hello)
    
    set(SDK_VERSION 0_0_1)
    # >>> build type 
    set(CMAKE_BUILD_TYPE "Release")				# 指定生成的版本
    set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb")
    set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
    # <<<
    
    
    # >>> CXX11 
    set(CMAKE_CXX_STANDARD 11)				# C++ 11 编译器
    SET(CMAKE_CXX_STANDARD_REQUIRED TRUE)
    # <<< 
    
    
    # >>> Python3 
    set(PYTHON_ROOT "/home/zjh/anaconda3/envs/learn")
    message("python root: " ${PYTHON_ROOT})
    include_directories(${PYTHON_ROOT}/include/)
    link_directories(${PYTHON_ROOT}/lib/)
    # <<<
    
    # --- generate ---
    add_executable(say_hello hello.cpp)
    target_link_libraries(say_hello -lpython3.6m)
    
    • hello.py
    def say():
        print("hello")
    
    
    if __name__ == "__main__":
        say()
    
    
    • hello.cpp
    #include <python3.6m/Python.h>
    #include <iostream>
    
    
    int main(int argc, char *argv[])
    {
        wchar_t *program = Py_DecodeLocale(argv[0], nullptr);
        if ( program == nullptr ){
            std::cout << "Fatal Error: cannot decode argv[0]!" << std::endl;
            return -1;
        }
        Py_SetProgramName(program);
        Py_SetPythonHome((wchar_t*)L"/home/zjh/anaconda3/envs/learn");
        Py_Initialize();
        if ( !Py_IsInitialized() ){
            std::cout << "Python init failed!" << std::endl;
    	return 0;
        }
        
        PyRun_SimpleString("import sys");
        PyRun_SimpleString("sys.path.append('/media/zjh/资料/code/C++_call_python/test/test_hello')");
        
        PyObject* pModule = PyImport_ImportModule("hello");
        if ( pModule == nullptr ){
            std::cout << "module not found!" << std::endl;
            return 1;
        }
        
        PyObject* pFunc = PyObject_GetAttrString(pModule, "say");
        if ( !pFunc || !PyCallable_Check(pFunc) ){
            std::cout << "not found function add_num!" << std::endl;
            return 2;
        }
        PyObject_CallObject(pFunc, nullptr);
    
        if ( Py_FinalizeEx() < 0 ){
            exit(120);
        }
        PyMem_RawFree(program);
        return 0;
    }
    
    

    3.2 有参

    • CMakeLists.txt
      在3.1的基础上修改开始的program 和最后generate部分就行。

    • add.py

    def add_num(a, b):
        print("the result {} + {} is {}".format(a, b, a+b))
        return a + b
    
    
    if __name__ == "__main__":
        add_num(1, 2)
    
    
    • add.cpp
    #include <python3.6m/Python.h>
    #include <iostream>
    
    
    int main(int argc, char *argv[])
    {
        wchar_t *program = Py_DecodeLocale(argv[0], nullptr);
        if ( program == nullptr ){
            std::cout << "Fatal Error: cannot decode argv[0]!" << std::endl;
            return -1;
        }
        Py_SetProgramName(program);
        Py_Initialize();
        if ( !Py_IsInitialized() ){
            std::cout << "Python init failed!" << std::endl;
    	return 0;
        }
        
        PyRun_SimpleString("import sys");
        PyRun_SimpleString("sys.path.append('/home/heygears/work/C++_python/test/test_add')");
        
        PyObject* pModule = PyImport_ImportModule("add");
        if ( pModule == nullptr ){
            std::cout << "module not found!" << std::endl;
            return 1;
        }
        
        PyObject* pFunc = PyObject_GetAttrString(pModule, "add_num");
        if ( !pFunc || !PyCallable_Check(pFunc) ){
            std::cout << "not found function add_num!" << std::endl;
            return 2;
        }
        
        PyObject* args = Py_BuildValue("(ii)", 28, 103);
        PyObject* pRet = PyObject_CallObject(pFunc, args);
        Py_DECREF(args);
         
        int res = 0;
        PyArg_Parse(pRet, "i", &res);
        Py_DECREF(pRet);
        std::cout << "the res is: " << res << std::endl;
    
        if ( Py_FinalizeEx() < 0 ){
            exit(120);
        }
        PyMem_RawFree(program);
        return 0;
    }
    
    

    四、调用类

    • CMakeLists.txt

    • test_class.py

    class Test(object):
        def __init__(self):
            self.i = 1
            print("init!")
    
        def modify(self):
            self.i += 1
    
        def do(self):
            print(self.i)
     
    if __name__ == "__main__":
        test_class = Test()
        test_class.do()
        test_class.modify()
        test_class.do()
    
    
    • testClass.cpp
    #include <python3.6m/Python.h>
    #include <iostream>
    
    
    int main(int argc, char *argv[])
    {
        wchar_t *program = Py_DecodeLocale(argv[0], nullptr);
        if ( program == nullptr ){
            std::cout << "Fatal Error: cannot decode argv[0]!" << std::endl;
            return -1;
        }
        Py_SetProgramName(program);
        Py_Initialize();
        if ( !Py_IsInitialized() ){
            std::cout << "Python init failed!" << std::endl;
    	return 0;
        }
        
        PyRun_SimpleString("import sys");
        PyRun_SimpleString("sys.path.append('/home/heygears/work/C++_python/test/test_class')");
        
        // 1. 导入模块
        PyObject* pModule = PyImport_ImportModule("test_class");
        if ( pModule == nullptr ){
            std::cout << "module not found!" << std::endl;
            return 1;
        }
    
        PyObject* pTestDict = PyModule_GetDict(pModule);
        
        
        // 2. 导入模块中方法或类
        PyObject* pTestClass = PyDict_GetItemString(pTestDict, "Test");
    
        // 3. 创建实例
        PyObject* pTestInstance = nullptr;
        if ( PyCallable_Check(pTestClass) ){
            pTestInstance = PyObject_CallObject(pTestClass, nullptr);
        }
        
        // 4. 调用类方法
        PyObject_CallMethod(pTestInstance, "do", nullptr);
        PyObject_CallMethod(pTestInstance, "modify", nullptr);
        PyObject_CallMethod(pTestInstance, "do", nullptr);
    
        if ( Py_FinalizeEx() < 0 ){
            exit(120);
        }
        PyMem_RawFree(program);
        return 0;
    }
    
    

    注:如果类函数有参数,可以参照4.2中方法

    五、调用SSD目标检测算法

    参考C/C++调用Python [OpenCV与Numpy]Windows下C++调用Python版的Pytorch模型
    这里以调用SSD模型为例

    • CMakeLists.txt
      由于需要用到Numpy,所以在CMakeLists.txt中先引入Numpy的头文件,可以参考一、基本使用方法
      另外还需要用到OpenCV库,在CMakeLists.txt后面添加如下代码, target_link_libraries也需要追加 ${OpenCV_LIBS}库。
    # >>> opencv
    set(OpenCV_DIR "/usr/local")
    message(STATUS ${OpenCV_DIR})
    find_package(OpenCV REQUIRED)
    if(OpenCV_FOUND)
        include_directories(${OpenCV_DIR}/include/opencv4/opencv2)
        include_directories( ${OpenCV_INCLUDE_DIRS})
        link_directories(${OpenCV_DIR}/lib)
        message(STATUS "Configure package with OpenCV!")
        set(HAVE_OpenCV True)
    else()
        set(HAVE_OpenCV False)
        message(STATUS "Configure package without OpenCV!")
    endif()
    # <<<
    
    • inferencePb.py
    # -*- coding :  utf-8 -*-
    # @File      :  inferencePb.py
    # Desctiption:  MobileNetV2SSDlite
    
    
    import os
    import cv2
    import time
    import numpy as np
    import tensorflow as tf
    
    #os.environ["CUDA_VISIBLE_DEVICES"]="-1"
    ###############################################################################
    #- 定义识别函数
    
    
    def arrayreset(array):
        a = array[:, 0:len(array[0] - 2):3]
        b = array[:, 1:len(array[0] - 2):3]
        c = array[:, 2:len(array[0] - 2):3]
        a = a[:, :, None]
        b = b[:, :, None]
        c = c[:, :, None]
        m = np.concatenate((a, b, c), axis=2)
        return m
    
    
    
    def recognize(src_image):
        """
        MobileNetV2-SSDLite
        :param src_image: 输入视频流或图像
        :param pb_file_path: the model file path
        :return: 
        """
        
        with tf.Graph().as_default():
            output_graph_def = tf.GraphDef()
    
    
            #---------------------------------------
            # 打开 .pb 模型
            pb_file = "ssd300_pascal_07+12_epoch-86_loss-1.2568_val_loss-0.5428.pb"
    
            with open(pb_file, "rb") as f:
                output_graph_def.ParseFromString(f.read())
                tensors = tf.import_graph_def(output_graph_def, name="")
                print("tensors:",tensors)
    
    
            with tf.Session() as sess:
               # init = tf.global_variables_initializer()
               # sess.run(init)
    
                #---------------------------------------
                # 打开图中所有的操作
                op = sess.graph.get_operations()
                for i,m in enumerate(op):
                    print('op{}:'.format(i),m.values())
    
                #---------------------------------------
                # 模型的的输入和输出名称
    
                #--------------------------------------
                # 遍历某目录下的图像
    
                input_x = sess.graph.get_tensor_by_name("input_1:0")
                #print("input_X:",input_x)
                output_tensor = sess.graph.get_tensor_by_name("ssd_decoded_predictions/loop_over_batch/TensorArrayStack/TensorArrayGatherV3:0")
                #print("Output:",output_tensor)
         
    
                #--------------------------------------
                # 计算时间, 持续加载同一张图像
    
                # src_image = arrayreset(src_image)       
                src_image = cv2.imread(src_image) 
                org_img = src_image.copy()
    
                img=cv2.resize(src_image,(300,300))
                img=img.astype(np.float32)
                      
                y_pred = sess.run([output_tensor], feed_dict={input_x:np.reshape(img,(1,300,300,3))})
                          
                confidence_threshold = 0.8
    
                y_pred_array = np.array(y_pred[0])
    
                y_pred_thresh = [y_pred_array[k][y_pred_array[k,:,1] > confidence_threshold] for k in range(y_pred_array.shape[0])]
                classes = ['background', 'tank']
                image_size = (300, 300, 3)
    
                for box in y_pred_thresh[0]:
                    xmin = box[2] * org_img.shape[1] / image_size[0]
                    ymin = box[3] * org_img.shape[0] / image_size[1]
                    xmax = box[4] * org_img.shape[1] / image_size[1]
                    ymax = box[5] * org_img.shape[0] / image_size[0]
                    label = '{}: {:.2f}'.format(classes[int(box[0])], box[1])
                    print("label", label)
    
    
           
    
    
    def main():
        src_image = "002394.jpg"
        pb_file = "ssd300_pascal_07+12_epoch-86_loss-1.2568_val_loss-0.5428.pb"
        recognize(src_image)
    
    
    
    if __name__ == '__main__':
        main()
    
    
    • TargetDetection.cpp
    /******************************************************************************
     * @file       :   TargetDetection.cpp
     * @Desctiption:   c++ 调用 SSD inferencePb.py 模块
     *
     *****************************************************************************/
    
    #include <Python.h> 
    #include <iostream>
    #include <cstring>
    #include <opencv2/opencv.hpp>
    #include <numpy/arrayobject.h> 
    #include <time.h>
    
    static void help()
    {
    	std::cout << std::endl;
    	std::cout << "This sample demostrates MobileNet-V2-SSDLite detection with tensorflow server inference." << std::endl;
    	std::cout << "Call" << std::endl;
    }
    
    
    int main(int argc, char* argv[])
    {   
        if (argc != 2) 
    	{
    		help();
    	}
        
    
        Py_Initialize();                // 初始化 Python 环境
        if (!Py_IsInitialized())
        {
            std::cout << "init faild ..." << std::endl; 
        }
        
        import_array();  // 初始化numpy
    
        // 如果查找函数文件一直是 nullptr 则加上下面两行路径
        PyRun_SimpleString("import sys");
    	PyRun_SimpleString("sys.path.append('/home/xm/project_ssd/build/')");
        
    
    	PyObject* pModule = nullptr;                               //.py文件  
        pModule = PyImport_ImportModule("inferencePb");            //调用上述路径下的inferencePb.py文件
        if (pModule == nullptr)
    	{
            std::cout << "don't find the python file!" << std::endl;
            return -1;
    	}
        
        clock_t start, end;
        for (int i=0;i<100;i++)
        {
        start = clock();
        // 这里用视频流替换传入的图像参数
        std::string image = argv[1];
        cv::Mat img = cv::imread(image);
        if (img.empty())
        {
            std::cout << "could not load image ..." << std::endl;
            return -1;
        }
    
        int m, n;
        n = img.cols *3;
        m = img.rows;
    
    
        unsigned char *data = (unsigned char*)malloc(sizeof(unsigned char) * m * n);
        int p = 0;
        for (int i = 0; i < m;i++)
        {
            for (int j = 0; j < n; j++)
            {
                data[p]= img.at<unsigned char>(i, j);
                p++;
            }
        }
    
        npy_intp Dims[2] = { m,n };  //图像的维度信息
    
        PyObject* PyArray = nullptr;
        PyArray = PyArray_SimpleNewFromData(2, Dims, NPY_UINT8, data);      //建立函数的形参
    
        PyObject* ArgArray =nullptr;
        ArgArray = PyTuple_New(1);                  //新建长度为1的元组
        PyTuple_SetItem(ArgArray, 0, PyArray);      //设置元组ArgArray[0]为PyArray图像
    
        
        PyObject* pFunc = nullptr;                  //py文件中的函数
    
        pFunc = PyObject_GetAttrString(pModule,"recognize");
        if (pFunc==nullptr)
        {
            std::cout << "can't find function recognize ... " << std::endl;
            return -1;
        }
        
        PyObject* pReturnValue;
        pReturnValue = PyObject_CallObject(pFunc, ArgArray);
        
        // 从结果中得到结果,将结果画在图像上
         
        if (pReturnValue)
        {   
            int list_len = PyObject_Size(pReturnValue);
            std::cout << list_len << std::endl;
            std::cout << "++++++++++++++++++++++++" << std::endl; // 返回 list 长度,表示检测到目标的个数 
    
            PyArrayObject *pyResultArr = (PyArrayObject *) pReturnValue;
            float *resDataArr = (float *) PyArray_DATA(pyResultArr);
    
            //int dimNum = PyArray_NDIM(pyResultArr);//返回数组的维度数,此处恒为1
            //std::cout << dimNum << std::endl;
    
            
            npy_intp *pdim = PyArray_DIMS(pyResultArr);//返回数组各维度上的元素个数值
            //std::cout << pdim << "+++++++++++++++" << pdim[1] << "+++++++++" << std::endl;
    
            for (int i = 0; i < list_len; ++i) 
            {
                for (int j = 0; j < pdim[1]; ++j)
                {   
                    std::cout << resDataArr[i*pdim[1] + j] << ", ";
                }
                std::cout << std::endl;
            }
        }
        
        end = clock();
    
        std::cout << "Time is" << (double) (end-start) / 1000000 << std::endl;
        }
        // 这张图是用来传入 下面 Python 的算法中的一张图像,需要提前处理,
        // 功能实现之后,该功能替换为海康相机 SDK 的视频流
        
        std::cout << "Finish ..." << std::endl; 
           
        Py_Finalize(); // 释放 python 环境 
        return 0;
    }
    

    六、遇到的错误

    6.1 Error: ModuleNotFoundError: No module named 'encodings'

    Could not find platform independent libraries <prefix>
    Could not find platform dependent libraries <exec_prefix>
    Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]
    Fatal Python error: Py_Initialize: Unable to get the locale encoding
    ModuleNotFoundError: No module named 'encodings'
    
    Current thread 0x00007ff4011626c0 (most recent call first):
    Aborted (core dumped)
    
    

    解决办法
    如果采用anaconda3的base环境就可以正常运行。我采用的是虚拟环境,在初始化之前需加入Py_SetPythonHome函数,如:

        Py_Initialize();
    

    变为:

       Py_SetPythonHome((wchar_t*)L"/home/zjh/anaconda3/envs/learn");
       Py_Initialize();
    

    6.2 numpy Warning:

    Warning "Using deprecated Numpy API, disable it with "
    

    解决办法
    在cpp文件最开始加入

    
    #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
    

    参考链接:

    https://docs.python.org/2/extending/embedding.html
    https://zhuanlan.zhihu.com/p/79896193
    https://blog.csdn.net/ziweipolaris/article/details/83689597
    https://blog.csdn.net/u011681952/article/details/92765549
    https://blog.csdn.net/hnlylyb/article/details/89498651

  • 相关阅读:
    苹果信息推送服务(Apple Push Notification Service)使用总结
    Xcode 相关路径总结
    微信红包随机算法 OC
    Xcode真机测试could not find developer disk image解决方法
    字典转模型 重写初始化方法
    Xcode 写代码没有补全提示解决:删缓存及显示隐藏文件命令
    按位与、或、异或等运算方法
    OC语言@property @synthesize和id
    iOS开发—Quartz2D简单介绍
    iOS开发—CoreLocation定位服务
  • 原文地址:https://www.cnblogs.com/xiaxuexiaoab/p/14471181.html
Copyright © 2011-2022 走看看