下文的代码可能展示不全,详情请下载文件:用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. pycharm报错:Process finished with exit code -1073741819 (0xC0000005)解决办法

    这个是几个月前的问题了,有小伙伴在CSDN问我咋解决的,那我今天在这边把这个问题解决办法分享下吧,免得大家把很多时间都浪费在安装排坑上面,有些坑虽然解决了还真不知道啥原因. 我的pycharm一直用的 ...

  2. November 24th, Week 48th, Sunday, 2019

    Once you replace negative thoughts with positive ones, you will start having positive results. 淘汰消极思 ...

  3. 编译原理:直接推导、间接推导、n次推导、规范推导

    直接推导,直接运用规则进行的推导 间接推导.n次推导 有两种符号 第一种是,表示多次运用直接推导 第二种是,表示零次或多次运用直接推导 n表示中间的步骤数 规范推导 其实就是最右推导

  4. [洛谷P1122][题解]最大子树和

    这是一道还算简单的树型dp. 转移方程:f[i]=max(f[j],0) 其中i为任意非叶节点,j为i的一棵子树,而每棵子树都有选或不选两种选择 具体看代码: #include<bits/std ...

  5. luoguP1871 对撞机【赛后第一题

    题面 题目描述 在2312年,宇宙中发现了n台巨型对撞机,这些对撞机分别用1-n的自然数标识.科学家们不知道启动这些对撞机会发生什么危险事故,所以这些机器,刚开始都是出于关闭的状态. 随着科学家们的研 ...

  6. Java连载54-两种单例模式、接口详解

    一.单例模式分为两种: (1)饿汉式单例:在类加载阶段就创建了一个对象. (2)懒汉式单例:用对对象的时候才会创建对象.(连载53中例子就是懒汉式) 饿汉式举例: package com.bjpowe ...

  7. JS-时间相关的函数封装

    1.用JS把时间戳转换为时间,代码如下: //时间戳转换为时间 function timestampToTime(timestamp) { var date = new Date(timestamp) ...

  8. IT兄弟连 HTML5教程 HTML5表单 多样的输入类型1

    HTML5拥有多个新的表单输入类型,这些新特性提供了更好的输入控制和验证.并不是所有的主浏览器都支持新的input类型,不过我们可以在所有的主浏览器中使用它们,即使不被支持,仍然可以显示为常规的文本域 ...

  9. IT兄弟连 HTML5教程 HTML5表单 HTML表单中的get和post方法

    指引 表单在网页应用中十分重要,基本上任何一个网站都必须使用到表单元素,所以表单的美观和易于交互对于网站设计就变得十分重要.HTML5对目前Web表单进行了全面提升,使得我们使用表单更加智能.它在保持 ...

  10. oracle将时间加一天,加小时,加分,加秒

    前言 oracle 时间类型可以直接相加,但加的是天,以天为单位,我们了解了这个,加一天,一小时,一分,一秒就都简单了. 加一天 select to_date('2019-08-15 22:03:10 ...