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)
exposure_time = 300
readlock = threading.Lock()
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_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. )
if readlock.acquire() :
start_time = time.time()
(lib.XC_CopyFrameBuffer(xcamera_id, fbuffer, frame_size) )
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"
lib.XC_StopCapture(xcamera_id)
lib.XC_SetFan(xcamera_id, False)
lib.XC_CloseCamera(xcamera_id)
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

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