python extension c++ extension

Module writing reference tutorial:

https://thomasnyberg.com/cpp_extension_modules.html

https://docs.python.org/3/extending/extending.html

Debug reference:

https://stackoverflow.com/questions/15253586/python-extension-debugging

https://wiki.python.org/moin/DebuggingWithGdb

https://blog.csdn.net/wfdtxz/article/details/7368357

Python programming is indeed very aspect, but sometimes the speed is not as good as C and C++. When the amount of data processed is relatively large, it is still necessary to use python to call C++. This method uses the python extension method, and the data conversion is more cumbersome. Only one of its own templates is provided here for easy remembering.

First, you need to create a folder and report an error extension module:

 

The cpp directory is used to save cpp files, and setup.py is used to compile and install extension modules.

The cpp directory mainly contains the following files:

The main content format is as follows:

setup.py:

This file is mainly responsible for compiling c++ modules and encapsulating them into a form that can be called by python. Here we mainly modify the module_name1 item to be your own package name, and the source in the cpp file path you use.

import sys
import numpy as np
from distutils.core import setup
from distutils.extension import Extension
package_name = 'level-set'
module_name1 = 'drlse'
version = sys.version[0]
wrap_source = './cpp/wrap_py{0:}.cpp'.format(version)
module1 = Extension(module_name1,
                    include_dirs=[np.get_include(), './cpp'],
                    sources=['./cpp/drlse.cpp', 
                             './cpp/level_set.cpp', wrap_source])

setup(name=package_name,
      ext_modules=[module1])

drlse.cpp:

Here call the c++ module, pass the python variable to the c++ method, and return the result of c++ to python

Remember to use the NPY_FLOAT32 data type, not the NPY_FLOAT64 type, otherwise an error will occur when the result is returned to python.

#include <Python.h>
#include "numpy/arrayobject.h"
#include "level_set.hpp"
#include <iostream>

using namespace std;

// example to use numpy object: http://blog.debao.me/2013/04/my-first-c-extension-to-numpy/
// write a c extension ot Numpy: http://folk.uio.no/hpl/scripting/doc/python/NumPy/Numeric/numpy-13.html
static PyObject *
level_set_wrapper(PyObject *self, PyObject *args)
{
    PyObject *I=NULL,*phi=NULL;
	float W,H,mu,timestep,lambda,alfa,epsilon,potential_function,iters;
    PyArrayObject *arr_I=NULL;
	PyArrayObject *arr_phi=NULL;
    
    if (!PyArg_ParseTuple(args, "OOfffffffff", &I,&phi,&W,&H,&mu,&timestep,&lambda,&alfa,&epsilon,&potential_function,&iters)) return NULL;
    
    arr_I = (PyArrayObject*)PyArray_FROM_OTF(I, NPY_FLOAT32, NPY_IN_ARRAY);
    if (arr_I == NULL) return NULL;
	
	arr_phi = (PyArrayObject*)PyArray_FROM_OTF(phi, NPY_FLOAT32, NPY_IN_ARRAY);
    if (arr_phi == NULL) return NULL;
    
	npy_intp * shape = PyArray_DIMS(arr_I);  // npy_intp array of length nd showing length in each dim.
	
	
	
	drlse_Evolution((float*)arr_I->data, (float*)arr_phi->data, int(W), int(H), mu, timestep, lambda, alfa,
                                 epsilon, (int)potential_function, (int)iters);
    cout<<1<<endl;
    
	
    // level_set2D.InitPhi(mask, image_width, image_height)

    // alfa = 0;
    // level_set2D.Evolution();
    // float* final_phi = level_set2D.GetPhi();

	// PyArrayObject * phi_np = (PyArrayObject*) PyArray_SimpleNewFromData(2, shape, NPY_FLOAT64, final_phi);
	Py_DECREF(arr_I);
	//Py_DECREF(arr_phi);
	return PyArray_Return(arr_phi);

    
}

static PyMethodDef Methods[] = {
    {"drlse",  level_set_wrapper, METH_VARARGS, "computing drlse by cpp"}, 
    {NULL, NULL, 0, NULL}
};

wrap_py3.cpp:

The method name needs to be modified.

#include "drlse.cpp"


static struct PyModuleDef cGeosDis =
{
    PyModuleDef_HEAD_INIT,
    "drlse", /* name of module */
    "",          /* module documentation, may be NULL */
    -1,          /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */
    Methods
};


PyMODINIT_FUNC PyInit_drlse(void) {
    import_array();
    return PyModule_Create(&cGeosDis);
}

The main method modules are no longer listed, and there is no difference from the normal C++ writing method, which is mainly used to implement the methods to improve efficiency.

Of the above files, the most complicated is the drlse.cpp file, which is the link file, which is the core here, and other modules are more templates. After these files are prepared, the method can be called after executing the command.

python setup.py build

python setup.py install

Then you can call and test the module in python, like this:

import drlse
import numpy as np
from PIL import Image

filename = '216748_216749-100180_100181-18.jpg'
img = np.array(Image.open(filename).convert('L'))
W,H=img.shape
image_size = W * H
timestep = 5
potential_function=1
c0=2
mu = 0.2 / timestep
_lambda = 20
alfa = 4
epsilon = 1.5
iters = 50


initialLSF = 2 * np.ones(img.shape)
phi=initialLSF.copy()
phi[100:120,100:120]=-c0
final_phi=drlse.drlse(img.astype(np.float32),phi.astype(np.float32), W,H,mu,timestep,_lambda,alfa,epsilon, potential_function,iters)
ted=1
print(final_phi)


    

The most complicated part of the whole process is debugging. At present, it is not possible to realize joint debugging in IDE. My debugging method is to install gdb in cygwin to debug the python test module, and then find the error in that part, and then find the code. This part is mainly to debug the connection code of drlse.cpp. In the c++ part, I wrote the main function separately for debugging. This process made it extremely troublesome. . .

Pay attention to when debugging, use different build commands, my command in cygwin is

CFLAGS='-Wall -O0 -g' python3 setup.py build

My thoughts: I have done python extension programming before, and it took two or three days. This time I implemented another method, but it took two or three days. Therefore, I make a special note and hope that it can help other people in need. This process is cumbersome, and I hope Daniel can provide a more efficient and concise solution.

Guess you like

Origin blog.csdn.net/lebusini/article/details/103925461