python和C++混合编程实现区域增长

python和C++混合编程实现区域增长

这两天项目需要选取眼底图片的感兴趣区域,这个图片长这个样子:
在这里插入图片描述
这个图片中除了黑色部分都是感兴趣区域,而黑色背景部分是一块连续的区域,用区域增长的方法能很快确定,于是我就拿matlab实现了一下,效果很nice,是我想要的内容。我的平台是在pyQT5上搭建的,怀着激动的心情用python按照matlab的思路写了一遍,其具体代码如下:

ef region_grow(I,seed_x,seed_y):
    '''
    The ALG of region_grow is based on binary images
    :param I:
    :param seed_x:
    :param seed_y:
    :return:
    '''

    high, width = np.shape(I)

    result_old = np.zeros([high, width])
    result = result_old.copy()
    result[seed_x,seed_y] = 1

    while np.max(np.abs(result-result_old)) > 0: #前一次迭代结果不等于后一次需要不断迭代
        result_old = result.copy()
        for i in range(1,high - 1):
            for j in range(1,width - 1):
                if result[i,j] == 1:
                    if I[i,j - 1] == 1:
                        result[i,j - 1] = 1
                    if I[i,j + 1] == 1:
                        result[i,j + 1] = 1
                    if I[i - 1,j - 1] == 1:
                        result[i - 1,j - 1] = 1
                    if I[i - 1,j] == 1:
                        result[i - 1,j] = 1
                    if I[i - 1,j + 1] == 1:
                        result[i - 1 ,j + 1] = 1
                    if I[i + 1,j - 1] == 1:
                        result[i + 1,j - 1] = 1
                    if I[i + 1,j] == 1:
                        result[i + 1,j] = 1
                    if I[i + 1,j + 1] == 1:
                        result[i + 1,j + 1] = 1

    return result

然后开心的点了运行按钮,拿起了我的水杯,喝了一口茶,咦~怎么还没反应,是不是喝的不够,再来一口,怎么还是没反应,我就继续一口一口的喝起了茶,终于我喝完了茶,但是它怎么还没有反应,是不是我写了死循环,吓得我赶紧停下来去查看,结果发现并不是我的错。作为一个自负的菜狗,就又点了运行,这次我倒了更大的一杯茶,终于在45秒之后,给我弹出了我想要的结果,如下图所示。
在这里插入图片描述
这让我很生气,明明一样的算法,为啥比matlab慢这么多呢,我细细看了下我的代码,有很多if,我猜想是不是这个问题,于是我测试了matlab和python的if语句的速度,matlab的if语句的运行速度在我的电脑上大约是python的15-20倍的样子,让我感到挺不可思议的。
越想越气,立志一定要解决这个问题,坚决不能让我每次都等45秒。所以我决定用python调用C++函数,希望能加快我的速度。我参考了这位兄台的内容。但是我用的C++的IDE是QT,下面记录了我整个操作的过程。

一、生成DLL

1.打开QT Creator,新建文件文件或项目,选择Library->C++ library.
在这里插入图片描述
然后一路默认就可以,当然可以改下自己的存储路径名字等。我才用Cmake进行的,完成之后的文件结果如下图所示.
在这里插入图片描述
2.修改头文件(Region_grow.h)

#ifndef REGION_GROW_H
#define REGION_GROW_H
#include <iostream>
#include <math.h>
#include "Region_Grow_global.h"
using namespace std;
#if defined(REGION_GROW_LIBRARY)
//让DLL文件的函数可以检测到
#  define REGION_GROW_EXPORT Q_DECL_EXPORT  
#else
#  define REGION_GROW_EXPORT Q_DECL_IMPORT  
#endif
// C++中不能直接返回二维数组,可以借助结构体实现
typedef struct Image
{
    int I[1024][1024];

}image, *Im;
class REGION_GROW_EXPORT Region_Grow
{
public:
    Region_Grow();
};
#endif // REGION_GROW_H
//被外部函数能检测到的函数的声明
extern "C" REGION_GROW_EXPORT Im region_grow(int a[1024][1024],int seed_x,int seed_y);

//产生零矩阵
int ** zeros(int high,int width);

//矩阵的复制
Im copy(Im sorce, Im target);

//查看矩阵是不是相同
bool different(int f[1024][1024],int s[1024][1024]);

2. 实现头文件中的函数(修改.cpp文件)

#include "region_grow.h"

Region_Grow::Region_Grow()
{
}
REGION_GROW_EXPORT Im region_grow(int I[1024][1024],int seed_x,int seed_y)
{
    //结构体指针的声明
    Im res,old;
    res = new(Image);  //记的初始化
    old = new(Image);
    
    //不使用静态变量会发生stack overflow的情况
    static int **ima;
    
    int i = 0;
    int j = 0;
    ima = zeros(1024,1024);
    for (i = 0;i<1024;i++)
    {
        for (j=0;j<1024;j++)
            res->I[i][j] = int(ima[i][j]);
    }
    
    old = copy(res,old);
    res->I[seed_x][seed_y] = 1;
    
    while (different(old->I,res->I))
    {
        old = copy(res,old);
        int i = 1;
        while (i < 1023)
        {
            int j = 1;
            while (j < 1023)
            {
                if (res->I[i][j])
                {
                    if (I[i - 1][j - 1]) res->I[i - 1][j - 1] = 1;
                    if (I[i - 1][j]) res->I[i - 1][j] = 1;
                    if (I[i - 1][j + 1]) res->I[i - 1][j + 1] = 1;
                    if (I[i][j - 1]) res->I[i][j - 1] = 1;
                    if (I[i][j + 1]) res->I[i][j + 1] = 1;
                    if (I[i + 1][j - 1]) res->I[i + 1][j - 1] = 1;
                    if (I[i + 1][j]) res->I[i + 1][j] = 1;
                    if (I[i + 1][j + 1]) res->I[i + 1][j + 1] = 1;
                }
                j++;
            }
            i++;
        }
    }
    cout<<"Region Grow completed";
    return res;
}
int ** zeros(int high,int width)
{
    //通过指针声明二维数组
    static int **res;
    res = (int**)new int*[high];
    for (int i=0;i< high;i++)
    {
        *(res+i) = new int[width];
    }
    
    
    for (int i = 0;i < high;i++)
    {
        for (int j = 0;j < width; j++)
        {
            res[i][j] = 0;
        }
    }

    return res;
}

Im copy(Im sorce,Im target)
{
    for (int i=0;i<1024;i++)
    {
        for (int j=0;j<1024;j++)
        {
            target->I[i][j] = sorce->I[i][j];
        }
    }
    return target;
}


bool different(int f[1024][1024],int s[1024][1024])
{
    for (int i = 0;i<1024;i++)
    {
        for (int j=0;j<1024;j++)
        {
            if (f[i][j] != s[i][j])
                return true;
        }
    }
    return false;
}

做完这些就可以编译dll了,编译运行完成后就可以用python调用它使用了。
3.python调用DLL库
在python的文当中这么进行如下编写

def R_G(I,seed_x,seed_y):
    '''
    The ALG of region_grow is based on binary images
    :param I:
    :param seed_x:
    :param seed_y:
    :return:
    '''
    in_put = ((c_int * 1024) * 1024)()    #C++函数的输入类型,和C++的接口。
    #把python的数据修改为C++可以接收的
    for i in range(1024):
        for j in range(1024):
            in_put[i][j] = int(I[i, j])
    #读取dll文件,可以写生成的dll地址
    lib = ctypes.cdll.LoadLibrary('Region_Grow.dll')
    h = lib.region_grow
    h.restype = ctypes.POINTER(Ima)
    p = lib.region_grow(in_put, seed_x, seed_y)
    res = np.zeros([1024, 1024])
    #将C++处理后的数据改变为python可以接受的类型
    for i in range(1024):
        for j in range(1024):
            # print(p.contents.I[i][j])
            res[i][j] = p.contents.I[i][j]

    return res

#这两行的写法是和C++的结构体相对应
class Ima(ctypes.Structure):
    _fields_ = [("I",(ctypes.c_int * 1024) * 1024)]

万事大吉,开始运行代码,端着茶继续抿一口,果然茶还没喝到就出结果了,用时大约1.5s,终于可以打出一口气了。其结果如下图所示。
在这里插入图片描述
写在最后:关于如何将C++的结构体和python结合起来,可以参考这个老哥的帖子

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值