extensión python extensión c ++

Tutorial de referencia de escritura del módulo:

https://thomasnyberg.com/cpp_extension_modules.html

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

Referencia de depuración:

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

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

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

La programación de Python es de hecho muy importante, pero a veces la velocidad no es tan buena como C y C ++. Cuando la cantidad de datos procesados ​​es relativamente grande, aún necesita usar Python para llamar a C ++. Este método usa el método de extensión de Python, y el la conversión de datos es más engorrosa. Aquí solo se proporciona una de sus propias plantillas para recordarla fácilmente.

Primero, debe crear una carpeta e informar un módulo de extensión de error:

 

El directorio cpp se usa para guardar archivos cpp y setup.py se usa para compilar e instalar módulos de extensión.

El directorio cpp contiene principalmente los siguientes archivos:

El formato de contenido principal es el siguiente:

setup.py:

Este archivo es principalmente responsable de compilar los módulos de C ++ y encapsularlos en una forma que pueda ser llamada por Python. Aquí modificamos principalmente el elemento module_name1 para que sea su propio nombre de paquete y la fuente en la ruta del archivo cpp que usa.

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:

Aquí llame al módulo c ++, pase la variable de python al método c ++ y devuelva el resultado de c ++ a python

Recuerde usar el tipo de datos NPY_FLOAT32 y no use el tipo NPY_FLOAT64; de lo contrario, se producirá un error cuando el resultado se devuelva a 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:

Es necesario modificar el nombre del método.

#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);
}

Los módulos del método principal ya no se enumeran y no hay diferencia con el método de escritura normal de C ++, que se utiliza principalmente para implementar los métodos para mejorar la eficiencia.

De los archivos anteriores, el más complicado es el archivo drlse.cpp, que es el archivo de enlace, que es el núcleo aquí, y otros módulos son más plantillas. Una vez preparados estos archivos, se puede llamar al método después de ejecutar el comando.

python setup.py build

python setup.py install

Luego puede llamar y probar el módulo en Python, así:

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)


    

La parte más complicada de todo el proceso es la depuración, actualmente no es posible realizar una depuración conjunta en IDE. Mi método de depuración es instalar gdb en cygwin para depurar el módulo de prueba de Python, y luego encontrar el error en esa parte y luego encontrar el código. Esta parte es principalmente para depurar el código de conexión de drlse.cpp. En la parte de c ++, escribí la función principal por separado para la depuración Este proceso lo hizo extremadamente problemático. . .

Preste atención al depurar, use diferentes comandos de compilación, mi comando en cygwin es

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

Mis pensamientos: he hecho programación de extensiones de Python antes y me llevó dos o tres días. Esta vez implementé otro método, pero me llevó dos o tres días. Por lo tanto, hago una nota especial y espero que pueda ayudar a otras personas en necesitar. Este proceso es engorroso y espero que Daniel pueda brindar una solución más eficiente y concisa.

Supongo que te gusta

Origin blog.csdn.net/lebusini/article/details/103925461
Recomendado
Clasificación