20200411更新:

经过评论区 @鹤汀凫渚 的指导,我成功的用最简单的方法在python中调用到了GPU加速后的函数,这里把这位朋友的评论贴出来供各位参考:

以下原文:

本文的核心目的就是加速,在实时图像处理的路上,没有什么比得上加速,速度足够快就能上更复杂的模型,速度足够快就能有更多的预处理,总之,加速就是一切。

为了弥补Opencv-Python接口没有cuda加速的缺陷,本文旨在通过调用C++上才有的cuda模块,对Opencv进行加速,然后将其打包为Python接口后调用。

ps:本来笔者最开始采用的是Cython的第三方解决方案,但是经过同事指教后发现官方的API更加明晰,故改回使用Python官方的API来完成。

目录:图像数组的跨平台传递。

在C++下编写cuda加速的OpenCV代码。

--------------------------------------------------------------------------------

图像数组的跨平台传递

在采用PyTorch或者TF等深度学习框架的项目中,OpenCV主要的工作是针对图像的预处理,因此绝大部分情况下,数据的IO都是通过Python进行的,如何将图像数据从Python跨平台传输到C++下就是我们首先要解决的问题,而在Python下的图像数据基本都是保存为ndarray类型,因此我们需要在C++下也同样引入Numpy库,这个库可以通过APT直接安装,头文件会与Python3的头文件放在一起。

本文主要涉及的C++第三方库包括:OpenCV

Numpy

Python3.6

代码逻辑为:接收来自Python的ndarray数组,将其转为PyArrayObject类

将PyArrayObject转为OpenCV的Mat类数据

调用OpenCV对Mat进行图像处理,本文为了演示仅做BGR2GRAY处理

将处理后的Mat转换为PyArrayObject类

将PyArrayObject传回给Python,Python会自动将其识别为ndarray类对象

为了完成上面的逻辑,我们需要新建三个类文件:interface.cpp/.h :接口类,主要负责步骤1,5

conversion.cpp/.h :转换类,主要负责步骤2,4

process.cpp/.h :处理类,主要负责步骤3

先从interface.cpp文件开始:

//interface.cpp// Created by liuky on 2020-01-02.//#include #include "numpy/arrayobject.h"#include "numpy/ndarrayobject.h"#include "opencv2/imgcodecs.hpp"#include "conversion.h"#include "process.h"//参数检测与转换,将会检测Python端输入参数的合法性,并转为PyObject类static PyObject* array2array(PyObject* self,PyObject* args){

PyObject *array;

if (not PyArg_ParseTuple(args,"O",&array)){ //判断args输入的参数是否为PyOBJ,并且将array指针指向参数 PyErr_SetString(PyExc_TypeError,"input arg is not pyobject");//如果不是则报错 }

PyObject* res = process(array);//调用图像处理函数对array进行处理 return Py_BuildValue("O",res);

}

//声明要暴露出去的方法集合,该集合为PyMethodDef结构static PyMethodDef my_test_methods[]={

{"array2array",array2array,METH_VARARGS},

{NULL,NULL,0,NULL}

};

//声明模组,模组包含一个HEAD_INIT头初始化,模组名,以及描述字符等,最后必须包含方法集合static PyModuleDef my_test_modules={

PyModuleDef_HEAD_INIT,

"my_test",

"DES",

-1,

my_test_methods,

};

//包初始化,当在Python下 import这个包时就会调用初始化函数,要注意初始化函数名的命名规则,必须是PyInit_xxx(包名)PyMODINIT_FUNC PyInit_my_test(void){

import_array();//要注意array在每个类文件下都要重新初始化 conversion_init();

return PyModule_Create(&my_test_modules);

}

然后是conversion.cpp:

//conversion.cpp// Created by liuky on 2020-01-02.//#include "conversion.h"int conversion_init(){

import_array();

return 0;

}

cv::Mat array2mat(PyObject *pyobj){

cv::Mat mat;

PyArrayObject* py_array_obj = nullptr;

//检查是否为PyArray if(!PyArray_Check(pyobj)){

free(py_array_obj);

PyErr_SetString(PyExc_TypeError,"input obj is not PyArrayObject");

} else py_array_obj = (PyArrayObject*) pyobj;

bool needcopy = false; //判断PyArray是否内存地址连续

//判断PyArray的元素类型,并且找到对应的Mat元素类型 int array_dtype = PyArray_TYPE(py_array_obj);

int mat_dtype =array_dtype == NPY_UBYTE ? CV_8U :

array_dtype == NPY_BYTE ? CV_8S :

array_dtype == NPY_USHORT ? CV_16U :

array_dtype == NPY_SHORT ? CV_16S :

array_dtype == NPY_INT ? CV_32S :

array_dtype == NPY_INT32 ? CV_32S :

array_dtype == NPY_FLOAT ? CV_32F :

array_dtype == NPY_DOUBLE ? CV_64F : -1;

/*得到PyArray的维度信息,包含ndim,dims,strides,element size等,* 根据元素大小和strides的值的比较判断Py_array内存是否连续*/

#ifndef CV_MAX_DIM const int CV_MAX_DIM = 32; //最大接收channel为32的图像array#endif int ndim = PyArray_NDIM(py_array_obj);

npy_intp* dims = PyArray_DIMS(py_array_obj);

npy_intp* strides = PyArray_STRIDES(py_array_obj);

size_t element_size = CV_ELEM_SIZE1(mat_dtype);

bool ismultichannel = ((ndim == 3) && (dims[2] <= CV_CN_MAX)); //判断PyArray是否为3维数组 // 1 如果最后一个维度(储存单个元素)的stride值与element_size不相等,表示内存不连续,需要值拷贝 // 2 如果排序较前的维度stride小于排序较后的维度,表示维度被transpose过,内存不连续,需要值拷贝 for(int i = ndim-1;i>=0 && !needcopy;i--){

if ((i == ndim-1 && (size_t)strides[i] !=element_size) ||

(i

needcopy = true;

}

}

// 3 如果是3维度图像数组,则维度2的stride应该等于维度3的stride(即元素大小)*该维度的元素个数,否则内存不连续 if (ismultichannel && strides[1]!=(npy_intp)element_size * dims[2]){

needcopy=true;

}

if (needcopy){

py_array_obj = PyArray_GETCONTIGUOUS(py_array_obj);

pyobj = (PyObject*) py_array_obj;

strides = PyArray_STRIDES(py_array_obj);

}

// 将dims,strides转换为mat接受的数据格式 int sizes[ndim];

size_t steps[ndim];

for (int i = 0;i

sizes[i] = (int) dims[i];

steps[i] = (size_t)strides[i];

}

//如果PyArray是空数组,则留一个element_size的内存,返回一个元素数量为1的数组 if (ndim == 0){

sizes[ndim] = 1;

steps[ndim] = element_size;

ndim ++;

}

//如果是3维度图像数组,则将最后一个维度转换为Vec数据类型。 if(ismultichannel){

ndim --; //去掉最后一个维度 mat_dtype = CV_MAKETYPE(mat_dtype,sizes[2]);

}

mat = cv::Mat(ndim,sizes,mat_dtype,PyArray_DATA(py_array_obj),steps);

return mat;

}

PyObject* mat2array(const cv::Mat &mat){

int type = mat.type();//获得mat的数据类型 int depth = CV_MAT_DEPTH(type);//根据数据类型,得到元素类型,比如CV_8UC3会得到CV_8U int cn = CV_MAT_CN(type);//mat最后一个维度的channel int dims = mat.dims;

const int f = (int)(sizeof(size_t) / 8);

int typenum =

depth == CV_8U ? NPY_UBYTE :

depth == CV_8S ? NPY_BYTE :

depth == CV_16U ? NPY_USHORT :

depth == CV_16S ? NPY_SHORT :

depth == CV_32S ? NPY_INT :

depth == CV_32F ? NPY_FLOAT :

depth == CV_64F ? NPY_DOUBLE :

f * NPY_ULONGLONG + (f ^ 1) * NPY_UINT;

cv::AutoBuffer sizes(dims + 1);

const int *matSizes = mat.size;

for (int i = 0 ; i < dims ; i++)

{

sizes[i] = matSizes[i];

}

if (cn > 1)

{

sizes[dims++] = cn;

}

PyObject *array = PyArray_SimpleNew(dims, sizes, typenum);

void *data = PyArray_DATA(array);

int len = mat.total() * mat.elemSize();

memcpy(data, mat.data, len);

return array;

}

最后是process.cpp:

//process.cpp// Created by liuky on 2020-01-02.//PyObject * process(PyObject* obj){

if (not PyArray_Check(obj)){

PyErr_SetString(PyExc_TypeError,"input obj is not a array");

return nullptr;

}

else{

cv::Mat mat = array2mat(obj);//PyArrayObject转mat cv::cvtColor(mat,mat,cv::COLOR_BGR2GRAY);//彩图转黑白 PyObject* res = mat2array(mat);//mat转回PyArrayObject return res;

}

}

最后给出setup.py文件:

from distutils.core import setup,Extension

testModule = Extension("my_test",

["py_init.cpp",'conversion.cpp','process.cpp'],

include_dirs=[

"/usr/local/include/opencv4",

"/usr/include/python3.6m",

],

extra_compile_args=["-std=c++11"],

extra_link_args=[

"-lpython3.6m",

"-lopencv_core",

"-lopencv_video",

"-lopencv_videoio",

"-lopencv_imgproc",

"-lopencv_cudaimgproc",

"-lopencv_imgcodecs",

]

)

setup(name='my_test',version="0.1",ext_modules=[testModule])

通过Python3 setup.py install build_ext --inplace命令就可以将包安装进Python3中

python opencv gpu加速_让Python下的OpenCV也能GPU加速!part.1相关推荐

  1. python gpu并行计算_【Python - GPU】基于Python的GPU加速并行计算 -- pyCUDA

    Python实现的CUDA – pyCUDA Nvidia的CUDA 架构为我们提供了一种便捷的方式来直接操纵GPU 并进行编程,但是基于 C语言的CUDA实现较为复杂,开发周期较长.而python ...

  2. python 怎么用gpu运算_使用Python玩转GPU

    问题 随着机器学习对模型运算速度的需求越来越强烈, 一直想进行GPU编程,但一直以来这些都是c++的专利 一想到c++里的各种坑,就提不起劲来,毕竟这样来来回回填坑的投入产出,生产效率就会大打折扣 解 ...

  3. python 预编译加速_让Python代码运行更快的最佳方式

    Python因其强大.灵活且易于使用等特性,而赢得了声誉.这些优点使其在各种各样的应用程序.工作流程和领域中得到了广泛应用.但是就语言的设计,也就是它天然的解释能力还有它的运行时的动态性而言,Pyth ...

  4. python登录微信客户端_命令行下的微信客户端

    _____ _ _ _____ _ _ ___ _____ |_ _| | | / __ \| | | | / _ \_ _| | | | | | | / \/| |_| |/ /_\ \| | | ...

  5. python gui测试工具_在Suse10下尝试dogtail(一个python的GUI测试工具..

    你的位置: 技术文档 -> Python -> 文档详情 在Suse10下尝试dogtail(一个python的GUI测试工具.. 零 简介: DogTail是一个用python写的,自动 ...

  6. macbook自带python保存文件夹_在mac下查找python包存放路径site-packages的实现方法 在Mac系统下python如何安装第三方函数库?...

    mac怎么查看python的site-package位置世界上最伤心的事,不是你爱的人不爱你,而是他爱你过后,最后却不爱你. 可以通过find命令查看,参考demo如下: sudo find / -n ...

  7. python windows 消息通讯_在windows下使用python进行串口通讯的方法

    在windows下使用python进行串口通讯的方法 Windows版本下的python并没有内置串口通讯的pyserial的库,所以需要自己下载.参照了网上的教程,有许多用的pip的安装方式,但是试 ...

  8. python基于opencv的手势识别_求python opencv 手势识别源代码

    2013-06-22 回答 1.1.介绍introduction 从opencv2.4开始,加入了新的类facerecognizer,我们可以使用它便捷地进行人脸识别实验.本文既介绍代码使用,又介绍算 ...

  9. python anaconda下载包_【Python开发】anaconda3 安装python包

    环境说明电脑配置:win7 64位安装版本:anaconda3 Python 3.6参考链接http://python.jobbole.com/86236/(链接中有一个小点介绍了如何加速包的下载)h ...

最新文章

  1. 2W+好评,这个python数据分析课程免费开放3天!
  2. 在 Ubuntu 下安装 Discuz! 7.0
  3. 腾讯张正友:攻克可进化机器人,6个研究趋势与7大技术突破点
  4. python快速入门 pdf-零起点PYTHON机器学习快速入门 PDF |网盘链接下载|
  5. jenkins内置变量的使用
  6. python查看函数参数,在python函数中获取参数名称列表
  7. 通过Erlang构建TCP服务器
  8. 人才空缺4600万!大厂优先录用,这个职业今年火遍全网
  9. asp.net core 腾讯验证码的接入
  10. Gym101128J
  11. 配置ubuntu使用console登录登录欢迎提示
  12. emit传参,获取返回值
  13. 被吹的神乎其神的Python到底都能干什么
  14. 微课|玩转Python轻松过二级(3.3节):字典使用要点
  15. Atitit 现代信息检索 Atitit 重要章节 息检索建模 检索评价 第8章 文本分类 Line 210: 第9章 索引和搜索 第11章 Web检索 第13章 结构化文本检索 目录 L
  16. [C#][Quartz]帮助类
  17. chrome支持的java版本下载_安装Chrome Java插件
  18. Ubuntu10.04正式版主目录加密BUG
  19. 为 Vue 项目添加 cnzz 统计
  20. 问题 : 找出直系亲属

热门文章

  1. 地图可视化 - 气泡点图
  2. php开启sockets模块,独立编译php的sockets模块
  3. 解决IE浏览器打印iframe页面时字体等样式缩小的问题
  4. [C] 不撞南墙不回头——深度优先搜索
  5. 《机器学习》西瓜书课后题7.3
  6. 计算机比赛小组名称和口号,小组名称口号大全(精选150个)
  7. sql server 参数探测(Parameter Sniffing)影响存储过程执行效率解决方案
  8. python表求列平均值_python中表列的平均值
  9. 各品牌主板、笔记本、台式机启动快捷键
  10. 计算机的记事本和写字板的功能,记事本和写字板有什么不同?功能上