python调用C++实例:用C++对numpy执行BFS(广度优先搜索)
下文的代码可能展示不全,详情请下载文件:用cpp遍历ndarray.rar
问题背景:
现在我有一张二值图test.npy,需要对其闭区域进行孔洞填充,如下图所示:

文件下载链接:用cpp遍历ndarray.rar
用python实现BFS:
def bfs1(im, vis, x, y, xb, yb):
def legal(tx, ty):
if tx < xb and tx >= and ty < yb and ty >= :
return True
else:
return False dx = [, , , -]
dy = [, -, , ]
q = Queue()
ls = []
q.put((x, y))
flag = True
while not q.empty():
tmp = q.get()
cx, cy = tmp
vis[cx][cy] =
for i in range(, ):
tx = cx + dx[i]
ty = cy + dy[i]
if (legal(tx, ty)):
if im[tx][ty] == and vis[tx][ty] == :
q.put((tx, ty))
ls.append((tx, ty))
vis[tx][ty] =
else:
flag = False
if flag:
for pt in ls:
tx, ty = pt
im[tx][ty] = def fillHolePy(im):
x, y = im.shape[:]
ans=im.copy()
vis = np.zeros([x, y])
for i in range(, x):
for j in range(, y):
if vis[i][j] == : # and im[i][j]==
bfs1(ans, vis, i, j, x, y)
return ans
程序执行了0.914秒
用C++实现BFS:(因为python向cpp传参只能用一维数组,这涉及到多维数组到一维数组的映射,详见我的另一篇博客:numpy中多维数组的绝对索引)
int x_s,y_s;
inline int MAP(int x,int y){
return y_s*x + y;
}
int dx[]={, , , -};
int dy[]={, -, , };
int vis[*];
typedef struct Pt
{
int x,y;
Pt(int x,int y):x(x),y(y){
}
}Pt;
bool legal(int x,int y){
if(x<x_s && x>= && y<y_s && y>=)
return true;
return false;
}
void bfs(int *img,int x,int y){
queue<Pt> q;
vector<Pt> v;
q.push(Pt(x,y));
bool flag=;
int i;
while(!q.empty()){
Pt pt=q.front();
q.pop();
vis[MAP(x,y)]=;
int cx=pt.x,cy=pt.y;
FF(i,){
int tx=cx+dx[i];
int ty=cy+dy[i];
if(legal(tx,ty)){
if(img[MAP(tx,ty)]== && vis[MAP(tx,ty)]==){
q.push(Pt(tx,ty));
v.push_back(Pt(tx,ty));
vis[MAP(tx,ty)]=;
}
}else{
flag=;
}
}
if(flag){
int sz=v.size();
FF(i,sz){
int & tx=v[i].x;
int & ty=v[i].y;
img[MAP(tx,ty)]=;
}
}
}
}
void fillHole(int * img,int X,int Y){
x_s=X,y_s=Y;
int i,j;
FF(i,x_s)FF(j,x_s)if(!vis[MAP(i,j)]){
bfs(img,i,j);
}
}
下面我们看怎样用python调用cpp。
在上文的cpp中,对想要执行的函数fillHole进行声明:
extern "C" {
__declspec(dllexport)
void fillHole(int * img,int X,int Y)
;
}
用g++(mingw64位)编译为dll:
g++ bfs.cpp -shared -o bfs.dll -Wl,--out-implib,bfs.lib
pause
在python中使用numpy的封装加载DLL并且传参调用:
import numpy.ctypeslib as npct def fillHoleCpp(im):
array_2d_int32 = npct.ndpointer(dtype=np.int32, ndim=2, flags='CONTIGUOUS')
dll = npct.load_library("bfs.dll",".")
bfs=dll.fillHole
bfs.restype = None
bfs.argtypes = [array_2d_int32, c_int, c_int]
im=im.astype(dtype=np.int32)
if not im.flags['C_CONTIGUOUS']:
im = np.ascontiguous(im, dtype=im.dtype)
X, Y=im.shape
bfs(im,X,Y)
return im
查看测试结果:
程序执行了0.058秒
根据测试cpp比python快了15倍。
cpp完整代码:
#include <stdio.h>
#include <vector>
#include <queue>
#include <algorithm> using namespace std; #define FF(a,b) for(a=0;a<b;a++) extern "C" {
__declspec(dllexport)
void fillHole(int * img,int X,int Y)
;
} int x_s,y_s; inline int MAP(int x,int y){
return y_s*x + y;
} int dx[]={, , , -};
int dy[]={, -, , };
int vis[*]; typedef struct Pt
{
int x,y;
Pt(int x,int y):x(x),y(y){
}
}Pt; bool legal(int x,int y){
if(x<x_s && x>= && y<y_s && y>=)
return true;
return false;
} void bfs(int *img,int x,int y){
queue<Pt> q;
vector<Pt> v;
q.push(Pt(x,y));
bool flag=;
int i;
while(!q.empty()){
Pt pt=q.front();
q.pop();
vis[MAP(x,y)]=;
int cx=pt.x,cy=pt.y;
FF(i,){
int tx=cx+dx[i];
int ty=cy+dy[i];
if(legal(tx,ty)){
if(img[MAP(tx,ty)]== && vis[MAP(tx,ty)]==){
q.push(Pt(tx,ty));
v.push_back(Pt(tx,ty));
vis[MAP(tx,ty)]=;
}
}else{
flag=;
}
}
if(flag){
int sz=v.size();
FF(i,sz){
int & tx=v[i].x;
int & ty=v[i].y;
img[MAP(tx,ty)]=;
}
}
}
} void fillHole(int * img,int X,int Y){
x_s=X,y_s=Y;
int i,j;
FF(i,x_s)FF(j,x_s)if(!vis[MAP(i,j)]){
bfs(img,i,j);
}
} //int main() {
// return 0;
//}
bfs.cpp
python完整代码:
import numpy as np
import numpy.ctypeslib as npct
import pylab as plt
from queue import Queue
import datetime
from ctypes import * def bfs1(im, vis, x, y, xb, yb):
def legal(tx, ty):
if tx < xb and tx >= 0 and ty < yb and ty >= 0:
return True
else:
return False dx = [0, 0, 1, -1]
dy = [1, -1, 0, 0]
q = Queue()
ls = []
q.put((x, y))
flag = True
while not q.empty():
tmp = q.get()
cx, cy = tmp
vis[cx][cy] = 1
for i in range(0, 4):
tx = cx + dx[i]
ty = cy + dy[i]
if (legal(tx, ty)):
if im[tx][ty] == 0 and vis[tx][ty] == 0:
q.put((tx, ty))
ls.append((tx, ty))
vis[tx][ty] = 1
else:
flag = False
if flag:
for pt in ls:
tx, ty = pt
im[tx][ty] = 255 def fillHolePy(im):
x, y = im.shape[:2]
ans=im.copy()
vis = np.zeros([x, y])
for i in range(0, x):
for j in range(0, y):
if vis[i][j] == 0: # and im[i][j]==0
bfs1(ans, vis, i, j, x, y)
return ans import numpy.ctypeslib as npct def fillHoleCpp(im):
array_2d_int32 = npct.ndpointer(dtype=np.int32, ndim=2, flags='CONTIGUOUS')
dll = npct.load_library("bfs.dll",".")
bfs=dll.fillHole
bfs.restype = None
bfs.argtypes = [array_2d_int32, c_int, c_int]
im=im.astype(dtype=np.int32)
if not im.flags['C_CONTIGUOUS']:
im = np.ascontiguous(im, dtype=im.dtype)
X, Y=im.shape
bfs(im,X,Y)
return im if __name__ == '__main__':
img=np.load('test.npy')
plt.subplot(121)
plt.title('before fill')
plt.imshow(img)
starttime = datetime.datetime.now()
img=fillHoleCpp(img) #使用BFS(广度优先搜索算法)对原图像进行处理
endtime = datetime.datetime.now()
print("程序执行了%.03f秒" % ((endtime - starttime).microseconds / 1000000))
# exit(0)
plt.subplot(122)
plt.title('after fill')
plt.imshow(img)
plt.show()
dealArray.py
参考资料:
https://segmentfault.com/a/1190000000479951
python调用C++实例:用C++对numpy执行BFS(广度优先搜索)的更多相关文章
- Python调用ansible API系列(二)执行adhoc和playbook
执行adhoc #!/usr/bin/env python # -*- coding: utf-8 -*- import sys from collections import namedtuple ...
- python3.4学习笔记(二十五) Python 调用mysql redis实例代码
python3.4学习笔记(二十五) Python 调用mysql redis实例代码 #coding: utf-8 __author__ = 'zdz8207' #python2.7 import ...
- python3.4学习笔记(二十三) Python调用淘宝IP库获取IP归属地返回省市运营商实例代码
python3.4学习笔记(二十三) Python调用淘宝IP库获取IP归属地返回省市运营商实例代码 淘宝IP地址库 http://ip.taobao.com/目前提供的服务包括:1. 根据用户提供的 ...
- python调用系统命令popen、system
python调用Shell脚本,有两种方法:os.system(cmd)或os.popen(cmd),前者返回值是脚本的退出状态码,后者的返回值是脚本执行过程中的输出内容.所以说一般我们认为popen ...
- Python的扩展接口[3] -> Matlab引擎 -> 使用 Python 调用 Matlab 程序
Python - Matlab 目录 Python-Matlab 引擎 Python-Matlab 数组 Python-Matlab 基本操作 Python-Matlab 调用 m 文件 Matlab ...
- Python调用Java代码部署及初步使用
Python调用Java代码部署: jpype下载地址:https://www.lfd.uci.edu/~gohlke/pythonlibs/#jpype 下载的时候需要使用Chrome浏览器进行下载 ...
- Windows中使用 Python 调用 Matlab 程序
https://ww2.mathworks.cn/help/matlab/matlab_external/system-and-configuration-requirements.html http ...
- Python调用R编程——rpy2
在Python调用R,最常见的方式是使用rpy2模块. 简介 模块 The package is made of several sub-packages or modules: rpy2.rinte ...
- python调用其他程序或脚本方法(转)
python运行(调用)其他程序或脚本 在Python中可以方便地使用os模块运行其他的脚本或者程序,这样就可以在脚本中直接使用其他脚本,或者程序提供的功能,而不必再次编写实现该功能的代码.为了更好地 ...
随机推荐
- vue--CRUD
1. Create this.$http.post("http://localhost:3000/users",newCustomer).then(function (respon ...
- 编译原理之DFA最小化,语法分析初步
1.将DFA最小化: 状态转换图: 识别语言:b*ac*(da)*bb* 2.构造以下文法相应的最小的DFA S→ 0A|1B A→ 1S|1 B→0S|0 (1)正规式: S -> 0(1S+ ...
- 一图了解 CODING 2.0:企业级持续交付解决方案
近日,CODING 在 KubeCon 2019 上海站上正式推出了 DevOps 的一站式解决方案:CODING 2.0. CODING 2.0 进行了产品.产品理念.功能.首页的升级,对用户服务进 ...
- DSP编程与调试总结
(1)error: can't allocate .ebss, size 000c450d (page 1) in DXINTFRAM2 (avail: 00010000) error: errors ...
- mongo shell 通过返回信息定位错误点
有时候我们会通过mongo shell 运行一些脚本,去执行更新或运维需求.mongo shell 可执行的代码可以实现比较复杂的功能,代码也可以比较丰富.当执行报错时,如果可以快速定位到错误点,对解 ...
- memcache和redis缓存对比及我为什么选择redis
对比结论 1. 性能上: 性能上都很出色,具体到细节,由于Redis只使用单核,而Memcached可以使用多核,所以平均每一个核上Redis在存储小数据时比Memcached性能更高.而在100k以 ...
- Python—定时任务(APScheduler实现)
简介 APScheduler的全称是Advanced Python Scheduler.它是一个轻量级的基于Quartz的 Python 定时任务调度框架.APSche ...
- 淘宝爬取图片和url
刚开始爬取了 百度图片和搜狗图片 但是图片不是很多,随后继续爬取淘宝图片,但是淘宝反爬比较厉害 之前的方法不能用 记录可行的 淘宝爬取 利用selenium爬取 https://cloud.tence ...
- 高阶函数&&高阶组件(二)
高阶组件总共分为两大类 代理方式 操纵prop 访问ref(不推荐) 抽取状态 包装组件 继承方式 操纵生命周期 操纵prop 代理方式之 操纵prop 删除prop import React fro ...
- Qt 信号和槽异常: QObject::connect: No Such slot baseClassName::subClassfunction() in ......
2019-08-14起笔 小熊的情况描述: 父类A继承自QWidget,所以父类A自动添加了Q_OBJECT. 子类B继承自父类A,子类B没有添加Q_OBJECT.在子类B中给动态创建的控件添加事件 ...