9

I have a numpy array which came from a cv2.imread and so has dtype = np.uint8 and ndim = 3.

I want to convert it to a Cython unsigned int* for use with an external cpp library.

I am trying cdef unsigned int* buff = <unsigned int*>im.data however I get the error Python objects cannot be cast to pointers of primitive types

What am I doing wrong?

Thanks

Ferguzz
  • 5,777
  • 7
  • 34
  • 41

2 Answers2

12

The more modern way would be to use a memoryview rather than a pointer:

cdef np.uint32_t[:,:,::1] mv_buff = np.ascontiguousarray(im, dtype = np.uint32)

The [:,;,::1] syntax tells Cython the memoryview is 3D and C contiguous in memory. The advantage of defining the type to be a memoryview rather than a numpy array is

  1. it can accept any type that defines the buffer interface, for example the built in array module, or objects from the PIL imaging library.
  2. Memoryviews can be passed without holding the GIL, which is useful for parallel code

To get the pointer from the memoryview get the address of the first element:

cdef np.uint32_t* im_buff = &mv_buff[0,0,0]

This is better than doing <np.uint32_t*>mv_buff.data because it avoids a cast, and casts can often hide errors.

DavidW
  • 29,336
  • 6
  • 55
  • 86
9

thanks for your comments. solved by:

cdef np.ndarray[np.uint32_t, ndim=3, mode = 'c'] np_buff = np.ascontiguousarray(im, dtype = np.uint32)
cdef unsigned int* im_buff = <unsigned int*> np_buff.data
Ferguzz
  • 5,777
  • 7
  • 34
  • 41
  • 1
    you should probably use `np.uint` instead of `np.uint32` (`unsigned int` might be 64-bit on some systems). – jfs May 24 '12 at 12:06
  • 2
    according to https://github.com/cython/cython/wiki/tutorials-NumpyPointerToC, &np_buff[0,0,0] would be better than np_buff.data – Syrtis Major Jul 02 '14 at 04:45