Pass a numpy array to a C function in cython
Question: I'm wrapping a third party camera library interface with Cython so I can call
it from a python program. For the most part things work very well, but I've
hit a snag in my acquireImage() function. I've tried to create a contiguous
numpy array, pass that to the library, and pick up the result after the
library has finished populating it. Finally, I want to copy that array,
reshape it and return it. (The reshape stuff hasn't been coded yet)

Here is my code:

cpixis.pxd:

    
    
    ctypedef bint rs_bool
    ctypedef unsigned short uns16
    ctypedef short int16
    ctypedef unsigned int uns32
    ctypedef unsigned int* uns32_ptr
    ctypedef void* void_ptr
    ctypedef char* char_ptr
    ctypedef short* int16_ptr
    ctypedef struct rgn_type:
            short s1
            short s2
            short sbin
            short p1
            short p2
            short pbin
    ctypedef rgn_type* rgn_const_ptr
    ctypedef rgn_type* rgn_ptr
    
    #cdef CAM_NAME_LEN 32
    
    cdef extern from "/usr/local/pvcam/examples/pvcam.h":
        cdef enum cam_open:
            OPEN_EXCLUSIVE
        cdef enum exposure:
            TIMED_MODE, STROBED_MODE, BULB_MODE, TRIGGER_FIRST_MODE, FLASH_MODE, VARIABLE_TIMED_MODE, INT_STROBE_MODE
        cdef enum readout:
            READOUT_NOT_ACTIVE, EXPOSURE_IN_PROGRESS, READOUT_IN_PROGRESS, READOUT_COMPLETE, 
            FRAME_AVAILABLE = READOUT_COMPLETE, READOUT_FAILED, ACQUISITION_IN_PROGRESS, MAX_CAMERA_STATUS
        rs_bool pl_pvcam_init()
        rs_bool pl_pvcam_uninit()
        rs_bool pl_cam_get_name(int16 cam_num, char_ptr camera_name)
        rs_bool pl_cam_open(char_ptr camera_name, int16_ptr hcam, int16 o_mode)
        rs_bool pl_cam_close(int16 hcam)
        rs_bool pl_pvcam_uninit()
        rs_bool pl_exp_init_seq()
        rs_bool pl_exp_setup_seq (int16 hcam, uns16 exp_total,
                                  uns16 rgn_total, rgn_const_ptr rgn_array,
                                  int16 exp_mode, uns32 exposure_time,
                                  uns32_ptr exp_bytes)
        rs_bool pl_exp_start_seq (int16 hcam, void_ptr pixel_stream)
        rs_bool pl_exp_check_status (int16 hcam, int16_ptr status, uns32_ptr bytes_arrived)
        int16 pl_error_code()
        rs_bool pl_exp_finish_seq (int16 hcam, void_ptr pixel_stream, int16 hbuf)
        rs_bool pl_exp_uninit_seq ()
    

pixis.pyx:

    
    
    cimport cpixis
    from cpython.mem cimport PyMem_Malloc, PyMem_Free
    cimport numpy as np
    import ctypes
    
    
    cdef class Camera:
        cdef cpixis.rgn_type* _region
        cdef cpixis.int16 _cam_selection
        cdef cpixis.int16 _num_frames
        cdef cpixis.uns32 _exp_time
        cdef char _cam_name[32]
        cdef cpixis.int16 _hCam
        cdef cpixis.uns32 _size
        cdef cpixis.int16 _status
        cdef cpixis.uns32 _notNeeded
        #cdef cpixis.uns16* _frame
    
    
    
        def __cinit__(self):
            self._region = <cpixis.rgn_type *> PyMem_Malloc(sizeof(cpixis.rgn_type))
            if self._region is NULL:
                raise MemoryError()
            #self._frame = <cpixis.uns16 *> PyMem_Malloc( self._size *2 )
            if self._region is NULL:
                raise MemoryError()
            self._cam_selection = 0
            self._num_frames = 1
            self._exp_time = 100
        def __dealloc__(self):
            cpixis.pl_cam_close(self._hCam)
            cpixis.pl_pvcam_uninit()
            if self._region is not NULL:
                PyMem_Free(self._region)
            #if self._frame is not NULL:
            #   PyMem_Free(self._frame)
        def initCamera(self):
            if cpixis.pl_pvcam_init() == False:
                print "Camera failed to init"
                quit()
            if cpixis.pl_cam_get_name(self._cam_selection, self._cam_name) == False:
                print "Didn't get camera name"
                quit()
            if cpixis.pl_cam_open(self._cam_name, &self._hCam, cpixis.OPEN_EXCLUSIVE ) == False:
                print "Camera did not open"
                quit()
        def setRegionOfInterest(self, s1, s2, sbin, p1, p2, pbin):
            self._region.s1 = s1
            self._region.s2 = s2
            self._region.sbin = sbin
            self._region.p1 = p1
            self._region.p2 = p2
            self._region.pbin = pbin
        def acquireImage(self, exposureTime):
            cdef np.ndarray[np.uint16_t, ndim=1] _frame
            self._exp_time = exposureTime
            if cpixis.pl_exp_init_seq() == False:
                print "init_seq Failed"
            if cpixis.pl_exp_setup_seq( self._hCam, 1, 1, self._region, cpixis.TIMED_MODE, self._exp_time, &self._size ) == False:
                print "Experiment failed"
            self.image = np.ndarray(shape=(self._size), dtype=np.uint16, order='C')
            self._frame = np.ascontiguousarray(self.image, dtype=ctypes.c_ushort)
            cpixis.pl_exp_start_seq( self._hCam, &self._frame[0] ); # start image acqusition
            while cpixis.pl_exp_check_status(self._hCam, &self._status, &self._notNeeded) \
                  and (self._status != cpixis.READOUT_COMPLETE and self._status != cpixis.READOUT_FAILED):
                pass
            cpixis.pl_exp_finish_seq(self._hCam, &self._frame[0], 0)
            cpixis.pl_exp_uninit_seq()
            self.image = np.copy(self._frame)
            return self.image
    

Lines 64 and 66 have the same error, which is "**Cannot take address of Python
variable.** " I've been working from another similar question
[here](https://stackoverflow.com/questions/23435756/passing-numpy-integer-
array-to-c-code).

Is there a way to make this work, or should I approach this problem
differently?

Thanks!


Answer: In the acquireImage() function, I was using the correct idea, but forgot to
remove the "self" from the self._frame references. I had started out with
_frame declared as a non local variable, but then forgot to update the
references in the function when I moved it to a local scope. I removed the
extra selfs and the problem went away.

