使用ctypes从相机读取帧缓冲区

Imp*_*est 5 python camera ctypes framebuffer driver

我在使用python读取相机的帧缓冲区时遇到问题。相机(Xenics)通过USB连接,相机随附一个dll。我使用ctypes访问此dll。我使用的代码主要受lantz的python模块(lantz_drivers_xenics)启发。
dll提供了XC_CopyFrameBuffer我用来将帧缓冲区复制到numpy数组的功能。

虽然原则上采集工作正常,但麻烦在于以中等或高速连续读取帧缓冲区。相机随附的已编译软件能够以24 fps的速度读出相机。在我的程序中,我想读取5到25 fps之间的帧缓冲区。但是,我无法达到此值,因为调用XC_CopyFrameBuffer函数所需的时间在0到〜0.5秒之间;它通常很低,但是大约每三帧大约需要0.5秒。

我的真实程序更复杂,使用线程并处理获取的图像。但是我将代码简化为一个重现问题并已附加的最小示例。它的文本和图形输出如下所示。我的问题是:

  1. 有没有人遇到过类似的相机问题?
  2. 有没有人使用过Xenics相机,并通过python中的ctypes连接到它,并可以提供一个可行的示例?
  3. 我(和/或lantz_drivers_xenics)使用dll的方式中是否存在一些明显或隐藏的问题?

这是我正在使用的代码:

import time
import ctypes 
import threading
import numpy as np
from numpy.ctypeslib import ndpointer


calibration_file =  r"C:\Path\to\some\calibrationfile.xca"
dll = "C:\\Programme\\X-Control\\xcamera.dll"
lib = ctypes.WinDLL(dll) #for xcamera we need ctypes.WinDLL

exposure_time = 300 #microseconds (us)
readlock = threading.Lock()

#add types    
lib.XC_OpenCamera.argtypes = [ctypes.c_uint]
lib.XC_CloseCamera.argtypes = [ctypes.c_uint]
lib.XC_IsInitialised.argtypes = [ctypes.c_uint]
lib.XC_LoadFromFile.argtypes = [ctypes.c_uint, ctypes.c_char_p]
lib.XC_LoadCalibrationPack.argtypes = [ctypes.c_uint, ctypes.c_char_p]
lib.XC_SetGainCamera.argtypes = [ctypes.c_uint, ctypes.c_double]
lib.XC_SetIntegrationTime.argtypes = [ctypes.c_uint, ctypes.c_ulong]

lib.XC_SetFan.argtypes = [ctypes.c_uint, ctypes.c_bool]
lib.XC_StartCapture.argtypes = [ctypes.c_uint]
lib.XC_StopCapture.argtypes = [ctypes.c_uint]
lib.XC_GetFrameSizeInBytes.argtypes = [ctypes.c_uint]
lib.XC_CloseCamera.restype = ctypes.c_void_p
lib.XC_StopCapture.restype = ctypes.c_void_p

xcamera_id = lib.XC_OpenCamera(0)

#lib.XC_LoadFromFile(xcamera_id,  self.config_file)
lib.XC_LoadCalibrationPack(xcamera_id,  calibration_file)
height = lib.XC_GetHeight(xcamera_id)
width = lib.XC_GetWidth(xcamera_id)
shape = (height, width)
lib.XC_CopyFrameBuffer.argtypes = [ctypes.c_uint, ndpointer(dtype=np.uint16, shape=shape),ctypes.c_uint]
frame_size = lib.XC_GetFrameSizeInBytes(xcamera_id)
fbuffer = np.zeros(shape=shape, dtype=np.uint16)

lib.XC_SetIntegrationTime(xcamera_id, exposure_time)
lib.XC_SetFan(xcamera_id,  True)

lib.XC_StartCapture(xcamera_id)

times = []

for i in range(150):

    time.sleep( exposure_time/1000000. ) #  1./25
    if readlock.acquire() : 
        start_time = time.time()
        (lib.XC_CopyFrameBuffer(xcamera_id, fbuffer, frame_size) )
        #time.sleep(0.0002)
        now = time.time()
        readlock.release()

        print "Frame {nr}\ttime: {time}".format(time=now-start_time, nr=i)
        times.append(now-start_time)
    else:
        time.sleep(0.001)
        print "Try again" #This gets never printed, so readlock works fine.


###### CLOSING ###########
lib.XC_StopCapture(xcamera_id)
lib.XC_SetFan(xcamera_id,  False)
lib.XC_CloseCamera(xcamera_id)                                         

###### Plot ###########
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(121)
ax.imshow(fbuffer, interpolation="none")
ax2 = fig.add_subplot(122)
ax2.plot(times)
plt.savefig("testing/readout.png")
plt.show()
Run Code Online (Sandbox Code Playgroud)

典型的输出看起来像这样,其中时间是复制帧缓冲区所花费的时间。

Frame 72    time: 0.0
Frame 73    time: 0.0
Frame 74    time: 0.000999927520752
Frame 75    time: 0.512000083923
Frame 76    time: 0.000999927520752
Frame 77    time: 0.0
Frame 78    time: 0.516000032425
Frame 79    time: 0.0
Frame 80    time: 0.000999927520752
Frame 81    time: 0.516000032425
Frame 82    time: 0.0
Frame 83    time: 0.0
Frame 84    time: 0.514000177383
Frame 85    time: 0.0
Frame 86    time: 0.0759999752045
Run Code Online (Sandbox Code Playgroud)

绘制的图形就是这样(图像看上去完全像它应该的那样)。右图显示每帧的时间(以秒为单位)

在此处输入图片说明

评论:

  • 我正在使用python 2.7
  • 我玩了一些参数:
    • time.sleep(x)在循环中的不同位置为x 添加不同的值具有增加读取0.5s的帧数的效果。睡眠时间越长,读取的帧越长。
    • 省略time.sleep( exposure_time/1000000. )提供空框架。
    • 问题与我是否使用readlock.acquire()无关。
    • 问题与循环数无关。