TheImagingSource/ic4-examples

Queue sink not working with DMK 33UX249 camera

Closed this issue · 2 comments

Hello,
in our lab we use mainly two models of cameras DMK 33UX174 and DMK 33UX249. However If I was trying to acuire with the queue sink with the DMK 33UX249 the method frames_queued of the Queue Sink Listener was never called, as in contrast to usage with DMK 33UX174. Do you know what could be the issue?

Here I share the code used:

import time
import numpy as np

import imagingcontrol4 as ic4

# Initialize library
ic4.Library.init()


class PrintChunkExposureTimeListener(ic4.QueueSinkListener):
    prop_map: ic4.PropertyMap

    def __init__(self, prop_map: ic4.PropertyMap):
        self.prop_map = prop_map

    def sink_connected(self, sink: ic4.QueueSink, image_type: ic4.ImageType, min_buffers_required: int) -> bool:
        print("Sink connected")
        return True

    def frames_queued(self, sink: ic4.QueueSink):
        # Do not throw from callback function, capture and log errors instead
        try:
            print("\nthere are frames in the queue!")
            print(
                f"Queue size: {sink.queue_sizes().free_queue_length} free, {sink.queue_sizes().output_queue_length} output")
            # if the queue length is smaller than 1, we can add more buffers
            buffer = sink.pop_output_buffer()
            print(f"Received image buffer with {buffer}")
            print(f"Metadata {buffer.meta_data}")
            buffer_np = buffer.numpy_wrap()
            print(f"Buffer shape: {buffer_np.shape}")
            print(
                f"Queue size: {sink.queue_sizes().free_queue_length} free, {sink.queue_sizes().output_queue_length} output")
            # to simulate slow SW
            # time.sleep(0.3)

            # print("")

            # print(f"Received image buffer with {buffer}")

            # if buffer.frame_number == 10:
            #     print("Clearing buffer queue")
            #     sink.clear_output_buffers()

            # # Use the image buffer as backend for read operations on chunk properties
            # self.prop_map.connect_chunkdata(buffer)

            # # Read chunk property from image buffer
            # val = self.prop_map.get_value_float(ic4.PropId.CHUNK_EXPOSURE_TIME)
            # print(f"ChunkExposureTime = {val}")
            # get the queu sizes

        except ic4.IC4Exception as ex:
            print(
                f"Error trying to request ChunkExposuretime: {ex.code} ({ex.message})")
        finally:
            # Disconnecting is not strictly necessary, but will release the buffer for reuse earlier
            self.prop_map.connect_chunkdata(None)

    def sink_disconnected(self, sink: ic4.QueueSink):
        print("Sink disconnected")
        pass


class Camera:

    def __init__(self, serial: str):
        print(64*'=')
        print("Camera object created")
        print(64*'=')
        self._get_grabber(serial)

        # Configure the device to output images in the Mono16 pixel format
        self.grabber.device_property_map.set_value(
            ic4.PropId.PIXEL_FORMAT, ic4.PixelFormat.Mono16)

        # get the width and height of the image
        self.width = self.get_property('Width')
        self.height = self.get_property('Height')

        self.grabber.device_property_map.set_value(
            ic4.PropId.EXPOSURE_AUTO, "Off")
        self.grabber.device_property_map.set_value(
            ic4.PropId.EXPOSURE_TIME, 100.0)

        # set framerate to 10fps
        self.grabber.device_property_map.set_value(
            ic4.PropId.ACQUISITION_FRAME_RATE, 10.0)

        self.latest_frame = np.zeros(
            (self.height, self.width), dtype=np.uint16)

    def _get_grabber(self, serial_number):
        self.grabber = ic4.Grabber()

        print(f"Available devices: {ic4.DeviceEnum.devices()}")

        for device_info in ic4.DeviceEnum.devices():
            if device_info.serial == serial_number:
                self.model = device_info.model_name
                self.grabber.device_open(device_info)

    def setup_continuous_acquisition(self, max_queue_size=4):
        prop_map = self.grabber.device_property_map
        self.queue_listener = PrintChunkExposureTimeListener(prop_map)
        self.sink = ic4.QueueSink(
            self.queue_listener, max_output_buffers=max_queue_size)

        self.grabber.stream_setup(
            self.sink, setup_option=ic4.StreamSetupOption.ACQUISITION_START)

    def get_info(self):
        print("\nINFO:")
        print(64*"-")
        print(
            f"Queue size: {self.sink.queue_sizes().free_queue_length} free, {self.sink.queue_sizes().output_queue_length} output")
        print(f"Is streaming: {self.grabber.is_streaming}")
        print(f"{self.get_property(ic4.PropId.EXPOSURE_TIME)=}")
        print(f"{self.get_property(ic4.PropId.ACQUISITION_FRAME_RATE)=}")
        print(64*'-')

    def stop_acquisition(self):
        self.grabber.stream_stop()

    def get_property(self, property_name):
        return self.grabber.device_property_map.find(property_name).value

    def close_device(self):
        self.grabber.device_close()


if __name__ == "__main__":
    desired_serial = "53020434"  # serial of model DMK 33UX174
    desired_serial = "53020426"  # serial of model DMK 33UX249
    camera = Camera(desired_serial)
    camera.setup_continuous_acquisition()
    for i in range(5):
        camera.get_info()
        time.sleep(0.3)
    camera.get_info()
    camera.stop_acquisition()
    camera.close_device()

Hello,
the most common reason for this would be that the camera is left in trigger mode from some previous usage in a different program.
Can you check using ic4-demoapp or IC Capture?

If this is indeed your problem, you can also reset all camera settings to default before applying your configuration, as shown here:

grabber.device_property_map.set_value(ic4.PropId.USER_SET_SELECTOR, "Default")
grabber.device_property_map.execute_command(ic4.PropId.USER_SET_LOAD)

That helped, thank you!