Reading frame buffer from camera using ctypes

I am having trouble reading the frame of the camera buffer using python . The camera (Xenics) connects via USB and there is a dll that comes with the camera. I am accessing this dll using ctypes. The code I'm using is mostly inspired by the python module for lantz ( lantz_drivers_xenics ).
Dll provides a function XC_CopyFrameBufferthat I use to copy the framebuffer to a numpy array.

Despite the fact that, in principle, the acquisition works fine, the problem is to constantly read the framebuffer at moderate or high speed. The compiled software that came with the camera can read the camera at 24 frames per second. In my program, I would like to read a framebuffer with something from 5 to 25 frames per second. However, I cannot reach this value because the time it takes to call the function XC_CopyFrameBuffervaries from 0 to ~ 0.5 seconds ; it's mostly low, but 0.5 seconds for about every third frame or so.

My real program is more complicated, uses streams and processes the received images. But I reduced the code to a minimal example that reproduces the problem and that I am attaching. Text and graphic output are shown below. My question is:

  • Has anyone encountered similar issues with cameras?
  • Has anyone used the Xenics camera associated with it via ctypes in python and could serve as a working example of this?
  • Is there any obvious or hidden problem in how I (and / or lantz_drivers_xenics) use a DLL?

This is the code I'm using:

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()

A typical output looks something like this: the time it takes to copy the frame buffer.

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

And the plot is (where the image looks exactly as intended). The right graph shows the time in seconds for each frame

enter image description here

Comments:

  • I work in python 2.7
  • I played with some parameters:
    • Adding time.sleep(x)with different values ​​for x at different positions of the loop leads to an increase in the number of frames that read 0.5 s. The longer the sleep time, the longer the frame is read.
    • Ommiting time.sleep( exposure_time/1000000. ) .
    • , readlock.acquire() .
    • .
+4

Source: https://habr.com/ru/post/1659121/


All Articles