Bootstrap

C++调用Python系列之一

任务描述:C++ 调用Python训练的TensorFlow模型(多个深度学习算法模型),封装为dll或者封装为exe文件。

调用形式:C++直接调用Python运行脚本,没有涉及各个算法间数据流的传递,保存为中间文件(.png,.txt等);

主要步骤如下:

1、获取tensorflow可以运行的python环境;2、将环境添加到VS2015工程中(当然其它版本的VS也是可以的);3、写测试主程序,然后封装为DLL、Lib;4、调用接口;

1、获取Python环境

一般用的都是虚拟环境,比如用Anaconda创建虚拟环境,然后打包整个虚拟环境,打包的方式就是复制整个文件夹。下图是我用的虚拟环境(TF35,都是用Anaconda 创建的,位置:~/Anaconda3/envs/

2、将环境添加到VS2015

当然VS其它版本也是可以的, 创建好一个空的项目后,将TF35文件夹放到新建工程的根目录(位置可以自己确定),具体添加步骤如下图所示:(1)C/C++:附加包含目录,"TF35\include";(2)链接器:附加依赖项, "TF35\libs\python35.lib";(3)调试/环境:PATH=TF35. 必须添加,否则无法成功导入环境

3、写主测试程序,封装接口

完成步骤2后,基本上已经配置好Python的虚拟环境了,主程序如下:

#include <Python.h>
#include <iostream>
#include <string>
#include <windows.h> 
#include <stdlib.h>

//extern "C" _declspec(dllexport)int DLPose()

int main()
{
	Py_SetPythonHome(L"TF35");  // 添加Python环境路径
	Py_Initialize();
	if (Py_IsInitialized())
		std::cout << "Init Success 1" << std::endl;

	PyRun_SimpleString("import sys");
	PyRun_SimpleString("sys.path.append('./')");
	PyRun_SimpleString("print(sys.version)\n");

	system("python ./merge/deal_img.py");
	system("python ./merge/KerasYolo3/yolo_video.py");
	system("python ./merge/deeplabv3/deeplabv3_demo_v3.py");
	system("python ./merge/Spine/test_v3.py");
}

注意:通常按照上面的代码,可以运行相应的深度学习算法模型,完成测试,一般运行的时候会报错:找不到python35.dll,可以按照下图设置,或者将python35.dll放到VS工程的根目录,具体可以自己尝试: 

封装为DLL,LIB:程序如下,只需更改函数名字:int main --> extern "C" _ declspec(dllexport) int DLPose(),后面的名字是标准的DLL接口,int DLPose()是自己命的函数名;

#include <Python.h>
#include <iostream>
#include <string>
#include <windows.h> 
#include <stdlib.h>

extern "C" _declspec(dllexport)int DLPose()
// int main()
{
	Py_SetPythonHome(L"TF35");  // 添加Python环境路径
	Py_Initialize();
	if (Py_IsInitialized())
		std::cout << "Init Success 1" << std::endl;

	PyRun_SimpleString("import sys");
	PyRun_SimpleString("sys.path.append('./')");
	PyRun_SimpleString("print(sys.version)\n");

	system("python ./merge/deal_img.py");
	system("python ./merge/KerasYolo3/yolo_video.py");
	system("python ./merge/deeplabv3/deeplabv3_demo_v3.py");
	system("python ./merge/Spine/test_v3.py");
    return 0;
}

当然还需要一个头文件(DLPose.h):为了方便让他人知道接口的函数名字;

#pragma once
extern "C" _declspec(dllexport)int DLPose();

还需要设置:将配置类型改为动态库(.dll)

完成上面的准备后,可以编译工程,运行结果如下,SpinEstimate.dllSpinEstimate.lib是需要的文件,Lib文件的名字和工程的名字一致;

4、调用封装的DLL

新建一个新的工程,调用上述封装好的接口,DLL和LIB,测试工程无需再添加Python环境,编译运行即可;

#include<iostream>
// #include<Python.h>
#include<windows.h>
#include"DLPose.h"
#include<stdlib.h>

int main()
{
	DLPose();  // 接口的名字,也即是要调用的函数名,没有输入参数
	return 0;
}

注意:需作如下设置,添加PATH=TF35,否则无法使用虚拟环境,当然可以还有其它的处理方式,比如像步骤2一样给测试工程添加Python环境(具体情况,具体测试!);

5、调用exe文件

如果不想调用DLL,可以将原工程直接打包成Exe文件,这样使用更加方便。只需使用默认的配置类型即可。生成后的exe文件位于~x64\Release目录下,此时可以用cmd直接运行,或者其它程序直接调用该exe文件。

注意:不管是调用DLL,或者是Exe,只要直接运行Exe文件,都会存在无法成功启动Python环境的问题,此时需要将虚拟环境添加到系统环境变量即可。具体如下图所示:

 

 

;