aravis
aravis copied to clipboard
Crash with DFK 33UX273 Camera at 200 FPS and 1000 Exposure, Works Fine with Basler QCAM-UC1440-220CE
Hi!
Describe the bug When I use a camera The Imaging Source DFK 33UX273 with 200 fps and exposure 1000 my application crashes, but when I use a Basler QCAM-UC1440-220CE camera it doesn't crash
To Reproduce I set the camera to 1000 us of exposure and set the fps to 200
Expected behavior I hope to get the images for later processing with any camera
Camera description: CAMERA THAT OCCURS THE BUG
- Manufacturer The Imaging Source
- Model DFK 33UX273
- Interface USB3
CAMERA THAT DOESN'T OCCUR THE BUG
- Manufacturer Basler
- Model DFK QCAM-UC1440-220CE
- Interface USB3
Platform description:
- Aravis version 0.8.31
- OS: Debian GNU/Linux 12 (bookworm)
- Hardware Intel Atom(R) x6413E Processor @ 1.50GHz - 8G Memory
Additional context
capture loop
` def __non_triggered_capture(self):
with self.lock_var_to_update:
for i in range(1, 10):
buffer = self._stream.timeout_pop_buffer(10000 * 1000)
if buffer:
if not (buffer.get_status().value_name == 'ARV_BUFFER_STATUS_SUCCESS'):
continue
logging.info(self._stream.get_statistics())
img = self._converter(buffer)
timestamp = buffer.get_timestamp()
self._stream.push_buffer(buffer)
self.frame_id = (self.frame_id + 1) % (sys.maxsize - 1)
if img is None:
raise CameraError("Camera capture failed")
return img, self.frame_id, timestamp / 1000000
logging.warning(f"Failed capturing from camera {self.camera_id}, model {self.dev}. Retrying {10 - i} times")
raise CameraError("Camera capture failed")
`
img = self._converter(buffer)
if img is None:
raise CameraError("Camera capture failed")
Capture failed is raised when the call to converter() return a None. I don't know what converter() is supposed to do.
It is a function to convert img in raw format to numpy array
def _converter(self, buf):
if not buf:
return None
pixel_format = buf.get_image_pixel_format()
bits_per_pixel = pixel_format >> 16 & 0xff
# Determine the appropriate ctypes data type based on bits per pixel
if bits_per_pixel == 8:
INTP = ctypes.POINTER(ctypes.c_uint8)
bytes_per_pixel = 1
elif bits_per_pixel == 16:
INTP = ctypes.POINTER(ctypes.c_uint16)
bytes_per_pixel = 2
elif bits_per_pixel == 24:
INTP = ctypes.POINTER(ctypes.c_uint8)
bytes_per_pixel = 3
elif bits_per_pixel == 32:
INTP = ctypes.POINTER(ctypes.c_uint8)
bytes_per_pixel = 4
else:
raise ValueError(f"Unsupported bits per pixel: {bits_per_pixel}")
addr = buf.get_data()
ptr = ctypes.cast(addr, INTP)
height = buf.get_image_height()
width = buf.get_image_width()
# Determine the number of channels based on bytes per pixel
if bytes_per_pixel == 1:
im = np.ctypeslib.as_array(ptr, (height, width))
else:
im = np.ctypeslib.as_array(ptr, (height, width, bytes_per_pixel))
# Copy the image to ensure it is not a view into the original buffer
im = im.copy()
return im
Thanks.
At some point in the log, the payload size returned in the image trailer packet changes from 4665600 to 187396. Do you change some features between 2 call to __non_triggered_capture ?
Yes, after initializing the camera the application starts capturing(using __non_triggered_capture) and then during the capture the application configure some features, such as exposure, gain and gamma, for example.
exposure, gain and gamma
Is this an exhaustive list ? Any feature that may modify the payload size ?
Full list: frame rate region exposure time exposure auto gain gamma balance ration balance white auto trigger activation trigger delay trigger
I think the only part that can change the payload size is the part where I configure the image size(which I called region in the list above).
set window size method
# makes the x's and y's a multiple of 4
x0 -= x0 % 4
x1 -= x1 % 4
y0 -= y0 % 4
y1 -= y1 % 4
self.cam.stop_acquisition()
self.cam.set_region(
x0, # offset x
y0, # offset y
max(x1 - x0, 16), # 16*8 pixel minimal image
max(y1 - y0, 8),
)
self.create_buffer()
self.cam.start_acquisition()
create buffer method
def create_buffer(self):
if hasattr(self, '_stream'):
del self._stream
self._stream = self.cam.create_stream(None, None)
payload = self.cam.get_payload()
for _ in range(0, 10):
self._stream.push_buffer(Aravis.Buffer.new_allocate(payload))
You should also stop the acquisition thread when you want to set the region, otherwise there will still be buffer with the wrong size in the queues. Please have a look at tests/arvroitest.c, switch_roi() function.