2013-06-14 15 views
6

Quindi sto usando python per chiamare i metodi in una libreria C++ condivisa. Sto riscontrando un problema nel convertire un array numerico 2D in un array C++ 2D di cortocircuiti come input di funzione. Ho creato un esempio di giocattolo che mostra il problema. Sentiti libero di compilare e provalo!Converti un array di numpy 2D in C++ short **?

Ecco il codice python (soexample.py):

# Python imports 
from ctypes import CDLL 
import numpy as np 

# Open shared CPP library: 
cpplib=CDLL('./libsoexample.so') 
cppobj = cpplib.CPPClass_py() 

# Stuck on converting to short**? 
array = np.array([[1,2,3],[1,2,3]]) 
cpplib.func_py(cppobj,array) 

Ecco la libreria C++ (soexample.cpp):

#include <iostream> 

using namespace std; 

class CPPClass 
{ 
    public: 
    CPPClass(){} 

    void func(unsigned short **array) 
    { 
     cout << array[0][0] << endl; 
    } 
}; 

// For use with python: 
extern "C" { 
    CPPClass* CPPClass_py(){ return new CPPClass(); } 
    void func_py(CPPClass* myClass, unsigned short **array) 
    {  
     myClass->func(array);  
    } 
} 

che compilo con il seguente comando:

g++ -fPIC -Wall -Wextra -shared -o libsoexample.so soexample.cpp 

Quando eseguo il file python, viene visualizzato il seguente errore:

>> python soexample.py 
Traceback (most recent call last): 
    File "soexample.py", line 13, in <module> 
    cpplib.func_py(cppobj,array) 
ctypes.ArgumentError: argument 2: <type 'exceptions.TypeError'>: Don't know how to  convert parameter 2 

Come correggere correttamente questo sfortunato TypeError?

+1

ritengo brevi int di C sono 16 bit. L'int numpy predefinito, d'altra parte, è in genere 32 bit. Puoi provare a creare il tuo array come 'array = np.array ([[1,2,3], [1,2,3]], dtype = np.uint16)' e vedi cosa succede. – Jaime

risposta

4

È possibile utilizzare ctypes 's c_short e POINTER per aiutare con la conversione intermedia. La seguente funzione trasforma una matrice numpy in un array di tipo 2 di tipo C che può essere passato in una funzione C in attesa di short **.

def c_short_2darr(numpy_arr): 
    c_short_p = POINTER(c_short) 
    arr = (c_short_p * len(numpy_arr))() 
    for i in range(len(numpy_arr)): 
    arr[i] = (c_short * len(numpy_arr[i]))() 
    for j in range(len(numpy_arr[i])): 
     arr[i][j] = numpy_arr[i][j] 
    return arr 

Nota, modificato func_py e CPPClass::func prendere 2 parametri aggiuntivi, larghezza e lunghezza della matrice data. Con questo, CPPClass::func può stampare tutti gli elementi dell'array:

// ... 
void CPPClass::func(unsigned short **array, size_t w, size_t h) 
{ 
    for(size_t i = 0; i < w; ++i) 
    { 
     for(size_t j = 0; j < h; ++j) 
      cout << array[i][j] << ", "; 
     cout << '\n'; 
    } 
} 
// ... 
void func_py(CPPClass *myClass, 
      unsigned short **array, 
      size_t w, size_t h) 
{ 
    myClass->func(array, w, h); 
} 

con quella funzione di supporto definita, la seguente dovrebbe funzionare:

>>> arr = numpy.array([ [1,2,3], [4,5,6] ]) 
>>> arr 
array([[1, 2, 3], 
     [4, 5, 6]]) 
>>> cpplib.func_py(cppobj, c_short_2darr(arr), 2, 3) 
1, 2, 3, 
4, 5, 6, 
0 
+0

Grazie! Ha funzionato perfettamente. Ho un'altra domanda simile a cui potresti essere in grado di aiutarmi qui: http://stackoverflow.com/questions/17138054/return-c-double-to-python – dillerj