C++程序调用Python的函数(简单应用)及Ubuntu16.04下codeblocks的环境配置

今天需要在C++程序中调用Python的程序,以完成不同功能的整合,以前以为C++中调用Python程序应该比较容易,没想到今天走下来也趟了不少的坑,记录一下。

一、codeblocks的环境配置

因为我的C++程序是在Ubuntu 16.04下用codeblocks建立的工程,所以需要在codeblocks下搭一下调用Python程序时需要的环境。下面来简单介绍一下
我在网上看到了有人在windows下使用codeblocks搭调用python环境的过程(原文见 codeblock中使用C++调用python文件——西北有高楼的博客),但是Linux下却没有资料,我自己搭了一下,方便后来人。
(1)首先自己建立一个工程,右键工程名,选择Build Option,选择Search directories选项卡,在Compiler中选择添加" /usr/include/python2.7"路径,如图所示;
C++程序调用Python的函数(简单应用)及Ubuntu16.04下codeblocks的环境配置_第1张图片

(2)还是在Search directories选项卡中,选择Linker,添加“/usr/lib/python2.7”路径,如图所示
C++程序调用Python的函数(简单应用)及Ubuntu16.04下codeblocks的环境配置_第2张图片

(3)在Linker Settings选项卡中,在Link Libiaries中添加“/usr/lib/python2.7/config-x86_64-linux-gnu/libpython2.7.so”路径,如下图所示:
C++程序调用Python的函数(简单应用)及Ubuntu16.04下codeblocks的环境配置_第3张图片

至此环境搭建完成,后面可以直接写程序调用Python的程序了。

二、C++程序调用Python程序(简单方法)

在网上可以很容易的查到很多C++程序调用Python的方法,但是我的需求特别简单,只要调用我自己Python程序中的一个函数即可,所以我这里用的最简单的方法。
我要调用的Python程序如下:
其实这个程序没什么可看的,我就是训练了一个目标检测和识别的模型,然后用这个函数整合了一下,把最后的结果写到文件里。C++调用它的目的就是为了得到检测的结果,然后使用这个结果进行后续的处理,所以这个程序主要看函数名和函数的参数即可。
#coding=utf-8
#!/usr/bin/env python

'''
Created on 2017年11月20日

@author: hanchao
'''

import cv2
import numpy as np
import os
import os.path
import demo_save_detect
import classify_symbols
#其实这个函数没啥可看的,注意参数和函数名即可。
def get_detect_classify_results(imagename, symbol_label_filename, weights_filename, model_filename, resultname):
    image_name = imagename
    tmp_image = cv2.imread(image_name)
    print tmp_image.shape
    image = tmp_image
    if tmp_image.ndim == 3:
        image = cv2.cvtColor(tmp_image, cv2.COLOR_BGR2GRAY)
    detected_boxes = demo_save_detect.detect_symbols(image_name)
    images_to_recog, prob_classnum = classify_symbols.prepare_images(image, detected_boxes)
    
    transformer, net, labelnames = classify_symbols.load_modelweights(symbol_label_filename, weights_filename, model_filename)

    detect_classify_results = open(resultname, 'w')
    i = 0
    detect_classify_results.write(str(len(images_to_recog)) + '\n')
    for i in range(len(images_to_recog)):
        image = images_to_recog[i]
        bbox = detected_boxes[i]
        image = image / 255.0
        classify_result = classify_symbols.inference(image, transformer, net, labelnames)
        detect_classify_results.write(str(int(bbox[0])) + ' ' + str(int(bbox[1])) + ' ' + str(int(bbox[2])) + ' ' + str(int(bbox[3])) + ' ' + \
                                      str(classify_result[0][0]) + ' ' + str(classify_result[0][1]) + ' ' + \
                                      str(classify_result[1][0]) + ' ' + str(classify_result[1][1]) + '\n')
    detect_classify_results.close()
然后我调用的程序完全是仿照 浅析 C++ 调用 Python 模块——liuwons的博客中的方法,简单的调用了一下上面这个函数,我的调用程序如下:
#include "python2.7/Python.h"//注意一下这里,这是需要这样引入Python
#include 

using namespace std;
//程序是从上面链接的源码copy过来的,根据我的需求改动了一下。
int main()
{
    Py_Initialize();    // 初始化
    // 将Python工作路径切换到待调用模块所在目录,一定要保证路径名的正确性
    string path = "/home/hanchao/pva-faster-rcnn/tools";
    string chdir_cmd = string("sys.path.insert(0,\"") + path + "\")";//注意这里我与前面链接中代码不同,链接中代码在我这里不适用,原因未知


    const char* cstr_cmd = chdir_cmd.c_str();
    PyRun_SimpleString("import sys");
    PyRun_SimpleString(cstr_cmd);

    // 加载模块,这里是我前面那个函数所在的模块的名称
    PyObject* moduleName = PyString_FromString("detect_classify_utils"); //模块名,不是文件名
    PyObject* pModule = PyImport_Import(moduleName);
    if (!pModule) // 加载模块失败
    {
        cout << "[ERROR] Python get module failed." << endl;
        return 0;
    }
    cout << "[INFO] Python get module succeed." << endl;

    // 加载函数
    PyObject* pv = PyObject_GetAttrString(pModule, "get_detect_classify_results");
    if (!pv || !PyCallable_Check(pv))  // 验证是否加载成功
    {
        cout << "[ERROR] Can't find funftion (test_add)" << endl;
        return 0;
    }
    cout << "[INFO] Get function (test_add) succeed." << endl;

    // 设置参数
    PyObject* args = PyTuple_New(5);   // 5个参数
    PyObject* arg1 = PyString_FromString("008831.jpg");
    PyObject* arg2 = PyString_FromString("trainSymbolImage_labels.txt");
    PyObject* arg3 = PyString_FromString("conv8Net_fc_iter_202000.caffemodel");
    PyObject* arg4 = PyString_FromString("deploy.prototxt");
    PyObject* arg5 = PyString_FromString("008831.jpg_results");
    PyTuple_SetItem(args, 0, arg1);
    PyTuple_SetItem(args, 1, arg2);
    PyTuple_SetItem(args, 2, arg3);
    PyTuple_SetItem(args, 3, arg4);
    PyTuple_SetItem(args, 4, arg5);

    // 调用函数
    PyObject* pRet = PyObject_CallObject(pv, args);

    Py_Finalize();
    return 0;
}

我这里就图了个方便,完成了我的需求就行,没考虑更深入的东西,更多C++调用Python的资料可以参考 知乎——如何实现 C/C++ 与 Python 的通信?

你可能感兴趣的:(Python相关,C++)