Хранение данных с использованием PyArray_NewFromDescr - PullRequest
0 голосов
/ 28 мая 2018

Я использую Cython, и мне нужно хранить данные, как показано ниже.Ранее я использовал циклы для хранения данных из pus_image[0] в трехмерный массив, но при работе для n frames это создавало узкое место в производительности.Поэтому я использовал PyArray_NewFromDescr для хранения, что решает проблему узкого места, с которой мы столкнулись ранее.Но отображаемые изображения выглядят иначе, чем в предыдущем методе, так как я не могу сделать приращение _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

1 Ответ

0 голосов
/ 04 июня 2018

Есть несколько больших ошибок в том, как вы это делаете.Однако то, что вы делаете, совершенно не нужно, и есть гораздо более простой подход.Вы можете просто распределить данные с помощью 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 и использовать вместо него массивы для размещения ваших данных.

...