opencv mat类_191123 使用 Pybind11 和 OpenCV 创建 Python 库

本文介绍了如何使用Pybind11将C++的OpenCV代码(包括cv::Point,cv::Rect,cv::Mat)转换为Python接口,实现与numpy.ndarray的互转,创建了一个名为pycv的Python库,提高了性能并实现了代码复用。
摘要由CSDN通过智能技术生成

9d7eb652953888bc3d189e67f491131a.png
参观飞机工厂不能让你学得流体力学,也不能让你学会开飞机。然而如果你会开飞机又懂流体力学,参观飞机工厂可以带给你最大的乐趣和价值。-- 侯捷

献给 @AliceInt-ZLJ by Knight @2019/11/23

Knight:191123 使用 Pybind11 和 OpenCV 创建 Python 库​zhuanlan.zhihu.com
582c380fba6eb01a3dcce6299d2d9f7c.png

2020.03.01 更新:

新增 github 项目地址 ausk/keras-unet-deploy 。

本文内容可在 keras-unet-deploy/cpp/unet/pycv 目录下查看。


C++ 是一种编译型(compiled)语言,设计重点是性能、效率和使用灵活性,偏向于系统编程、嵌入式、资源受限的软件和系统。Mordern C++ 支持宏、泛型重载、面向过程、面向对象、函数式等不同风格。模板类型萃取、容器、迭代器、算法是C++ STL 标准库的重要组成部分,善用之可改善编码效率。

Python是一种解释型(interpreted)语言,同样也支持不同的编程范式。Python 内置了常用数据结构(str, tuple, list, dict),支持鸭子类型(动态类型)和自动垃圾回收,加上简洁的语法、丰富的内置库(os,sys,urllib,...)和三方库(numpy, tf, torch ...),使其成为瑞士军刀,啥都能做。

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


最近在研究 openpose 人体骨骼关键点检测的非官方 keras 代码实现,转 pb 模型文件后,使用 c++ 版 tensorflow 进行推理及后处理。由于使用 C++ 重写了 keras python 版对应的后处理部分(当然 openpose 源码里有实现,不过由于其嵌入到了工程里,导致难以直接复用), 典型的后处理部分从 200 ms 减少到 20 ms。突发奇想,可不可以把重写后的代码暴露给 Python 调用。在 C++ 端,使用 cv::Mat 表示多维矩阵;对应地在 Python 端使用 numpy.ndarray 表示多维矩阵。经过各种尝试后,发现了使用 pybind11 基本可以实现 C++ 和 Python 之间的无缝对接,从而实现代码复用。

需要暴露接口的典型的 OpenCV 数据结构有 cv::Point, cv::Rect, cv::Mat, 其中 cv::Point 是 cv::Point_<int> 特化,cv::Rect 是 cv::Rect_<int> 特化,而常用的 cv::Mat 中的元素类型有 CV_8U (uchar), CV_32S (int), CV_32F (float)。

核心,是对上述需要转换的数据结构 T,通过添加模板重载结构体 pybind11::detail::type_caster<T>,实现对类型 T 的转换方法 load 和 cast 的注册。

1. 点与元组转换 cv::Point <=> tuple(x,y)

实现 cv::Point 和 tuple(x,y) 之间的转换, 需要特化模板结构体 pybind11::detail::type_caster<cv::Point>,然后实现 load 和 cast 方法。

简洁版:

namespace pybind11 {
     namespace detail{
    
template<>
struct type_caster<cv::Point>{
        
    PYBIND11_TYPE_CASTER(cv::Point, _("tuple_xy"));    
    bool load(handle obj, bool){
            
        py::tuple pt = reinterpret_borrow<py::tuple>(obj);        
        value = cv::Point(pt[0].cast<int>(), pt[1].cast<int>());       
        return true;    
    }    

    static handle cast(const cv::Point& pt, return_value_policy, handle){
            
        return py::make_tuple(pt.x, pt.y
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值