下文的代码可能展示不全,详情请下载文件:用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(广度优先搜索)的更多相关文章

  1. Python调用ansible API系列(二)执行adhoc和playbook

    执行adhoc #!/usr/bin/env python # -*- coding: utf-8 -*- import sys from collections import namedtuple ...

  2. python3.4学习笔记(二十五) Python 调用mysql redis实例代码

    python3.4学习笔记(二十五) Python 调用mysql redis实例代码 #coding: utf-8 __author__ = 'zdz8207' #python2.7 import ...

  3. python3.4学习笔记(二十三) Python调用淘宝IP库获取IP归属地返回省市运营商实例代码

    python3.4学习笔记(二十三) Python调用淘宝IP库获取IP归属地返回省市运营商实例代码 淘宝IP地址库 http://ip.taobao.com/目前提供的服务包括:1. 根据用户提供的 ...

  4. python调用系统命令popen、system

    python调用Shell脚本,有两种方法:os.system(cmd)或os.popen(cmd),前者返回值是脚本的退出状态码,后者的返回值是脚本执行过程中的输出内容.所以说一般我们认为popen ...

  5. Python的扩展接口[3] -> Matlab引擎 -> 使用 Python 调用 Matlab 程序

    Python - Matlab 目录 Python-Matlab 引擎 Python-Matlab 数组 Python-Matlab 基本操作 Python-Matlab 调用 m 文件 Matlab ...

  6. Python调用Java代码部署及初步使用

    Python调用Java代码部署: jpype下载地址:https://www.lfd.uci.edu/~gohlke/pythonlibs/#jpype 下载的时候需要使用Chrome浏览器进行下载 ...

  7. Windows中使用 Python 调用 Matlab 程序

    https://ww2.mathworks.cn/help/matlab/matlab_external/system-and-configuration-requirements.html http ...

  8. Python调用R编程——rpy2

    在Python调用R,最常见的方式是使用rpy2模块. 简介 模块 The package is made of several sub-packages or modules: rpy2.rinte ...

  9. python调用其他程序或脚本方法(转)

    python运行(调用)其他程序或脚本 在Python中可以方便地使用os模块运行其他的脚本或者程序,这样就可以在脚本中直接使用其他脚本,或者程序提供的功能,而不必再次编写实现该功能的代码.为了更好地 ...

随机推荐

  1. mysql安装、使用

    一.下载.安装 1.下载 (1)下载地址 https://dev.mysql.com/downloads/mysql/ (2)此处我下载最新版(8.0.18) 2.安装 (1)解压.并配置环境变量 s ...

  2. Mac Electron 应用的签名(signature)和公证(notarization)

    背景 在MacOS 10.15之前,应用如果没有签名,那么首次打开时就会弹出这种“恶意软件”的提示框. 这时只要应用签名了,就不会弹这个框. 但在MacOS 10.14.5之后,应用如果没有公证(简单 ...

  3. 44.QT-安装MySQL、测试连接MySQL

    在上章学习了42.QT-操作SQLite数据库后,发现MySQL和SQLite的语句都大致相同,所以本章只测试MySQL是否能使用 MySQL安装参考链接:https://blog.csdn.net/ ...

  4. netty解决粘包半包问题

    前言:开发者用到TCP/IP交互时,偶尔会遇到粘包或者半包的数据,这种情况有时会对我们的程序造成严重的影响,netty框架为解决这种问题提供了若干框架 1. LineBasedFrameDecoder ...

  5. 追踪SQL Server执行delete操作时候不同锁申请与释放的过程

    一直以为很了解sqlserver的加锁过程,在分析一些特殊情况下的死锁之后,尤其是并发单表操作发生的死锁,对于加解锁的过程,有了一些重新的认识,之前的知识还是有一些盲区在里面的.delete加锁与解锁 ...

  6. 如何计算Data Guard环境中Redo所需的网络带宽传输 (Doc ID 736755.1)

    How To Calculate The Required Network Bandwidth Transfer Of Redo In Data Guard Environments (Doc ID ...

  7. s3c2440裸机-代码重定位(2.编程实现代码重定位)

    代码重定位(2.编程实现代码重定位) 1.引入链接脚本 我们上一节讲述了为什么要重定位代码,那么怎么去重定位代码呢? 上一节我们发现"arm-linux-ld -Ttext 0 -Tdata ...

  8. PDF软件

    推荐的PDF阅读软件:文电通

  9. ccf-csp201809题解

    目录 ccf-csp201809题解 1. 201809-1 卖菜 题目描述 解析 通过代码 2. 201809-2 买菜 题目描述 解析 通过代码 3.201809-3 元素选择器 题目描述 解析 ...

  10. VUE脚手架使用

    什么是vue脚手架?   他是一个快速构建vue项目的工具,通过他,我们可以将vue所需要的文件安装完成. vue-cli这个构建工具大大降低了webpack的使用难度,支持热更新,有webpack- ...