昆明建设厅培训网站,做新零售这些注册网站和找货源,郴州房产网,营销型网站建设方案演讲pptPython有很多种调c的方法#xff0c;有的复杂有的简单#xff0c;有时使用的时候反而不知道到底该用哪一种比较好#xff0c;其实没有最好的方法#xff0c;只有适合不适合自己。本文从我所遇到的问题说起#xff0c;然后讲述另一种比较简单的python调c并且传参numpy矩阵的…Python有很多种调c的方法有的复杂有的简单有时使用的时候反而不知道到底该用哪一种比较好其实没有最好的方法只有适合不适合自己。本文从我所遇到的问题说起然后讲述另一种比较简单的python调c并且传参numpy矩阵的方法。该方法调用的是python自带的ctypes库所以使用该方法不用安装或配置任何地第三方库。背景之前项目遇到一个问题求二值图像连通区域对于一般的图像其实很简单opencv有函数可以直接调。但是我要处理的是一个3D图像opencv没有求3D图像连通区域的函数所以只能自己写算法实现。该算法的核心思想是使用深度遍历来判断有多少像素点是连通的所以看到遍历两个字那python就肯定得排除了所以就选择了c。从工程上来看我的问题可以简单描述为python环境下有一个numpy矩阵以及若干参数现需要传递给c程序计算然后返回一个新的numpy矩阵或者直接修改原始numpy矩阵。然后我开始思考我到底该使用哪种方式调c我也调研了一些方法在此不一一列举总的来说它们的缺点是额外学习成本相对较高、得另外安装软件或库支持例如boost、调试起来各种奇怪的错误等等。再加上我使用的Linux服务器我并没有sudo权限故更加限制了这些方法的使用。这些方法或许很强大但是我的要求很简单只要能实现我上述的要求即可于是我开始把目光转向ctypes。解决方案Python使用ctypes调c很简单网上有一堆相关教程但这些教程中传递的参数基本都是int、float等等一些最基本的类型而我现在要传的是一个很大的numpy矩阵该怎么办我仔细研究了一下发现可以通过ctypes传指针而且numpy矩阵的指针也可以得到惊喜。利用ctypesnumpy矩阵的指针可以这样得到p 于是我想把numpy指针和numpy的shape信息传递过去不就相当于把整个numpy传递过去了吗比如src是一个10*10的矩阵指针为p那么在c中是不是就可以使用p[x][y]来定位具体的元素了想法是美好的c中可以使用p[x][y]的前提是p一个指针的指针具体来说应该是int**类型的而事实是p仅仅只是一个指针是int*类型的故此思路行不通。转念又一想既然它是int*类型那我就p[x]这样来取值就把它当成一个一维数组于是成功。那么现在问题来了本来numpy矩阵是多维的怎样跟一维数组对应呢对很简单就是把多维的矩阵拉成一维的即可相当于numpy的一个函数reshape想想reshape成一维的之后元素是怎样跟之前对应的就是这个对应关系。比如一个二维矩阵shape为10,20那么其中的ij点对应到一维数组里面的坐标就是i*20j三维矩阵道理相同。至此关键问题解决了。后续思考速度问题现有这样一个任务三维矩阵所有元素值加一用遍历方法实现。我们分别使用两种方法来实现并且对比速度1纯python实现2c实现使用刚刚的方法调c。c代码如下demo.cpp#include python代码如下main.pyimport 然后使用下面命令编译成动态链接库c11 -shared -fPIC demo.c最后运行main.py结果如下(10, 512, 512)
c : 0.009840011596679688
python: 7.284840822219849可见速度差别之大。内存连续问题可能有小伙伴已经想到了该方法可行的另一个重要前提是numpy矩阵所有元素在内存中必须是连续的若不连续肯定会出错。但是有时候我们传递的numpy矩阵可能就是不连续的那该怎么办很简单仅仅只需改变一下传递姿势。还拿刚才的例子举例还是元素自加一但是为了方便展示我们把numpy矩阵改为二维的。首先创建一个10*10的值为1的二维矩阵m0然后只取其左上角5*5的一部分m可以看出m肯定是不连续的现把m传参测试python代码如下def 结果(5, 5)
[[2 2 2 2 2 2 2 2 2 2][2 2 2 2 2 2 2 2 2 2][2 2 2 2 2 1 1 1 1 1][1 1 1 1 1 1 1 1 1 1][1 1 1 1 1 1 1 1 1 1][1 1 1 1 1 1 1 1 1 1][1 1 1 1 1 1 1 1 1 1][1 1 1 1 1 1 1 1 1 1][1 1 1 1 1 1 1 1 1 1][1 1 1 1 1 1 1 1 1 1]]
[[2 2 2 2 2][2 2 2 2 2][2 2 2 2 2][1 1 1 1 1][1 1 1 1 1]]可以看出m0和m的值都被改变了m的值并没有全部改变只改变了一部分而且m0刚好前5*525个值改变了这说明了m并不是深拷贝它仍然和m0共用一块内存空间c处理的时候只会连续着处理所以只改变了连续空间的这一段长度为5*5的值。当然解决方法很简单只需不让它们共用一份内存重新拷贝一份即可。上述第三行修改为m 或m 即可。写在后面前面已经说过没有最好的方法只有最适合自己的。我认为这种方法足够简单高效前提是它能满足你的需求比如类似传numpy矩阵这种。对了还有一点需要注意的地方就是一定要保证numpy元素的数据类型跟c中的一致比如一个numpy的dtype为np.uint8在c中却使用int*那肯定会出错可以先使用astype函数把数据类型转成一致然后再调c。还有我本来要解决的问题是3D图像的连通区域求解现已实现速度贼快感兴趣的小伙伴可以评论区回复。