Лучший способ обернуть программу C для интерфейса Python с преобразованием между буфером данных в C и массив NumPy?
У нас есть заранее существующая большая библиотека изображений, написанная на C/C++, с уже существующим типом изображений. Мы хотели бы связать его с Python. Мы знаем, как сделать большинство вещей, например, используя SWIG, но мы бы хотели, чтобы наш интерфейс использовал NumPy вместо собственного типа структуры для хранения наших изображений.
У кого-нибудь есть пример как это сделать? В Интернете есть примеры, которые связывают NumPy с голыми указателями. Как мы можем связать NumPy с существующей структурой типа C, подобной этой:
typedef struct xvimage {
int nx, ny, nz, nt ; // dimensions
enum {PIX_UINT8, PIX_INT16, PIX_UINT16, PIX_INT32, PIX_FLOAT, PIX_DOUBLE} ; // type
void *data;
} xvimage;
1 ответ
Похоже, у вас уже есть хороший ответ, но в случае, если это поможет другим, использующим C++, обернуть вектор
/* File : example.i */
%module example
%{
#include "../src/example.h"
%}
%include <std_string.i>
%include <stl.i>
%include <std_vector.i>
%include <stdint.i>
%include <cpointer.i>
%include <carrays.i>
namespace std {
%template(IntVector) vector<int>;
%template(ByteVector) vector<uint8_t>;
}
%include "../src/example.h"
Полный пример, с работающими скриптами python и ruby, показывающими, что он работает swig_examples_cpp
Есть в основном три способа:
Скопируйте из буфера изображения в массив NumPy и наоборот. Если дано изображение C/C++, создайте массив NumPy и скопируйте данные, а когда получите массив NumPy, создайте изображение C/C++ и скопируйте данные.
Массив NumPy в качестве обертки вокруг указателя данных C. Создайте массив NumPy, но с указанным указателем данных. Убедитесь, что ваше изображение C/C++, содержащее указатель данных, живет дольше, чем массив NumPy. Массив NumPy может жить короче, потому что в этом случае он не будет пытаться удалить данные.
Буфер изображений C/C++ в качестве оболочки вокруг указателя массива NumPy. Создайте массив NumPy и извлеките указатель данных, а затем используйте его для манипулирования массивом NumPy на месте. Убедитесь, что массив NumPy живет достаточно долго, удерживая ссылку на Python.
Каждый из них может быть реализован в карте типов SWIG.
В любом случае вам нужно преобразование типов ваших типов в типы NumPy (NPY_UINT8, ..) и сохранение размеров изображения в npy_intp *
,
Для создания массива NumPy используйте PyArray_New
или же PyArray_SimpleNew
или же PyArray_SimpleNewFromData
( Array API) и укажите желаемые флаги, такие как непрерывный стиль Фортрана или что угодно удобное для вас. Вы можете предоставить свой собственный указатель данных с PyArray_New
а также PyArray_SimpleNewFromData
,
Возвращаемое значение PyObject*
которые можно смело приводить к PyArrayObject*
(или выполнить PyArray_Check
до) и указатель данных извлекается PyArray_DATA
( Array API), который возвращает void *
который вы можете затем привести к желаемому типу. Затем вы можете выполнить копирование или выполнить модификацию на месте по желанию.
Чтобы добавить ссылку на объект Python, используйте Py_INCREF
а также Py_DECREF
( doc) на случай, если вы хотите избежать преждевременного удаления массива NumPy.
Если вы хотите получать уведомления, когда объект Python собирается собирать мусор, используйте слабую ссылку через PyWeakref_NewRef
( док).