alliedvision / VimbaPython

Old Allied Vision Vimba Python API. The successor to this API is VmbPy
BSD 2-Clause "Simplified" License
93 stars 40 forks source link

miss frames #108

Open tianyu06030020 opened 2 years ago

tianyu06030020 commented 2 years ago

hi @NiklasKroeger-AlliedVision, I follow the supplied example: multithreading_opencv.py, and give a little modify, here is the snippet code:

class FrameProducer(threading.Thread): def init(self, cam: Camera, frame_queue: queue.Queue): threading.Thread.init(self)

    self.log = Log.get_instance()
    self.cam = cam
    self.frame_queue = frame_queue
    self.killswitch = threading.Event()

def __call__(self, cam: Camera, frame: Frame):
    # This method is executed within VimbaC context. All incoming frames
    # are reused for later frame acquisition. If a frame shall be queued, the
    # frame must be copied and the copy must be sent, otherwise the acquired
    # frame will be overridden as soon as the frame is reused.
    if frame.get_status() == FrameStatus.Complete:
        frame_cpy = copy.deepcopy(frame)

        global preview_flag, preview_queue, record_flag, record_queue
        if record_flag and self.frame_queue.full():
            try_put_frame(self.frame_queue, cam, frame_cpy)

        if preview_flag and not preview_queue.full():
            preview_queue.put_nowait(frame_cpy.as_opencv_image())

    cam.queue_frame(frame)

I add two queues in the callback function, one for video record and one for preview, the consumers are two threads to read frames from the relative queue, But I find:

when only record or preview, that's ok, when record and preview all started, heavily missing frames exist,

I test the queue's put and get time, very small, so I don't know why?

tianyu06030020 commented 2 years ago

hi @NiklasKroeger-AlliedVision, I follow the supplied example: multithreading_opencv.py, and give a little modify, here is the snippet code:

class FrameProducer(threading.Thread): def init(self, cam: Camera, frame_queue: queue.Queue): threading.Thread.init(self)

    self.log = Log.get_instance()
    self.cam = cam
    self.frame_queue = frame_queue
    self.killswitch = threading.Event()

def __call__(self, cam: Camera, frame: Frame):
    # This method is executed within VimbaC context. All incoming frames
    # are reused for later frame acquisition. If a frame shall be queued, the
    # frame must be copied and the copy must be sent, otherwise the acquired
    # frame will be overridden as soon as the frame is reused.
    if frame.get_status() == FrameStatus.Complete:
        frame_cpy = copy.deepcopy(frame)

        global preview_flag, preview_queue, record_flag, record_queue
        if record_flag and self.frame_queue.full():
            try_put_frame(self.frame_queue, cam, frame_cpy)

        if preview_flag and not preview_queue.full():
            preview_queue.put_nowait(frame_cpy.as_opencv_image())

    cam.queue_frame(frame)

I add two queues in the callback function, one for video record and one for preview, the consumers are two threads to read frames from the relative queue, But I find:

when only record or preview, that's ok, when record and preview all started, heavily missing frames exist,

I test the queue's put and get time, very small, so I don't know why?

btw, I used 1800 U-158m usb camera

NiklasKroeger-AlliedVision commented 2 years ago

when only record or preview, that's ok, when record and preview all started, heavily missing frames exist,

Could you elaborate a bit what you mean by "missing frames"? Do not all frames get written to the video or are they not all displayed? Are they maybe missing from both?

The try_put_frame function you are using will attempt to put a frame into the queue, but if the queue is already full, it will simply drop the frame that you are trying to put into the queue. Perhaps your video writer cannot keep up with the speed at which frames are put into the queue, so the queue fills up and the try_put_frame function discards them? You could try logging messages of those discards by changing the function to the following:

def try_put_frame(q: queue.Queue, cam: Camera, frame: Optional[Frame]):
    try:
        q.put_nowait((cam.get_id(), frame))

    except queue.Full:
        print(f'Could not add {frame} to the queue because the queue was full')

This should hopefully make it easier to see, if frames are discarded because the video writer cannot keep up with the frame production speed.

A similar thing might happen with your preview queue, though there you are using the put_nowait method directly. Beware that you are also not catching the queue.Full exception for that call so if your preview queue ever fills up, your program would crash.

Would it be possible for you to provide a runnable example for me to test? This would make support much easier.