C++ 调用 Python(混合编程)函数的整理汇总
文章目录
- C++调用python概述
- 相关官方文档
-
相关函数
- 1.初始化python解释器环境
- 2.调用python脚本的静态简单方式
-
3.动态加载python模块并执行函数
- 3.1不带参数和返回值的举例说明
- 3.2带参数和返回值的举例说明
- 4. c++调用numpy和OpenCV
- 5.C++调用python显示图片(在python中显示)
- 6.C++调用python显示图片(在C++中显示)
- 7.C++调用python深度学习显示结果图片(在C++中显示)
- 8.将图像mat数据转换成numpy传递给python
- 9. 将视频每一帧传递给python
- 参考链接
C++调用python概述
python是一种非常强大的胶水语言,可以灵活的嵌入到c++和java等主流语言中。python提供了一套C的API库,使得开发者能够很方便的从C、C++的程序中调用python中的各个功能模块。
c++ 调用 python ,本质上是在 c++ 中启动了一个 python 解释器,由解释器对 python 相关的代码进行执行,执行完毕后释放资源,达到调用目的。
从操作步骤上看,C++调用Python低层接口可以分为几个阶段:
- 初始化Python解释器
- 从C++到Python转换数据
- 用转换后的数据做参数调用Python函数
- 把函数返回值转换为C++数据结构
说白了,即写一个C文件,执行【Python解释器初始化、导入模块,导入函数,构造输入参数,调用函数,解析返回值,终止Python解释器】。
相关官方文档
官方文档python和C相互调用
相关函数
1.初始化python解释器环境
和环境相关的接口如下:
void Py_Initialize():
初始化python解释器.C/C++中调用Python之前必须先初始化解释器
int Py_IsInitialized():
返回python解析器的是否已经初始化完成,如果已完成,返回大于0,否则返回0
void Py_Finalize() :
撤销Py_Initialize()和随后使用Python/C API函数进行的所有初始化,
并销毁自上次调用Py_Initialize()以来创建并为被销毁的所有子解释器。
2.调用python脚本的静态简单方式
int PyRun_SimpleString(const char*) :
执行一个简单的执行python脚本命令的函数
int PyRun_SimpleFile(FILE *fp, const char *filename):
从fp中把python脚本的内容读取到内容中并执行,filename应该为fp对应的文件名
方法示例:
#include "Python.h"
int main()
{
Py_Initialize(); // 初始化
PyRun_SimpleString("print('hello')");
Py_Finalize(); //释放资源
}
这种方法存在的问题:
- 把python代码当作一个字符串传给解释器来执行。
- 不管是字符串还是文件,都只能用于c++不需要像python传参,同时python不会向c++返回值的情况,只执行固定脚本的场景。
- 但是,实际的场景中是必然存在C++向python传参,python返回结果的,这个需求下我们要怎样做呢?
3.动态加载python模块并执行函数
python api提供了动态加载模块并且执行函数的能力,具体会涉及到下面几个api。
//加载模块
PyObject* PyImport_ImportModule(char *name)
PyObject* PyImport_Import(PyObject *name)
PyObject* PyString_FromString(const char*)
上面两个api都是用来动态加载python模块的。区别在于前者一个使用的是C的字符串,而后者的name是一个python对象,
这个python对象需要通过PyString_FromString(const char*)来生成,其值为要导入的模块名
//导入函数相关
PyObject* PyModule_GetDict( PyObject *module)
PyModule_GetDict()函数可以获得Python模块中的函数列表。PyModule_GetDict()函数返回一个字典。字典中的关键字为函数名,值为函数的调用地址。
字典里面的值可以通过PyDict_GetItemString()函数来获取,其中p是PyModule_GetDict()的字典,而key则是对应的函数名
PyObject* PyObject_GetAttrString(PyObject *o, char *attr_name)
PyObject_GetAttrString()返回模块对象中的attr_name属性或函数,相当于Python中表达式语句:o.attr_name
//调用函数相关
PyObject* PyObject_CallObject( PyObject *callable_object, PyObject *args)
PyObject* PyObject_CallFunction( PyObject *callable_object, char *format, ...)
使用上面两个函数可以在C程序中调用Python中的函数。callable_object为要调用的函数对象,也就是通过上述导入函数得到的函数对象,
而区别在于前者使用python的tuple来传参,后者则使用类似c语言printf的风格进行传参。
如果不需要参数,那么args可能为NULL。返回成功时调用的结果,或失败时返回NULL。
这相当于Python表达式 apply(callable_object, args) 或 callable_object(*args)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
3.1不带参数和返回值的举例说明
python脚本
#cat script/sayHello.py
def say():
print("hello")
C++代码
#include <Python.h> //C++和python混合编程的头文件
#include <iostream>
using namespace std;
int main() {
//初始化python解释器
Py_Initialize();
if (!Py_IsInitialized()) {
cout << "python init fail" << endl;
return 0;
}
//初始化python系统文件路径,保证可以访问到 .py文件
//PyRun_SimpleString:把python代码当作一个字符串传给解释器来执行。
PyRun_SimpleString("import sys");
/*把python脚本文件放入当前目录下的script文件夹下
sys.path是一个列表 list, 它里面包含了已经添加到系统的环境变量路径。
当我们要添加自己的引用模块搜索目录时,可以通过列表 list 的 append()方法;*/
PyRun_SimpleString("sys.path.append('./script')");
//PyImport_ImportModule:动态加载python模块,相当于导入python脚本文件
//调用python文件名。当前的测试python文件名是test.py。在使用这个函数的时候,只需要写文件的名称就可以了。不用写后缀。
PyObject* pModule = PyImport_ImportModule("sayHello");
if (pModule == NULL) {
cout << "module not found" << endl;
return 1;
}
/*PyObject* PyObject_GetAttrString(PyObject *o, char *attr_name)
PyObject_GetAttrString()返回模块对象中的attr_name属性或函数,
相当于Python中表达式语句:o.attr_name
相当于找到导入的python脚本文件里边的某个函数*/
PyObject* pFunc = PyObject_GetAttrString(pModule, "say");
if (!pFunc || !PyCallable_Check(pFunc)) {
cout << "not found function add_num" << endl;
return 0;
}
/*PyObject_CallObject:在C程序中调用python函数
参数1:通过导入函数获得的函数对象
参数2:被调用函数所需的参数*/
PyObject_CallObject(pFunc, NULL);
/* 撤销Py_Initialize()和随后使用Python/C API函数进行的所有初始化,
并销毁自上次调用Py_Initialize()以来创建并为被销毁的所有子解释器。*/
Py_Finalize();
return 0;
}
3.2带参数和返回值的举例说明
注意
要在release下进行否则会报错。
C++调用python程序时,出现如下问题:
无法解析的外部符号 __imp___Py_RefTotal
无法解析的外部符号 __imp___Py_NegativeRefcount
参数
在C/C++中,所有的Python类型都被声明为PyObject型,为了能够让C++能够操作python的数据,python提供了python各种数据类型和C语言数据类型的转换操作,具体的使用方法见参考链接。
在Python/C API中提供了Py_BuildValue()函数对数字和字符串进行转换处理,使之变成Python中相应的数据类型。其函数原型如下所示:
PyObject* Py_BuildValue( const char *format, ...)
Py_BuildValue()提供了类似c语言printf的参数构造方法,format是要构造的参数的类型列表,函数中剩余的参数即要转换的C语言中的整型、浮点型或者字符串等。
其返回值为PyObject型的指针。
返回值
python函数的返回值也是PyObject类型,因此,在python脚本返回到C/C++之后,需要解构Python数据为C的类型,这样C/C++程序中才可以使用Python里的数据。但是,由于python的返回值有多种数据结构类型,因此,我们需要为每个类型进行转换。
总体思路都是根据类型逐个从值从PyObject中提取。python提供了下面函数来完成这个功能
int PyArg_Parse( PyObject *args, char *format, ...)
根据format把args的值转换成c类型的值,format接受的类型和上述Py_BuildValue()的是一样的
释放资源
Python使用引用计数机制对内存进行管理,实现自动垃圾回收。在C/C++中使用Python对象时,应正确地处理引用计数,否则容易导致内存泄漏。在Python/C API中提供了Py_CLEAR()、Py_DECREF()等宏来对引用计数进行操作。
每个PyObject对象都有一个引用计数,用于垃圾回收,如果不能在恰当的时候增加(Py_INCREF)或减少(Py_DECREF)引用计数,则会发生:
- 你要访问的数据已经被释放
- 内存泄漏
当使用Python/C API中的函数创建列表、元组、字典等后,就在内存中生成了这些对象的引用计数。在对其完成操作后应该使用Py_CLEAR()、Py_DECREF()等宏来销毁这些对象。其原型分别如下所示
void Py_CLEAR(PyObject *o)
void Py_DECREF(PyObject *o)
其中,o的含义是要进行操作的对象。
对于Py_CLEAR()其参数可以为NULL指针,此时,Py_CLEAR()不进行任何操作。而对于Py_DECREF()其参数不能为NULL指针,否则将导致错误。
#include <Python.h> //C++和python混合编程的头文件
#include <iostream>
using namespace std;
int main() {
//初始化python解释器
Py_Initialize();
if (!Py_IsInitialized()) {
cout << "python init fail" << endl;
return 0;
}
//PyRun_SimpleString:把python代码当作一个字符串传给解释器来执行。
PyRun_SimpleString("import sys");
/*把python脚本文件放入当前目录下的script文件夹下
sys.path是一个列表 list, 它里面包含了已经添加到系统的环境变量路径。
当我们要添加自己的引用模块搜索目录时,可以通过列表 list 的 append()方法;*/
PyRun_SimpleString("sys.path.append('./script')");
//PyImport_ImportModule:动态加载python模块,相当于导入python脚本文件
PyObject* pModule = PyImport_ImportModule("sayHello");
if (pModule == NULL) {
cout << "module not found" << endl;
return 1;
}
/*PyObject* PyObject_GetAttrString(PyObject *o, char *attr_name)
PyObject_GetAttrString()返回模块对象中的attr_name属性或函数,
相当于Python中表达式语句:o.attr_name
相当于找到导入的python脚本文件里边的某个函数*/
PyObject* pFunc = PyObject_GetAttrString(pModule, "add_num");
if (!pFunc || !PyCallable_Check(pFunc)) {
cout << "not found function add_num" << endl;
return 0;
}
/*将参数转换为PyObject类型*/
PyObject* args = Py_BuildValue("(ii)", 5, 2);
/*PyObject_CallObject:在C程序中调用python函数
参数1:通过导入函数获得的函数对象
参数2:被调用函数所需的参数*/
PyObject* pRet = PyObject_CallObject(pFunc, args);
//释放参数内存
Py_DECREF(args);
int res = 0;
//把参数返回值转换为C类型
PyArg_Parse(pRet, "i", &res);
//释放返回值内存
Py_DECREF(pRet);
cout << res << endl;
Py_DECREF(pModule);
Py_DECREF(pFunc);
/* 撤销Py_Initialize()和随后使用Python/C API函数进行的所有初始化,
并销毁自上次调用Py_Initialize()以来创建并为被销毁的所有子解释器。*/
Py_Finalize();
return 0;
}
4. c++调用numpy和OpenCV
前言
首先要查看python的版本是release版本还是debug版本,一般安装的python都是Release版本。VS编写C++时,改为Release模式,这要与python的版本一致,否则会报错:
无法解析的外部符号 __imp___Py_RefTotal
如果将版本调整为相同的Release,则不会存在此问题。
后续见参考链接,感觉不是很全面。
5.C++调用python显示图片(在python中显示)
第一种方法:图片在python中显示,无返回值。
python代码
# opencv显示一张图片
import cv2
def show_image(img_path):
img = cv2.imread(img_path)
cv2.imshow("img-show", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == '__main__':
show_image('E:/green_screen_keying/test_set/test1.png')
C++代码
#include<iostream>
#include<Python.h>
using namespace std;
int main() {
Py_Initialize();
if (!Py_IsInitialized()) {
cout << "python initialize failed!" << endl;
return 0;
}
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./script')");
PyObject* pModule = PyImport_ImportModule("show_img");
if (pModule == NULL) {
cout << "module not found!" << endl;
return 0;
}
PyObject* pFunc = PyObject_GetAttrString(pModule, "show_image");
if (pFunc == NULL || PyCallable_Check(pFunc) == NULL) {
cout << "function not found!" << endl;
return 0;
}
PyObject* args = Py_BuildValue("(s)", "E:/green_screen_keying/test_set/test1.png");
PyObject_CallObject(pFunc, args);
Py_DECREF(pModule);
Py_DECREF(pFunc);
Py_DECREF(args);
Py_Finalize();
return 0;
}
6.C++调用python显示图片(在C++中显示)
C++使用numpy返回值的前提
环境:
- Visual Studio头文件目录:D:\Program Files\Python36\Lib\site-packages\numpy\core\include,并在代码中#include <numpy/arrayobject.h>
- 关键代码:在Py_Initialize();之后必须调用import_array();以加载所有numpy函数(C API),与加载dll类似。
C++使用opencv显示图片的前提
- Visual Studio配置包含目录,D:\Program Files\opencv3\build\include
- Visual Studio配置库目录,D:\Program Files\opencv3\build\x64\vc15\lib
- Visual Studio配置链接器输入:opencv_world341.lib
- 追加Path环境变量:Path=Path;D:\Program Files\opencv3\build\x64\vc15\bin,改完环境变量一定要重启Visual Studio才能生效。
python代码
# opencv显示一张图片
import cv2
def show_image(img_path):
img = cv2.imread(img_path)
cv2.imshow("img-show", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
def show_image_return_numpy(img_path):
img = cv2.imread(img_path)
img = cv2.resize(img, (400, 400)) # numpy类型
return img
if __name__ == '__main__':
show_image('E:/green_screen_keying/test_set/test1.png')
C++代码
#include<iostream>
#include<Python.h>
#include <numpy/arrayobject.h>//numpy的头文件
#include<opencv/cv.hpp>//opencv的头文件
using namespace cv;
using namespace std;
int main() {
Py_Initialize();
if (!Py_IsInitialized()) {
cout << "python initialize failed!" << endl;
return 0;
}
import_array();//加载numpy相关的库
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./script')");
PyObject* pModule = PyImport_ImportModule("show_img");
if (pModule == NULL) {
cout << "module not found!" << endl;
return 0;
}
PyObject* pFunc = PyObject_GetAttrString(pModule, "show_image_return_numpy");
if (pFunc == NULL || PyCallable_Check(pFunc) == NULL) {
cout << "function not found!" << endl;
return 0;
}
PyObject* args = Py_BuildValue("(s)", "E:/green_screen_keying/test_set/test1.png");
//PyObject_CallObject(pFunc, args);
PyObject* pRetValue = PyObject_CallObject(pFunc, args);
/* 解析返回结果 */
PyArrayObject* ret_array;
PyArray_OutputConverter(pRetValue, &ret_array);
//npy_intp代表数组的维度,指向数组的尺寸/形状的指针。
npy_intp* shape = PyArray_SHAPE(ret_array);
Mat imgReturn(shape[0], shape[1], CV_8UC3, PyArray_DATA(ret_array));
cv::imshow("res", imgReturn);
cv::waitKey(0);
Py_DECREF(pModule);
Py_DECREF(pFunc);
Py_DECREF(args);
Py_DECREF(pRetValue);
Py_DECREF(ret_array);
Py_Finalize();
return 0;
}
7.C++调用python深度学习显示结果图片(在C++中显示)
注意:
深度学习得到的结果转换成numpy类型是0~1之间的小数,即使*255也是float32类型,而C++生成Mat需要的是uint8的numpy类型。
python测试代码
import torch
import os
from torchvision import transforms as T
from torchvision.transforms.functional import to_pil_image
from threading import Thread
from torch.nn import functional as F
from model.model import MattingDGF
from PIL import Image
import cv2
import numpy as np
def show_image_return_numpy(img_path):
img = cv2.imread(img_path)
img = cv2.resize(img, (400, 400)) # numpy类型
return img
def test_image_c(images_src):
output_dir = "E:/VSProjects/out/"
output_types = ('pha', 'com')
device = torch.device('cuda')
# Load model
model = MattingDGF('mobilenetv2')
model = model.to(device).eval()
model.load_state_dict(torch.load("E:/green_screen_keying/deep-learning-V3-main/deep-learning-V3-main/TrainedModel"
"-V3/GSK-V3-3.pth", map_location=device))
# Worker function
def writer(img, path):
img = to_pil_image(img[0].cpu())
img.save(path)
# 读取单张图像数据
transforms = T.Compose([T.Resize((1080, 1920)), T.ToTensor()])
with Image.open(images_src) as img:
img = img.convert('RGB')
src = transforms(img)
src = src.to(device, non_blocking=True)
src = torch.unsqueeze(src, 3).permute(3, 0, 1, 2) # [B,C,H,W]
# Conversion loop
with torch.no_grad():
pred_pha_hr, pred_fgr_hr, pred_pha_lr, pred_fgr_lr, pred_err_lr = model(src)
# 转换回numpy格式
# 返回com
tgt_bgr = torch.tensor([1.0, 1.0, 1.0], device=device).view(1, 3, 1, 1)
com = pred_fgr_hr * pred_pha_hr + tgt_bgr * (1 - pred_pha_hr)
com = com.cpu().permute(2, 3, 1, 0).squeeze(3).numpy()
com = cv2.cvtColor(com, cv2.COLOR_BGR2RGB)*255
# com = cv2.resize(com, (400, 400))
# 返回pha
# pha = pred_pha_hr.cpu().permute(2, 3, 1, 0).squeeze(3).numpy()
# pha = cv2.resize(pha, (400, 400))*255
return com.astype(np.uint8)
if __name__ == "__main__":
img_src = "E:/green_screen_keying/test_set/test2.png"
pha = test_image_c(img_src) # (400,400,3) numpy
# pha = show_image_return_numpy(img_src) #(400,400,3) numpy
print(type(pha))
print(pha.shape)
print(pha.dtype)
cv2.imshow("img-show", pha)
cv2.waitKey(0)
cv2.destroyAllWindows()
C++代码
#include<iostream>
#include<Python.h>
#include <numpy/arrayobject.h>//numpy的头文件
#include<opencv/cv.hpp>//opencv的头文件
using namespace cv;
using namespace std;
int main() {
Py_Initialize();
if (!Py_IsInitialized()) {
cout << "python initialize failed!" << endl;
return 0;
}
import_array();//加载numpy相关的库
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./script/code-V3')");
PyObject* pModule = PyImport_ImportModule("test_image_C++");
if (pModule == NULL) {
cout << "module not found!" << endl;
return 0;
}
PyObject* pFunc = PyObject_GetAttrString(pModule, "test_image_c");
if (pFunc == NULL || PyCallable_Check(pFunc) == NULL) {
cout << "function not found!" << endl;
return 0;
}
PyObject* args = Py_BuildValue("(s)", "E:/green_screen_keying/test_set/test2.png");
PyObject* pRetValue = PyObject_CallObject(pFunc, args);
/* 解析返回结果 */
PyArrayObject* ret_array;
PyArray_OutputConverter(pRetValue, &ret_array);
npy_intp* shape = PyArray_SHAPE(ret_array);
Mat mat(shape[0], shape[1], CV_8UC3, PyArray_DATA(ret_array));
cv::imshow("res", mat);
cv::waitKey(0);
Py_DECREF(pModule);
Py_DECREF(pFunc);
Py_DECREF(args);
Py_DECREF(ret_array);
//Py_DECREF(pRetValue);
Py_Finalize();
return 0;
}
C++接收python返回的numpy的list
#include<iostream>
#include<Python.h>
#include <numpy/arrayobject.h>//numpy的头文件
#include<opencv/cv.hpp>//opencv的头文件
using namespace cv;
using namespace std;
int main() {
Py_Initialize();
if (!Py_IsInitialized()) {
cout << "python initialize failed!" << endl;
return 0;
}
import_array();//加载numpy相关的库
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./script/code-V3')");
PyObject* pModule = PyImport_ImportModule("test_image_C++");
if (pModule == NULL) {
cout << "module not found!" << endl;
return 0;
}
PyObject* pFunc = PyObject_GetAttrString(pModule, "test_image_c");
if (pFunc == NULL || PyCallable_Check(pFunc) == NULL) {
cout << "function not found!" << endl;
return 0;
}
PyObject* args = Py_BuildValue("(s)", "E:/green_screen_keying/test_set/test2.png");
PyObject* pRetValue = PyObject_CallObject(pFunc, args);
/* 解析返回结果 */
PyArrayObject* array_com,*array_pha;
PyArray_OutputConverter(PyList_GetItem(pRetValue, 0), &array_com);
PyArray_OutputConverter(PyList_GetItem(pRetValue, 1), &array_pha);
npy_intp* shape = PyArray_SHAPE(array_com);
Mat com(shape[0], shape[1], CV_8UC3, PyArray_DATA(array_com));
Mat pha(shape[0], shape[1], CV_8UC1, PyArray_DATA(array_pha));
cv::imshow("com", com);
cv::waitKey(0);
cv::imshow("pha", pha);
cv::waitKey(0);
Py_DECREF(pModule);
Py_DECREF(pFunc);
Py_DECREF(args);
Py_DECREF(array_com);
Py_DECREF(array_pha);
//Py_DECREF(pRetValue);
Py_Finalize();
return 0;
}
8.将图像mat数据转换成numpy传递给python
注意:
C++那里输入的图像参数必须得是tuple类型的参数,即使只有一个图像参数。
python代码
import cv2
def simple_func(a,b):return a+b
def super_resolution(img, scale=4):
height, width = img.shape[:2]
dsize = (width*scale, height*scale)
big_img = cv2.resize(img, dsize)
return big_img
C++代码
#include <Python.h>
#include <iostream>
#include <numpy/arrayobject.h>
#include<opencv/cv.hpp>
using namespace std;
using namespace cv;
int main() {
Py_Initialize();
import_array();
/* 读图 */
Mat sml_img = imread("E:/green_screen_keying/test_set/test2.png");
/* 导入模块和函数 */
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./script')");
PyObject* pName = PyUnicode_DecodeFSDefault("simple_module");
PyObject* pModule = PyImport_Import(pName);
PyObject* pFunc = PyObject_GetAttrString(pModule, "super_resolution");
/* 准备输入参数 */
PyObject* pArgs = PyTuple_New(2);
npy_intp dims[] = { sml_img.rows, sml_img.cols, sml_img.channels() };
//生成包含这个多维数组的PyObject对象,使用PyArray_SimpleNewFromData函数,
//第一个参数2表示维度,第二个为维度数组Dims,第三个参数指出数组的类型,第四个参数为数组
PyObject* pValue = PyArray_SimpleNewFromData(3, dims, NPY_UINT8, sml_img.data);
PyTuple_SetItem(pArgs, 0, pValue); /* pValue的引用计数被偷偷减一,无需手动再减 */
PyTuple_SetItem(pArgs, 1, Py_BuildValue("i", 3)); /* 图像放大4倍 */
/* 调用函数 */
PyObject* pRetValue = PyObject_CallObject(pFunc, pArgs);
/* 解析返回结果 */
PyArrayObject* ret_array;
PyArray_OutputConverter(pRetValue, &ret_array);
npy_intp* shape = PyArray_SHAPE(ret_array);
Mat big_img(shape[0], shape[1], CV_8UC3, PyArray_DATA(ret_array));
cv::imshow("res", big_img);
cv::waitKey(0);
/* 释放所有 */
Py_DECREF(pName);
Py_DECREF(pModule);
Py_DECREF(pFunc);
Py_DECREF(pArgs);
Py_DECREF(pValue);
Py_DECREF(pRetValue);
Py_Finalize();
return 0;
}
9. 将视频每一帧传递给python
注意:
不要再循环内Py_DECREF
python代码
import torch
import os
from torchvision import transforms as T
from torchvision.transforms.functional import to_pil_image
from threading import Thread
from torch.nn import functional as F
from model.model import MattingDGF
from PIL import Image
import cv2
import numpy as np
def load_model():
global device, model
device = torch.device('cuda')
# Load model
model = MattingDGF('mobilenetv2')
model = model.to(device).eval()
model.load_state_dict(torch.load("E:/green_screen_keying/deep-learning-V3-main/deep-learning-V3-main/TrainedModel"
"-V3/GSK-V3-3.pth", map_location=device))
def test_image_c(img):
# 读取单张图像数据
transforms = T.Compose([T.Resize((1080, 1920)), T.ToTensor()])
# with Image.open(images_src) as img:
# img = img.convert('RGB')
img = Image.fromarray(img) # numpy 转 PIL image类
src = transforms(img)
src = src.to(device, non_blocking=True)
src = torch.unsqueeze(src, 3).permute(3, 0, 1, 2) # [B,C,H,W]
# Conversion loop
with torch.no_grad():
pred_pha_hr, pred_fgr_hr, pred_pha_lr, pred_fgr_lr, pred_err_lr = model(src)
# 转换回numpy格式
# 返回com
tgt_bgr = torch.tensor([1.0, 1.0, 1.0], device=device).view(1, 3, 1, 1)
com = pred_fgr_hr * pred_pha_hr + tgt_bgr * (1 - pred_pha_hr)
com = com.cpu().permute(2, 3, 1, 0).squeeze(3).numpy()
com = cv2.cvtColor(com, cv2.COLOR_BGR2RGB)
com = cv2.resize(com, (400, 400)) * 255
# 返回pha
pha = pred_pha_hr.cpu().permute(2, 3, 1, 0).squeeze(3).numpy()
pha = cv2.resize(pha, (400, 400)) * 255
# return com.astype(np.uint8)
return [com.astype(np.uint8), pha.astype(np.uint8)]
if __name__ == "__main__":
img_src = "E:/green_screen_keying/test_set/test2.png"
img = cv2.imread(img_src)
load_model()
com, pha = test_image_c(img) # (400,400,3) numpy
# pha = show_image_return_numpy(img_src) #(400,400,3) numpy
# print(type(pha))
# print(pha.shape)
# print(pha.dtype)
cv2.imshow("img-show", pha)
cv2.waitKey(0)
cv2.destroyAllWindows()
C++代码
#include<iostream>
#include<Python.h>
#include <numpy/arrayobject.h>//numpy的头文件
#include<opencv/cv.hpp>//opencv的头文件
using namespace cv;
using namespace std;
int main() {
Py_Initialize();
if (!Py_IsInitialized()) {
cout << "python initialize failed!" << endl;
return 0;
}
import_array();//加载numpy相关的库
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./script/code-V3')");
PyObject* pModule = PyImport_ImportModule("test_image_C++");
if (pModule == NULL) {
cout << "module not found!" << endl;
return 0;
}
/*加载模型*/
PyObject* pFunc_load = PyObject_GetAttrString(pModule, "load_model");
if (pFunc_load == NULL || PyCallable_Check(pFunc_load) == NULL) {
cout << "function not found!" << endl;
return 0;
}
PyObject_CallObject(pFunc_load, NULL);
PyObject* pFunc = PyObject_GetAttrString(pModule, "test_image_c");
if (pFunc == NULL || PyCallable_Check(pFunc) == NULL) {
cout << "function not found!" << endl;
return 0;
}
/* 准备输入参数 */
//读入图片
//Mat img = imread("E:/green_screen_keying/test_set/test2.png");
//读入视频
VideoCapture capture;
capture.open("E:/green_screen_keying/test_video_13/test_videos/chizi.mp4");
if (!capture.isOpened())
{
printf("can not open ...\n");
return -1;
}
Mat img;
PyObject* pValue=NULL, *pArgs=NULL,*pRet = NULL;
PyArrayObject* array_com = NULL, * array_pha = NULL;
while (capture.read(img)){
cv::cvtColor(img, img, cv::COLOR_BGR2RGB);
npy_intp dims[] = { img.rows, img.cols, img.channels() };
//PyArray_SimpleNewFromData可以将void*的数据转换成np.ndarray
pValue = PyArray_SimpleNewFromData(3, dims, NPY_UINT8, img.data);
pArgs = PyTuple_New(1);
PyTuple_SetItem(pArgs, 0, pValue); /* pValue的引用计数被偷偷减一,无需手动再减 */
//PyTuple_SetItem(pArgs, 1, Py_BuildValue("i", 3));
pRet = PyObject_CallObject(pFunc, pArgs);
// 解析返回结果
//PyArrayObject* array_com, * array_pha;
PyArray_OutputConverter(PyList_GetItem(pRet, 0), &array_com);
PyArray_OutputConverter(PyList_GetItem(pRet, 1), &array_pha);
npy_intp* shape = PyArray_SHAPE(array_com);
Mat com(shape[0], shape[1], CV_8UC3, PyArray_DATA(array_com));
Mat pha(shape[0], shape[1], CV_8UC1, PyArray_DATA(array_pha));
cv::imshow("com", com);
cv::waitKey(10);
/*
cv::imshow("pha", pha);
cv::waitKey(0);
*/
com.release();
pha.release();
img.release();
}
Py_DECREF(pValue);
Py_DECREF(pRet);
Py_DECREF(pArgs);
Py_DECREF(pModule);
Py_DECREF(pFunc_load);
Py_DECREF(pFunc);
Py_DECREF(array_com);
Py_DECREF(array_pha);
//Py_DECREF(pRetValue);
capture.release();
Py_Finalize();
return 0;
}
继续更新中…
参考链接
C++调用python脚本
C++调用numpy和OpenCV
C++调用python时opencv和numpy的转换和使用
推荐阅读
-
C++ 调用 Python(混合编程)函数的整理汇总
-
包婷婷 (201550484)作业一 统计软件简介与数据操作-SPSS(Statistical Product and Service Solutions),"统计产品与服务解决方案"软件。最初软件全称为"(SolutionsStatistical Package for the Social Sciences),但是随着SPSS产品服务领域的扩大和服务深度的增加,SPSS公司已于2000年正式将英文全称更改为"统计产品与服务解决方案",标志着SPSS的战略方向正在做出重大调整。为IBM公司推出的一系列用于统计学分析运算、数据挖掘、预测分析和决策支持任务的软件产品及相关服务的总称SPSS,有Windows和Mac OS X等版本。 1984年SPSS总部首先推出了世界上第一个统计分析软件微机版本SPSS/PC+,开创了SPSS微机系列产品的开发方向,极大地扩充了它的应用范围,并使其能很快地应用于自然科学、技术科学、社会科学的各个领域。世界上许多有影响的报刊杂志纷纷就SPSS的自动统计绘图、数据的深入分析、使用方便、功能齐全等方面给予了高度的评价。 R统计软件介绍 R是一套完整的数据处理、计算和制图软件系统。其功能包括:数据存储和处理系统;数组运算工具(其向量、矩阵运算方面功能尤其强大);完整连贯的统计分析工具;优秀的统计制图功能;简便而强大的编程语言:可操纵数据的输入和输出,可实现分支、循环,用户可自定义功能。 与其说R是一种统计软件,还不如说R是一种数学计算的环境,因为R并不是仅仅提供若干统计程序、使用者只需指定数据库和若干参数便可进行一个统计分析。R的思想是:它可以提供一些集成的统计工具,但更大量的是它提供各种数学计算、统计计算的函数,从而使使用者能灵活机动的进行数据分析,甚至创造出符合需要的新的统计计算方法。 该语言的语法表面上类似 C,但在语义上是函数设计语言(functional programming language)的变种并且和Lisp 以及 APL有很强的兼容性。特别的是,它允许在"语言上计算"(computing on the language)。这使得它可以把表达式作为函数的输入参数,而这种做法对统计模拟和绘图非常有用。 R是一个免费的*软件,它有UNIX、LINUX、MacOS和WINDOWS版本,都是可以免费下载和使用的。在R主页那儿可以下载到R的安装程序、各种外挂程序和文档。在R的安装程序中只包含了8个基础模块,其他外在模块可以通过CRAN获得。 二、R语言 R是用于统计分析、绘图的语言和操作环境。R是属于GNU系统的一个*、免费、源代码开放的软件,它是一个用于统计计算和统计制图的优秀工具。 R作为一种统计分析软件,是集统计分析与图形显示于一体的。它可以运行于UNIX,Windows和Macintosh的操作系统上,而且嵌入了一个非常方便实用的帮助系统,相比于其他统计分析软件,R还有以下特点: 1.R是*软件。这意味着它是完全免费,开放源代码的。可以在它的网站及其镜像中下载任何有关的安装程序、源代码、程序包及其源代码、文档资料。标准的安装文件身自身就带有许多模块和内嵌统计函数,安装好后可以直接实现许多常用的统计功能。[2] 2.R是一种可编程的语言。作为一个开放的统计编程环境,语法通俗易懂,很容易学会和掌握语言的语法。而且学会之后,我们可以编制自己的函数来扩展现有的语言。这也就是为什么它的更新速度比一般统计软件,如,SPSS,SAS等快得多。大多数最新的统计方法和技术都可以在R中直接得到。[2] 3. 所有R的函数和数据集是保存在程序包里面的。只有当一个包被载入时,它的内容才可以被访问。一些常用、基本的程序包已经被收入了标准安装文件中,随着新的统计分析方法的出现,标准安装文件中所包含的程序包也随着版本的更新而不断变化。在另外版安装文件中,已经包含的程序包有:base一R的基础模块、mle一极大似然估计模块、ts一时间序列分析模块、mva一多元统计分析模块、survival一生存分析模块等等.[2] 4.R具有很强的互动性。除了图形输出是在另外的窗口处,它的输入输出窗口都是在同一个窗口进行的,输入语法中如果出现错误会马上在窗口口中得到提示,对以前输入过的命令有记忆功能,可以随时再现、编辑修改以满足用户的需要。输出的图形可以直接保存为JPG,BMP,PNG等图片格式,还可以直接保存为PDF文件。另外,和其他编程语言和数据库之间有很好的接口。[2] 5.如果加入R的帮助邮件列表一,每天都可能会收到几十份关于R的邮件资讯。可以和全球一流的统计计算方面的专家讨论各种问题,可以说是全世界最大、最前沿的统计学家思维的聚集地.[2] R是基于S语言的一个GNU项目,所以也可以当作S语言的一种实现,通常用S语言编写的代码都可以不作修改的在R环境下运行。 R的语法是来自Scheme。R的使用与S-PLUS有很多类似之处,这两种语言有一定的兼容性。S-PLUS的使用手册,只要稍加修改就可作为R的使用手册。所以有人说:R,是S-PLUS的一个“克隆”。 但是请不要忘了:R是免费的(R is free)。R语言源代码托管在github,具体地址可以看参考资料。[3] 。 R语言的下载可以通过CRAN的镜像来查找。 R语言有域名为.cn的下载地址,有六个,其中两个由Datagurn,由 中国科学技术大学提供的。R语言Windows版,其中由两个下载地点是Datagurn和 USTC提供的。 三、stata Stata 是一套提供其使用者数据分析、数据管理以及绘制专业图表的完整及整合性统计软件。它提供许许多多功能,包含线性混合模型、均衡重复反复及多项式普罗比模式。用Stata绘制的统计图形相当精美。 新版本的STATA采用最具亲和力的窗口接口,使用者自行建立程序时,软件能提供具有直接命令式的语法。Stata提供完整的使用手册,包含统计样本建立、解释、模型与语法、文献等超过一万余页的出版品。 除此之外,Stata软件可以透过网络实时更新每天的最新功能,更可以得知世界各地的使用者对于STATA公司提出的问题与解决之道。使用者也可以透过Stata. Journal获得许许多多的相关讯息以及书籍介绍等。另外一个获取庞大资源的管道就是Statalist,它是一个独立的listserver,每月交替提供使用者超过1000个讯息以及50个程序。 四、PYTHON
-
[风云变幻编程 - python 语法] 第 9 级(喊出我的名字) - 定义和调用函数 - 注释
-
混合编程:如何用 python11 调用 C++
-
理解C++编程中的stol和stoll函数:在函数调用中如何进行字符串转换