C++调用Python程序以及参数的相互传递(附完整代码)

以为c++为主程序,传入参数到Python环境中,进行数据处理后,获得返回值再传到主程序中。 

编译环境:VS2015,Python35, 下载的python中没有自带python35_d.lib,所以配置平台用release x64(后续如果需要会尝试补充debug版本),当然需要图像处理肯定还要用opencv的,版本3.x以上都可以

1.编写需要调用的python程序,代码如下,分别实现2个函数: Cal:实现数值计算功能,ImgProcessFromData实现从数据获得图像(函数中仅将图像显示出来,说明在Python中可以应用c++的图像数据),主要目的是实现将C++环境中获得的图像数据,传入到Python程序中进行处理,尤其在深度学习领域,Python实现更加便捷,而正常数据的采集和预处理等,C++的执行效率远高于Python,且很多实际应用中(比如一些相机的SDK)的主流还是C++。

import numpy as np
import cv2

def Cal(a,b,c,d):
    try:
     return (a+b)*c/d
    except ZeroDivisionError:
        print('divesion by zero')


def ImgProcessFromData(data):
    cv2.namedWindow('from data', cv2.WINDOW_NORMAL)
    cv2.imshow('from data',data)
    cv2.waitKey(0)

2.创建MFC对话框工程:下面也简单介绍了怎么做,懂MFC的可以直接跳过这

  • 建立MFC应用程序

  • “应用程序类型”选择基于对话框,其他不用改,直接点击完成即可

  • 添加2个按钮,分别为“数值计算”,以及“从数据获得图像”

3.配置调用环境

  • 首先要把实现对应功能的.py文件放到C++的工程文件夹里面
  • 设置包含目录,除了要包含Python本身的目录外,为了将C++的图像数据转换成numpy类型传到Python中,还行包含nump目录
  • 设置库目录
  • 添加附加依赖项
  • 到此为止,所有准备步骤的都做好了,下面就可以开始实现我们的混合编程啦,通过高效运行的C++程序进行数据采集和预处理,再让Python对图像进行方便高效的分割,分类,目标检测等等。

4.C++调用Python程序

先贴上调用Python功能的类定义及实现,主要的地方都有注释

CallPython.h

#pragma once
#include "stdafx.h"
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<fstream>
#include<Python.h>//
#include <arrayobject.h>//
#include "object.h"//这3个就是包含python和numpy的头文件
#include<string.h>
#include<vector>
#include<time.h>
#include<opencv2\opencv.hpp>
using namespace std;
using namespace cv;

class CallPy
{
public:
	CallPy();
	~CallPy();
	PyObject* pModule, *pDict, *pCal, *pImgProcessFromData;
	void PyInit(char filename[]);//初始化Python环境,加载模块和模块中的函数,filename是要调用的.py文件名
	float CalbyPy(float a, float b, float c, float d);//调用模块中的 ‘Cal’函数
	void ImgProFD(Mat img);//调用模块中的 ‘ImgProcessFromData’
private:
};

CallPython.cpp

#include "stdafx.h"
#include"CallPython.h"

int init_numpy()
{
	import_array();
}


void CallPy::PyInit(char filename[])
{
	Py_Initialize();//初始化Python环境
	init_numpy();//导入numpy库的c++版本

	PyRun_SimpleString("import sys");
	PyRun_SimpleString("sys.path.append('./')");
	if (!Py_IsInitialized())
		return ;
	pModule = PyImport_ImportModule(filename);//加载.py文件
	if (!pModule) {
		printf("Cant open python file!/n");
		return ;
	}
	pDict = PyModule_GetDict(pModule);//加载文件中的函数名
	if (!pDict)
	{
		printf("Cant find dictionary./n");
		return ;
	}
	pCal = PyDict_GetItemString(pDict, "Cal");//根据函数名获得函数功能块,‘Cal‘为Python中定义的函数名
	if (!pCal)
	{
		printf("Cant find Function. Cal /n");
	}
	pImgProcessFromData = PyDict_GetItemString(pDict, "ImgProcessFromData");//同样根据函数名获得函数功能块,‘ImgProcessFromData‘为Python中定义的函数名
	if (!pImgProcessFromData)
	{
		printf("Cant find Function. ImgProcessFromData /n");
	}
	cout << "import python model done" << endl;
	return;
}

float CallPy::CalbyPy(float a, float b, float c, float d)
{
	PyObject*args = PyTuple_New(4);//传入参数必须为Tuple类型,有几个参数,Tuple大小就为几
	PyTuple_SetItem(args, 0, Py_BuildValue("d", a));//将c++的float类型数据赋值给输入参数
	PyTuple_SetItem(args, 1, Py_BuildValue("d", b));
	PyTuple_SetItem(args, 2, Py_BuildValue("d", c));
	PyTuple_SetItem(args, 3, Py_BuildValue("d", d));
	PyObject*out = PyObject_CallObject(pCal, args);//调用函数,获得返回值
	float result = PyFloat_AsDouble(out);//将返回值转换成c++类型,就可以在后续的c++程序中应用啦
	cout <<"cal in c++:" <<result << endl;
	return result;
}

//处理图像需要先将Mat类型的数据转换成numpy类型,在赋值给传入参数的Tuple中,然后调用图像处理函数即可
void CallPy::ImgProFD(Mat img)
{
	PyObject *ArgList = PyTuple_New(1);
	auto sz = img.size();
	int x = sz.width;
	int y = sz.height;
	int z = img.channels();
	//cout << x<<" " << y <<" "<< z << endl;
	uchar *CArrays = new uchar[x*y*z];//这一行申请的内存需要释放指针,否则存在内存泄漏的问题
	int iChannels = img.channels();
	int iRows = img.rows;
	int iCols = img.cols * iChannels;
	if (img.isContinuous())
	{
		iCols *= iRows;
		iRows = 1;
	}

	uchar* p;
	int id = -1;
	for (int i = 0; i < iRows; i++)
	{
		// get the pointer to the ith row
		p = img.ptr<uchar>(i);
		// operates on each pixel
		for (int j = 0; j < iCols; j++)
		{
			CArrays[++id] = p[j];//连续空间
		}
	}

	npy_intp Dims[3] = { y, x, z }; //注意这个维度数据!
	PyObject *PyArray = PyArray_SimpleNewFromData(3, Dims, NPY_UBYTE, CArrays);
	PyTuple_SetItem(ArgList, 0, PyArray);
	PyObject_CallObject(pImgProcessFromData, ArgList);
	Py_DECREF(PyArray);
	Py_DECREF(ArgList);
}
CallPy::CallPy()
{

}
CallPy::~CallPy()
{

}
  • 对话框主程序修改:在生成的xxxDlg.cpp文件中增加以下内容

在开头处实例化调用对象: CallPy cCallPy;

在    OnInitDialog()中初始化:

    AllocConsole();//控制台调试窗口开启,主要是为了显示一些调试信息
    freopen("CONOUT$", "w+t", stdin);
    freopen("CONOUT$", "w+t", stdout);
    freopen("CONOUT$", "w+t", stderr);
    cCallPy.PyInit("BeCalled");//初始化调用对象,调用的文件为‘BeCalled.py’

在数值计算按钮函数中添加:cCallPy.CalbyPy(1, 2, 3, 4); //利用Python计算 (1+2)*3/4,获得返回值给c++主程序

在从数据获得图像按钮函数中添加:    

    Mat src = imread("1.jpg");
    namedWindow("c++", CV_WINDOW_NORMAL);
    imshow("c++", src);
    cCallPy.ImgProFD(src);

运行结果:

  • 6
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值