-2

I have two numpy 3D-array in python with different height and width. I want to pass them to my C-Extension. How can I resize and subtract them in c++? Please see the comments in the code.

static PyObject *my_func(PyObject *self, PyObject     *args)
{
    Py_Initialize();
    import_array();


    PyObject *arr1;
    PyObject *arr2;

    if(!PyArg_ParseTuple(args, "OO", &arr1, &arr2)) 
    {
        return NULL;
    }

    //How can I do this?

    //resize arr1 to [100, 100, 3]
    //resize arr2 to [100, 100, 3]
    //res = arr1 - arr2
    //return res
}
Iman
  • 424
  • 5
  • 18
  • 1
    Why would you do this in a extension module? That's straight-forward to do with pure python and it's likely as fast (probably only a few microseconds slower). – MSeifert May 29 '17 at 13:54
  • Unrelated, but if you really want to push extending your code with C++ I'd consider a wrapper language. They are much easier and robust. Consider for example Cython, ctypes, swig, or my latest favorite: pybind11 – Tom de Geus May 29 '17 at 14:05
  • @MSeifert My real problem is not exactly the same as this, but the most important part of the solution is how to resize and subtract numpy array in python. I know this is easy in python. – Iman May 30 '17 at 05:40
  • @TomdeGeus Thank you for your answer but it is not releated! My question is abvious.I want to do this with python c api not Cyton, ctype, boost, etc. – Iman May 30 '17 at 05:42

1 Answers1

3

Start by making the desired shape. It's easier to do this as a tuple than a list:

PyObject* shape = Py_BuildValue("iii",100,100,3);

Check this against NULL to ensure do error has occurred and handle if it has.

You can call the numpy resize function on both arrays to resize them. Unless you are certain that the data isn't shared then you need to call numpy.resize rather than the .resize method of the arrays. This involves importing the module and getting the resize attribute:

PyObject* np = PyImport_ImportModule("numpy");
PyObject* resize = PyObject_GetAttrString(np,"resize");
PyObject* resize_result = PyObject_CallFunctionObjArgs(resize,arr1, shape,NULL);

I've omitted all the error checking, which you should do after each stage.

Make sure you decrease the reference counts on the various PyObjects once you don't need them any more.

Use PyNumber_Subtract to do the subtraction (do it on the result from resize).


Addition: A shortcut for calling resize that should avoid most of the intermediates:

 PyObject* np = PyImport_ImportModule("numpy");
 // error check against null
 PyObject* resize_result = PyObject_CallMethod(np,"resize","O(iii)",arr1,100,100,3);

(The "(iii)" creates the shape tuple rather than needing to do it separately.)


If you are certain that arr1 and arr2 are the only owners of the data then you can call the numpy .resize method either by the normal C API function calls or the specific numpy function PyArray_Resize.

DavidW
  • 29,336
  • 6
  • 55
  • 86
  • Thank you for your answer. PyNumber_Subtract worked but resize didn't. Is this for Python3? or Python2? – Iman May 30 '17 at 07:34
  • PyObject* res = PyArray_SimpleNewFromData(3, dims, NPY_UINT8, FreeImage_GetBits(dib)); PyObject* shape = Py_BuildValue("iii",100,100,3); PyObject* tmp1 = PyObject_CallMethodObjArgs(res,"resize",shape, NULL); it gives compile error. "error: cannot convert ‘const char*’ to ‘PyObject*" – Iman May 30 '17 at 07:39
  • When I change "resize" to "Py_BuildValue("s","resize")" code compiled successfully but gives error in python: "ValueError: cannot resize this array: it does not own its data" – Iman May 30 '17 at 07:42
  • How can I solve this? and second question, may you give me a snippet for PyArray_Resize function? I couldn't use it because it requests PyArrayObject instead of PyObject. casting with (PyArrayObject)obj not working. – Iman May 30 '17 at 07:45
  • I've fixed the resize code hopefully. You need to call `numpy.resize` rather than `arr1.resize` because the array doesn't seem to be the sole owner of the data. `PyArray_Resize` would run into the same problem. In general though, you'd check that the object is an array with `PyArray_Check` and then cast to the pointer `(PyArrayObject*)obj`. – DavidW May 30 '17 at 08:07