basler / pypylon-samples

BSD 3-Clause "New" or "Revised" License
42 stars 15 forks source link

Three Basler acA4024-29uc cannot capture more than 3 FPS same time #5

Open tannguyen1110 opened 1 year ago

tannguyen1110 commented 1 year ago

Hello, I have three Basler acA4024-29uc (all 3 connect to 1 usb hub and then to a laptop) and I want them capture image at least 5 FPS at the same time. But the fastest FPS I can reach is 2,5 (time to retrieved each image is 0.4 sec). If I change FPS more than 3 the result time to retrieved each image cannot lower 0.37 sec. If I run with only 1 camera, time to retrieved is around 0.05 sec. Please help, this is my code: Thank you.

============================================

from pypylon import pylon import numpy as np

import traceback

import time import random

def BackGroundLoopSample(): print("hello multicam_cont")

maxCamerasToUse = 3

img = pylon.PylonImage()

ipo = pylon.ImagePersistenceOptions()
quality = 100
ipo.SetQuality(quality)

# Get the transport layer factory.
tlFactory = pylon.TlFactory.GetInstance()

# Get all attached devices and exit application if no device is found.
devices = tlFactory.EnumerateDevices()
if len(devices) == 0:
    raise pylon.RuntimeException("No camera present.")

# Create an array of instant cameras for the found devices and avoid exceeding a maximum number of devices.
cameras = pylon.InstantCameraArray(min(len(devices), maxCamerasToUse))

l = cameras.GetSize()

# Create and attach all Pylon Devices.
for i, cam_z in enumerate(cameras):
    cam_z.Attach(tlFactory.CreateDevice(devices[i]))

    # Print the model name of the camera.
    print("Using device ", cam_z.GetDeviceInfo().GetModelName(), cam_z.GetDeviceInfo().GetSerialNumber())

for i in range(l):
    cameras[i].Open()
    cameras[i].PixelFormat = "RGB8"
    cameras[i].ExposureTime = 1000

    cameras[i].AcquisitionFrameRateEnable = True
    cameras[i].AcquisitionFrameRate = 2.5

class ImageHandler(pylon.ImageEventHandler):

    def __init__(self, cam: pylon.InstantCameraArray):
        # count img
        self.count_z = 0
        # Take a "snapshot" of the camera's current timestamp value
        cam.TimestampLatch.Execute()
        # Get the timestamp value
        self.t0= cam.TimestampLatchValue.GetValue()
        self.tn= cam.TimestampLatchValue.GetValue()
        super().__init__()
        self.img_sum = np.zeros((cam.Height.Value, cam.Width.Value), dtype=np.uint16)

    def OnImageGrabbed(self, camera, grabResult):
        """ we get called on every image
            !! this code is run in a pylon thread context
            always wrap your code in the try .. except to capture
            errors inside the grabbing as this can't be properly reported from 
            the background thread to the foreground python code
        """
        try:
            if grabResult.GrabSucceeded():
                # check image contents
                img = grabResult.Array
                #self.img_sum += img
                self.count_z = self.count_z + 1
                # Take a "snapshot" of the camera's current timestamp value
                camera.TimestampLatch.Execute()
                # Get the timestamp value
                self.tn= camera.TimestampLatchValue.GetValue()
                print("success ", self.count_z, "time ", self.tn - self.t0)
                self.t0 = self.tn
            else:
                raise RuntimeError("Grab Failed")
        except Exception as e:
            traceback.print_exc()

# instantiate callback handler
handler0 = ImageHandler(cameras[0])
handler1 = ImageHandler(cameras[1])
handler2 = ImageHandler(cameras[2])
# register with the pylon loop
cameras[0].RegisterImageEventHandler( handler0 , pylon.RegistrationMode_ReplaceAll, pylon.Cleanup_None)
cameras[1].RegisterImageEventHandler( handler1 , pylon.RegistrationMode_ReplaceAll, pylon.Cleanup_None)
cameras[2].RegisterImageEventHandler( handler2 , pylon.RegistrationMode_ReplaceAll, pylon.Cleanup_None)

# fetch some images with background loop
cameras[0].StartGrabbingMax( 10, pylon.GrabStrategy_LatestImages, pylon.GrabLoop_ProvidedByInstantCamera)
cameras[1].StartGrabbingMax( 10, pylon.GrabStrategy_LatestImages, pylon.GrabLoop_ProvidedByInstantCamera)
cameras[2].StartGrabbingMax( 10, pylon.GrabStrategy_LatestImages, pylon.GrabLoop_ProvidedByInstantCamera)
# cameras[0].StartGrabbing(pylon.GrabStrategy_LatestImages, pylon.GrabLoop_ProvidedByInstantCamera)
# cameras[1].StartGrabbing(pylon.GrabStrategy_LatestImages, pylon.GrabLoop_ProvidedByInstantCamera)
# cameras[2].StartGrabbing(pylon.GrabStrategy_LatestImages, pylon.GrabLoop_ProvidedByInstantCamera)

while cameras[0].IsGrabbing() or cameras[1].IsGrabbing() or cameras[2].IsGrabbing():
    continue    
    # random exposuretime changes every 100ms
    # cam.ExposureTime = random.uniform(cam.ExposureTime.Min, 1000)
    # time.sleep(0.001)

cameras[0].StopGrabbing()
cameras[0].DeregisterImageEventHandler(handler0)
cameras[1].StopGrabbing()
cameras[1].DeregisterImageEventHandler(handler1)
cameras[2].StopGrabbing()
cameras[2].DeregisterImageEventHandler(handler2)

return handler0.img_sum

backgroundaverage = .average / 100

if name == 'main': BackGroundLoopSample()

thiesmoeller commented 11 months ago

Some comments:

Limit the amount of work in the OnImageGrabbed handler as much as possible

You share the bandwidth of all three cameras over one USB host controller. You'll see stronger jitter in when you receive the frame, compared to like having three direct ports to the host.

Have you tested your exact setup in pylonviewer or in the bandwidthmanager( -> from tools menu ) that all three camera work in the pylonviewer?