Python 中如何使用pybind11调用C++

news2024/11/25 4:50:16

Python 中如何使用pybind11调用C++

  • 1. pybind11简介与环境安装
  • 2. 求和函数
  • 3. STL和python内建数据类型的对应关系
    • 3.1 **返回vector**
    • 3.2 **返回struct**
  • 4. pybind11与numpy图像数据接口和速度对比:以图像rgb转化为gray的例子

Reference:

  1. 混合编程:如何用pybind11调用C++
  2. pybind11 — Seamless operability between C++11 and Python(这个官方文档更清晰)
  3. Ubuntu pybind11教程

在实际开发过程中,免不了涉及到混合编程,比如,对于python这种脚本语言,性能还是有限的,在一些对性能要求高的情景下面,还是需要使用c/c++来完成。那怎样做呢?我们能使用pybind11作为桥梁,pybind11的优点是对C++ 11支持很好,API比较简单,现在我们就简单记下Pybind11的入门操作。

1. pybind11简介与环境安装

Pybind11 是一个轻量级只包含头文件的库,用于 Python 和 C++ 之间接口转换,可以为现有的 C++ 代码创建 Python 接口绑定。Pybind11 通过 C++ 编译时的自省来推断类型信息,来最大程度地减少传统拓展 Python 模块时繁杂的样板代码, 已经实现了 STL 数据结构、智能指针、类、函数重载、实例方法等到Python的转换,其中函数可以接收和返回自定义数据类型的值、指针或引用

直接使用pip安装

pip3 install pybind11

由于pybind11依赖于pytest,所以在安装前需要先把pytest给安装上

pip3 install pytest

2. 求和函数

首先,我们编写一个C++源文件,命名为example.cpp

// pybind11 头文件和命名空间
#include <pybind11/pybind11.h>
namespace py = pybind11;

int add(int i, int j)
{
    return i + j;
}

PYBIND11_MODULE(example, m)
{
    // 可选,说明这个模块是做什么的
    m.doc() = "pybind11 example plugin";
    //def("给python调用方法名", &实际操作的函数, "函数功能说明",默认参数). 其中函数功能说明为可选
    m.def("add", &add, "A function which adds two numbers", py::arg("i")=1, py::arg("j")=2);
}

PYBIND11_MODULE()宏函数将会创建一个函数,在由Python发起import语句时该函数将会被调用。模块名字“example”,由宏的第一个参数指定(千万不能出现引号)。第二个参数"m",定义了一个py::module的变量。函数py::module::def()生成绑定代码,将add()函数暴露给Python。(py::module::def()的最后两个参数:py::arg(“i”)=1, py::arg(“j”)=2,是给函数添加默认值的)

我们使用CMake进行编译。首先写一个CMakeLists.txt。

cmake_minimum_required(VERSION 3.1)
project(example)

add_subdirectory(pybind11)
pybind11_add_module(example example.cpp)

就是CMakeList.txt和example.cpp放在一个目录下面。

cmake .
make

会生成example.cpython-36m-x86_64-linux-gnu.so文件。

这个文件就是python可以调用的文件。还是在相同目录下运行python,进入python命令行

import example
example.add(3, 4)
[out]: 7

更推荐的用法是:

import os,sys
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from lib import example

if __name__ == "__main__":
    output = example.add()
    print(output)

3. STL和python内建数据类型的对应关系

在使用python编程时,常使用内建容器作为函数的参数和返回值,python语言的这种特性使我们的程序变得非常灵活和易于理解。那么在使用pybind11封装C++实现的函数的时候,如何保留这一特性呢?下面介绍pybind11实现list和dict作为参数及返回值的方法。

C++ STLPython
std::vectorlist
std::arraylist
std::mapdict
std::setset

3.1 返回vector

//文件名:func.cpp  
#include "func.h"  
  
vector<long> list_square(vector<long> &in_list, vector<long>& out_list){  
    vector<long>::iterator iter;  
    for(iter = in_list.begin(); iter != in_list.end(); iter++){  
        out_list.push_back(*iter * *iter);  
    }  
    return out_list;  
}  
  
map<string, long> dict_square(map<string, long>& in_dict, map<string, long>& out_dict){  
    map<string, long>::iterator iter;  
    iter = in_dict.begin();  
    while(iter != in_dict.end()){  
        out_dict.insert({iter->first, iter->second * iter->second});  
        iter++;  
    }  
    return out_dict;  
}
  • 写pybind11封装函数
//文件名:func_wrapper.cpp  
#include <pybind11/pybind11.h>  
#include<pybind11/stl.h>  
#include "func.h"  
  
PYBIND11_MODULE(square, m){  
    m.doc() = "Square the members of the container";  
    m.def("list_square", &list_square);  
    m.def("dict_square", &dict_square);  
}

3.2 返回struct

#include <pybind11/pybind11.h>
#include <iostream>
struct Foo {
    std::string a;
};

void show(Foo f) {
    std::cout << f.a << std::endl;
}

namespace py = pybind11;

PYBIND11_PLUGIN(example) {
    py::module m("example", "pybind11 example plugin");

    m.def("show", &show, "Prints a");
    py::class_<Foo>(m, "Foo")
    .def_readwrite("a",    &Foo::a);

    return m.ptr();
}
  • 写pybind11封装函数
import sys
sys.path.append(".")
import example

b = example.Foo
b.a = "Hello"
example.show(b)

4. pybind11与numpy图像数据接口和速度对比:以图像rgb转化为gray的例子

  1. 编写pybind11的C++代码:
#include<iostream>
#include<pybind11/pybind11.h>
#include<pybind11/numpy.h>
namespace py=pybind11;
py::array_t<double> rgb_to_gray(py::array_t<unsigned char>& img_rgb)
{
	if(img_rgb.ndim()!=3)
	{
		throw std::runtime_error("RGB image must has 3 channels!");
	}
	py::array_t<unsigned char> img_gray=py::array_t<unsigned char>(img_rgb.shape()[0]*img_rgb.shape()[1]);
	img_gray.resize({img_rgb.shape()[0],img_rgb.shape()[1]});
	auto rgb=img_rgb.unchecked<3>();
	auto gray=img_gray.mutable_unchecked<2>();
	for(int i=0;i<img_rgb.shape()[0];i++)
	{
		for(int j=0;j<img_rgb.shape()[1];j++)
		{
			auto R=rgb(i,j,0);
			auto G=rgb(i,j,1);
			auto B=rgb(i,j,2);
			auto GRAY=(R*30+G*59+B*11+50)/100;
			gray(i,j)=static_cast<unsigned char>(GRAY);
		}
	}
	return img_gray;
}
PYBIND11_MODULE(example,m)
{
	m.doc()="simple demo";
	m.def("rgb_to_gray",&rgb_to_gray);
}
  1. 编写CMakeList.txt:
cmake_minimum_required(VERSION 3.1)
project(example)
 
add_subdirectory(pybind11)
pybind11_add_module(example example.cpp)
  1. 与rgb换成gray的python代码速度和cv2自带的cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)对比:
    a. python代码
import cv2
import time
import numpy as np
def rgb_to_gray(img_rgb):
        if img_rgb.shape[2]!=3:
                print('image channels is 3')
        h,w,c=img_rgb.shape
        gray=np.zeros(shape=(h,w),dtype=np.uint8)
        for i in range(h):
                for j in range(w):
                        R=img_rgb[i,j,0]
                        G=img_rgb[i,j,1]
                        B=img_rgb[i,j,2]
                        GRAY=(R*30+G*59+B*11+50)/100
                        gray[i,j]=np.uint8(GRAY)
        return gray

b. 对比pybind11 c++的速度:

import cv2
import example
import time
import numpy as np
def rgb_to_gray(img_rgb):
	if img_rgb.shape[2]!=3:
		print('image channels is 3')
	h,w,c=img_rgb.shape
	gray=np.zeros(shape=(h,w),dtype=np.uint8)
	for i in range(h):
		for j in range(w):
			R=img_rgb[i,j,0]
			G=img_rgb[i,j,1]
			B=img_rgb[i,j,2]
			GRAY=(R*30+G*59+B*11+50)/100
			gray[i,j]=np.uint8(GRAY)
	return gray
img_rgb=cv2.imread("lena.png")
for i in range(1000):
	t1=time.clock()
	rgb_to_gray(img_rgb)
	t2=time.clock()
	print("python time:{}/s".format(t2-t1))
	print("...................................")
	t1=time.clock()
	example.rgb_to_gray(img_rgb)
	t2=time.clock()
	print("pybind11 time:{}/s".format(t2-t1))
	print("...................................")
	t1=time.clock()
	cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
	t2=time.clock()
	print("cv2.cvtColor time:{}/s".format(t2-t1))
	print("...................................")

c. 结果和分析:
在这里插入图片描述

分析,用python直接写的速度最慢,cv2自带的函数最快,结论,像素级别的操作,能用cv2自带的函数就用,如果cv2没有,那就用pybind11编写c++代码转换为python API接口,像素级别的处理,python太慢了,根本原因是python的for效率太低了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/89361.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

银联卡8583协议小额免密免签交易总结

之前做过金融支付这块儿。到过北京石景山区银行卡检测中心过检PBOC的level&#xff12;认证&#xff0c;去过上海银联总部和湖南银联对接银联卡和扫码支付。对金融支付和卡交易这块儿熟悉。现在这块儿知识用不上了总结下留作备忘&#xff0c;同时分享给有需要的人。 关于免密免…

【云原生 | Kubernetes 实战】12、K8s 四层代理 Service 入门到企业实战应用(下)

目录 一、创建 Service&#xff1a;type 类型是 NodePort 1.1 创建一个 pod 资源 1.2 创建 service&#xff0c;代理 pod 在集群外访问 service&#xff1a; 数据转发流程&#xff1a; 二、创建 Service&#xff1a;type 类型是 ExternalName 2.1 创建 pod 2.2 创建…

相关数据库

h2 需要用以下 初始化一下 第一次启动需要加入下面代码 h2 创建表 可以直接用jdbc 然后进行测试 不需要链接mysql redis 想要启动redis 现在 该目录下 输入俩个cmd 一个cmd 输入redis-cli 到启动太 输入 shutdown 然后再另一个cmd 输入 redis-server.exe redis.windows.con…

如何利用电商模式,灵活结合当地产品生态全力助农,实现乡村振兴

随着互联网时代的发展&#xff0c;人们的消费观念和消费习惯逐渐被改变&#xff0c;绿色环保观念深入人心&#xff0c;人们加大了对农产品的高要求和高需求&#xff0c;同时&#xff0c;近年来国家对农业的重视和政策支持&#xff0c;促进了农产品电商的蓬勃发展&#xff0c;已…

YOLOV7学习记录之原理+代码介绍

博主计划做一个目标检测跟踪项目&#xff0c;考虑使用YOLO系列模型来作为目标检测器&#xff0c;如今YOLO项目已经更新到了YOLOV7版本&#xff0c;因此便来学习一下相关原理&#xff0c;完成相关实验工作。 论文链接&#xff1a;https://arxiv.org/abs/2207.02696 网络结构 YO…

【字节码】Java Instrumentation 简介 以及 ASM 组合案例

1.概述 本文来自:深入理解JVM字节码 并且对其进行补充。 2.Java Instrumentation简介 JDK从1.5版本开始引人了java.lang.instrument 包,开发者可以更方便的实现字节码增强。其核心功能由java.lang.instrument.Instrumentation 提供,这个接口的方法提供了注册类文件转换器…

python列表添加元素append(),extend(),insert(),+list的区别及说明

这篇文章主要介绍了python列表添加元素append(),extend(), insert(),list的区别及说明&#xff0c;具有很好的参考价值&#xff0c;希望对大家有所帮助。 列表添加元素append(),extend(),insert(),list区别 回忆初学python的时候&#xff0c;对列表list添加元素时&#xff0c…

[附源码]Nodejs计算机毕业设计基于web技术的米其林轮胎管理系统Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分…

C# 程序的组织

一 程序的组织 ① 名字控件 程序的逻辑组织&#xff1b; ② 嵌套类型 类中嵌套类型&#xff1b; ③ 程序集 程序的物理组织&#xff1b; 二 名字空间 1 名字控件的概念 逻辑划分&#xff1b;避免名字冲突&#xff1b; 2 名字空间的声明 namespace xxx.xxxxx{} 可嵌套 3 …

Jmeter 性能测试之阶梯式场景、波浪式场景

推荐阅读&#xff1a; [内部资源] 想拿年薪30W的软件测试人员&#xff0c;这份资料必须领取~ Python自动化测试全栈性能测试全栈&#xff0c;挑战年薪40W 1 阶梯式场景&#xff08;负载测试&#xff09; 该场景主要应用在负载测试里面&#xff0c;通过设定一定的并发线程数…

云游戏拉开产业化大幕

配图来自Canva可画 在过去十多年间&#xff0c;音乐和视频已经完成了线下存储到线上串流的变迁&#xff0c;VCD、CD、MP3也早已成为有历史记忆的收藏品&#xff0c;然而游戏业的“革命”——云游戏行业才刚刚开始。 尤其是随着5G和边缘计算的发展&#xff0c;更高的带宽、更低…

cubeIDE开发, 定时器TIM与外部中断NVIC实践案例

一、定时器功能 1.1 定时器分类 STM32 的定时器分为高级定时器、 通用定时器 、基本定时器三种。 这三个定时器成上下级的关系&#xff0c;即基本定时器有的功能通用定时器都有&#xff0c;而且还增加了向下、向上/向下计数器、PWM生成、输出比较、输入捕获等功能&#xff1b;而…

高并发编程之多线程锁和CallableFuture 接口

5 多线程锁 5.1 锁的八个问题演示 package com.xingchen.sync;import java.util.concurrent.TimeUnit;class Phone {public static synchronized void sendSMS() throws Exception {//停留4秒TimeUnit.SECONDS.sleep(4);System.out.println("------sendSMS");}publ…

AXI协议规范超详细中文总结版

link AXI协议规范中文翻译版 来源&#xff1a;https://github.com/lizhirui/AXI_spec_chinese 综述 本文参考分析整理总结了AMBA AXI and ACE Protocol Specification文档的AXI总线协议规范部分&#xff0c;错误之处欢迎指出。 AMBA AXI协议支持高性能高频的系统设计&#xff0…

【视觉高级篇】25 # 如何用法线贴图模拟真实物体表面

说明 【跟月影学可视化】学习笔记。 什么是法线贴图&#xff1f; 法线贴图就是在原物体的凹凸表面的每个点上均作法线&#xff0c;通过RGB颜色通道来标记法线的方向&#xff0c;你可以把它理解成与原凹凸表面平行的另一个不同的表面&#xff0c;但实际上它又只是一个光滑的平…

巧用 Chrome:网络知多少

开发者如数家珍的工具中&#xff0c;Chrome 想必是众多人心目中的白月光&#xff0c;倒也不是它有多么优秀&#xff0c;而是多亏同行浏览器们的衬托。其开源的内核 Chromium 也成就众多养家糊口的岗位&#xff0c;比如 Edge、Opera、QQ 浏览器、360 浏览器等等国内外一票浏览器…

物联网开发笔记(62)- 使用Micropython开发ESP32开发板之控制ILI9341 3.2寸TFT-LCD触摸屏进行LVGL图形化编程:环境搭建

一、目的 这一节我们学习如何使用我们的ESP32开发板来控制ILI9341 3.2寸TFT-LCD触摸屏进行LVGL图形化编程的第一步&#xff1a;环境搭建。 关键字&#xff1a;3.2寸SPI串口TFT液晶显示屏模块 ILI9341驱动 LCD触摸屏 240*320 LVGL图形化编程 XPT2046触摸屏芯片IC 二、环境 ESP…

实机安装CentOS7.9操作系统图文(保姆级)教程

一、制作启动U盘 1、下载Ventoy软件 去Ventoy官网下载Ventoy软件&#xff08;Download . Ventoy&#xff09;如下图界面 ​ 2、制作启动盘 选择合适的版本以及平台下载好之后&#xff0c;进行解压&#xff0c;解压出来之后进入文件夹&#xff0c;如下图左边所示&#xff0c…

Hive 之数据透视表

文章目录什么是数据透视表&#xff1f;创建数据源基于各产品在各个平台半年内的月销售额与汇总&#xff0c;制作数据透视表什么是数据透视表&#xff1f; 数据透视表是一种工具&#xff0c;用于帮助用户理解和分析大量数据。它通常是一个二维表格&#xff0c;可以让用户以不同…

java计算机毕业设计springboot+vue航空公司电子售票系统-机票预订系统

项目介绍 通篇文章的撰写基础是实际的应用需要,然后在架构系统之前全面复习大学所修习的相关知识以及网络提供的技术应用教程,以远程教育系统的实际应用需要出发,架构系统来改善现远程教育系统工作流程繁琐等问题。不仅如此以操作者的角度来说,该系统的架构能够对多媒体课程进…