首页 > 解决方案 > 使用 PyArray_NewFromDescr 存储数据

问题描述

我使用 cython,我需要存储数据,如下所示。早些时候,我使用 for 循环将数据存储pus_image[0]到 3D 数组中,但在运行n frames它时会产生性能瓶颈。因此,我曾经PyArray_NewFromDescr存储解决了之前面临的瓶颈问题。但是显示的图像看起来与以前的方法不同,因为我无法进行 increment _puc_image += aoiStride。谁能帮我解决这个问题。


代码 1:

    def LiveAquisition(self,nframes,np.ndarray[np.uint16_t,ndim = 3,mode = 'c']data):
    cdef:
        int available
        AT_64 sizeInBytes
        AT_64 aoiStride
        AT_WC string[20]
        AT_WC string1[20]
        AT_WC string2[20]
        AT_WC string3[20]
        unsigned char * pBuf
        unsigned char * _puc_image
        int BufSize
        unsigned int i, j, k, l = 0

    for i in range(nframes):
        pBuf = <unsigned char *>calloc(sizeInBytes, sizeof(unsigned char))
        AT_QueueBuffer(<AT_H>self.cameraHandle, pBuf, sizeInBytes)

        print "Frame number is :",
        print i
        response_code = AT_WaitBuffer(<AT_H>self.cameraHandle, &pBuf, &BufSize, 500)

        _puc_image = pBuf
        pus_image = <unsigned short*>pBuf
        for j in range(self.aoiWidth/self.hbin):
            pus_image = <unsigned short*>(_puc_image)
            for k in range(self.aoiHeight/self.vbin):
                data[l][j][k]  = pus_image[0]
                pus_image += 1
            _puc_image += aoiStride

    free(pBuf)
    return data

代码2:使用PyArray_NewFromDescr 之前其定义为:

from cpython.ref cimport PyTypeObject
from python_ref cimport Py_INCREF


cdef extern from "<numpy/arrayobject.h>":
object PyArray_NewFromDescr(PyTypeObject *subtype, np.dtype descr,int nd, np.npy_intp* dims,np.npy_intp*strides,void* data, int flags, object obj)

    def LiveAquisition(self,nframes,np.ndarray[np.uint16_t,ndim = 3,mode = 'c']data):
    cdef:
        int available
        AT_64 sizeInBytes
        AT_64 aoiStride
        AT_WC string[20]
        AT_WC string1[20]
        AT_WC string2[20]
        AT_WC string3[20]
        unsigned char * pBuf
        unsigned char * _puc_image
        int BufSize
        unsigned int i, j, k, l = 0
        np.npy_intp dims[2]
        np.dtype dtype = np.dtype('<B')


    for i in range(nframes):
        pBuf = <unsigned char *>calloc(sizeInBytes, sizeof(unsigned char))
        AT_QueueBuffer(<AT_H>self.cameraHandle, pBuf, sizeInBytes)
        print "Frame number is :",
        print i
        response_code = AT_WaitBuffer(<AT_H>self.cameraHandle, &pBuf, &BufSize, 500)

        Py_INCREF(dtype)
        dims[0] = self.aoiWidth
        dims[1] = self.aoiHeight
        data[i,:,:] = PyArray_NewFromDescr(<PyTypeObject *> np.ndarray, np.dtype('<B'), 2,dims, NULL,pBuf, np.NPY_C_CONTIGUOUS, None)

    free(pBuf)
    return data

标签: pythoncython

解决方案


您执行此操作的方式存在一些大错误。但是,您所做的完全没有必要,并且有一种更简单的方法。您可以简单地使用 Numpy 分配数据,并获取该数组的第一个元素的地址:

# earlier
cdef unsigned char[:,::1] p
# in loop
p = np.array((self.aoiWidth,self.aoiHeight),dtype=np.uint8)
pbuf = &p[0,0] # address of first element of p

# code goes here
data[i,:,:] = p

你正在做的错误:

  1. pBuf = <unsigned char *>calloc(sizeInBytes, sizeof(unsigned char))

    在这里,sizeInBytes未初始化,因此您分配的大小是任意的。

  2. PyArray_NewFromDescr 窃取descr论点的引用。这意味着它不会增加参数的引用计数。线

    PyArray_NewFromDescr(<PyTypeObject *> np.ndarray, np.dtype('<B'), ...)
    

    将被翻译为 Cython 之类的东西

    temp_dtype = np.dtype('<B') # refcount 1
    PyArray_NewFromDescr(<PyTypeObject *> np.ndarray, temp_dtype, ...)
    # temp_dtype refcount is still 1
    Py_DECREF(temp_dtype) # Cython's own cleanup
    # temp_dtype has now been destroyed, but is still being used by your array
    

    看起来您复制了一些正确处理此问题的代码(Py_INCREF(dtype)然后将其传递给PyArray_NewFromDescr),但选择忽略它并创建您自己的临时对象。

  3. PyArray_NewFromDescr不拥有数据。因此,您有责任在它被使用后重新分配它(并且只有在您确定不再需要它时)。你只做一个free, 在循环之后,所以你几乎泄漏了你分配的所有内存。要么将 置于free循环中,要么修改OWNDATA标志以赋予您的阵列的新阵列所有权。


总之,除非您对 Python C API 有很好的理解,否则我建议不要使用PyArray_NewFromDescr和使用 numpy 数组来分配数据。


推荐阅读