6
votes

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

2
The answers to this one probably help: stackoverflow.com/q/3046305/222914 - Janne Karila
Note also that np.uint8 is unsigned char, not unsigned int. - Janne Karila

2 Answers

8
votes

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
6
votes

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.