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

How to use asynchronous capture with multiple cameras? #96

Open OvervCW opened 2 years ago

OvervCW commented 2 years ago

I'm trying to stream frames from two cameras at the same time (Allied Vision 1800 U-2050c, Allied Vision 1800 U-2460c) using the following code:

from vimba import Camera, Frame, FrameStatus, PixelFormat, Vimba
import time
import threading

def setup_camera(cam: Camera) -> None:
    cam.set_pixel_format(PixelFormat.Mono8)

    cam.AcquisitionMode.set("Continuous")
    cam.BinningVertical.set(1)
    cam.BinningHorizontal.set(1)

    cam.Width.set(5328)
    cam.Height.set(3672)

    cam.ExposureAutoMin.set(1000.0)
    cam.ExposureAutoMax.set(20000.0)
    cam.ExposureTime.set(20000.0)
    cam.Gain.set(10.0)

    cam.AcquisitionFrameRateEnable.set(True)
    cam.AcquisitionFrameRate.set(1)

class Handler:
    def __init__(self, idx: int):
        self._idx = idx

    def __call__(self, camera: Camera, frame: Frame) -> None:
        if frame.get_status() == FrameStatus.Complete:
            print(f"{time.monotonic()} - cam #{self._idx}: complete frame")
        else:
            print(f"{time.monotonic()} - cam #{self._idx}: failed frame: {frame}")

        camera.queue_frame(frame)

stop_running = False

def capture_thread(idx, cam):
    global stop_running

    setup_camera(cam)

    handler = Handler(idx)

    cam.start_streaming(handler=handler, buffer_count=2)

    while not stop_running:
        time.sleep(1.0)

    cam.stop_streaming()

with Vimba.get_instance() as vimba:
    cameras = vimba.get_all_cameras()

    with cameras[0] as cam0:
        with cameras[1] as cam1:
            t0 = threading.Thread(target=capture_thread, args=(0, cam0))
            t1 = threading.Thread(target=capture_thread, args=(1, cam1))

            t0.start()
            t1.start()

            input("press enter to stop\n")
            stop_running = True

            t0.join()
            t1.join()

I would expect the handlers in both threads to be regularly called using a frame from the associated camera, but in practice only the handler for the first camera (with index 0) is actually called.

Sample output:

press enter to stop
1213137.914160055 - cam #0: complete frame
1213138.914284494 - cam #0: complete frame
1213141.914462255 - cam #0: complete frame
1213144.914603388 - cam #0: complete frame
1213145.91475032 - cam #0: complete frame
1213148.914914694 - cam #0: complete frame
...

If I change the two binning values to 2 then it does work:

press enter to stop
1213817.792815084 - cam #1: complete frame
1213818.743061794 - cam #0: complete frame
1213818.792745757 - cam #1: complete frame
1213819.74312082 - cam #0: complete frame
1213819.792785887 - cam #1: complete frame
...

The change in behavior based on the binning value would suggest a problem with bandwidth, but I find it hard to believe that I would be running into bandwidth problems at a frame rate of 1 with monochrome images.

What am I doing wrong? How do I capture full resolution frames from both cameras?

arunprakash-avt commented 2 years ago

Thank you for generating this issue. We recommend our Multithreading example for mutli cameras. Please find them in the example folder.

kriskorrel-cw commented 2 years ago

For future reference, my colleague @OvervCW got this to work by: