Skip to content

Unable to connect multiple CXP cameras using two different python processes #828

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
rbray1011 opened this issue Mar 14, 2025 · 1 comment

Comments

@rbray1011
Copy link

Describe what you want to implement and what the issue & the steps to reproduce it are:

We are trying to grab frames from two Basler boost R cameras connected to a CXP-12 4C card from two separate python processes and are running into issues. We are able to initialize one camera and start grabbing in one process, but the other process is unable to see any of the devices. We have had no issues with this same method using one CXP camera and one USB camera, or even two USB cameras. We have also tried using two interface cards with one camera connected to each, but this is also problematic. It seems like once one process is using the CXP transport layer, no other processes are allowed to access it. A single python process initializing both cameras works, but it would be ideal for our software architecture to maintain separate processes. I provided the error and code snippets for both methods below. We reached out to Basler support on this, but they recommended we post our issue here. Thanks for any help you can provide!

Error

[2025-03-13 11:08:07,010:14700:basler.fglib.AppletHelper.FileTypeHelper] ERROR: [gtlIF=IF0][handle=(struct VAdevice * __ptr64)0000015185BC0920][board-index=0][board-serial=b6400433][board-type=b64][applet=Acq_DualCXP12Area.hap][error=-28] Failed to initialize frame grabber: Failed to unpack Acq_DualCXP12Area.hap
[2025-03-13 11:08:07,011:14700:siso.wrapper.Acq_DualCXP12Area] ERROR: thread-id=14700|error calling 'Fg_InitHandleSlaveAware' (hapName = 'Acq_DualCXP12Area.hap')
[2025-03-13 11:08:07,017:14700:basler.fglib.AppletHelper.FileTypeHelper] ERROR: [gtlIF=IF0][board-index=0][applet=C:\Program Files\Basler\FramegrabberSDK\dll\CXP12-IC-4C\S1.0\Acq_DualCXP12Area.dll][flags=0][error=-28] Failed to initialize frame grabber: Failed to initialize C:\Program Files\Basler\FramegrabberSDK\dll\CXP12-IC-4C\S1.0\Acq_DualCXP12Area.dll
[2025-03-13 11:08:07,019:14700:basler.GenTL.ConsumerInterface] ERROR: [gtl=CXP] Resources are already in use
[2025-03-13 11:08:07,019:14700:Pylon.GenTL.TL] ERROR: [cti=1123c82654f6] <-- TLOpenInterface returns [status=-1001][hTL=1449649629472][phIface=0]
[2025-03-13 11:08:07,186:14700:basler.fglib.AppletHelper.FileTypeHelper] ERROR: [gtlIF=IF1][handle=(struct VAdevice * __ptr64)0000015185BC0080][board-index=1][board-serial=b65005c2][board-type=b65][applet=Acq_SingleCXP12Area.hap][error=-28] Failed to initialize frame grabber: Failed to unpack Acq_SingleCXP12Area.hap
[2025-03-13 11:08:07,187:14700:siso.wrapper.Acq_SingleCXP12Area] ERROR: thread-id=14700|error calling 'Fg_InitHandleSlaveAware' (hapName = 'Acq_SingleCXP12Area.hap')
[2025-03-13 11:08:07,189:14700:basler.fglib.AppletHelper.FileTypeHelper] ERROR: [gtlIF=IF1][board-index=1][applet=C:\Program Files\Basler\FramegrabberSDK\dll\CXP12-IC-2C\S1.0\Acq_SingleCXP12Area.dll][flags=0][error=-28] Failed to initialize frame grabber: Failed to initialize C:\Program Files\Basler\FramegrabberSDK\dll\CXP12-IC-2C\S1.0\Acq_SingleCXP12Area.dll
[2025-03-13 11:08:07,191:14700:basler.GenTL.ConsumerInterface] ERROR: [gtl=CXP] Resources are already in use
[2025-03-13 11:08:07,191:14700:Pylon.GenTL.TL] ERROR: [cti=1123c82654f6] <-- TLOpenInterface returns [status=-1001][hTL=1449649629472][phIface=0]

Multiprocessing

from pypylon import pylon
import numpy as np
import cv2
from multiprocessing import Process
import time
import sys

def test(device_idx):
    print("proc id", device_idx)
    camera = init_camera(device_idx)
    run_camera(camera)

def init_camera(device_idx):
    tlf: pylon.TlFactory = pylon.TlFactory.GetInstance()
    for tl in tlf.EnumerateTls():
        tl_type = tl.GetTLType()
        print("available tl", tl_type)
    device_infos = tlf.EnumerateDevices()
    for device_info in device_infos:
        print(f"device w/ sn {device_info.GetSerialNumber()} found")
    device = tlf.CreateDevice(device_infos[device_idx])
    camera = pylon.InstantCamera(device)
    return camera

def run_camera(camera: pylon.InstantCamera):
    sn = camera.DeviceInfo.GetSerialNumber()
    print(f"starting grabbing on camera with sn {sn}")
    camera.Open()
    camera.StartGrabbing()
    while True:
        with camera.RetrieveResult(5000, pylon.TimeoutHandling_ThrowException) as result:
            if not result.GrabSucceeded():
                print(f"grab unsuccessful! {result.GetErrorCode() : x}, {result.GetErrorDescription()}")
            image = result.GetArray()
            resized_image = cv2.resize(image.astype(np.uint8), (640,480))
            cv2.imshow(f"cam {sn}", resized_image)
            
            if cv2.waitKey(1) == ord("q"):
                break

if __name__ == "__main__":
    p1 = Process(target=test, args=(0,))
    p1.start()
    time.sleep(5)
    p2 = Process(target=test, args=(1,))
    p2.start()
    sys.stdout.flush()

Single Process

from pypylon import pylon
import cv2
import numpy as np

tl_factory = pylon.TlFactory.GetInstance()
devices = tl_factory.EnumerateDevices()

if len(devices) < 2:
    print("Two cameras are required, but only found:", len(devices))
    exit()

camera1 = pylon.InstantCamera(tl_factory.CreateDevice(devices[0]))
camera2 = pylon.InstantCamera(tl_factory.CreateDevice(devices[1]))
camera1.Open()
camera2.Open()
print(f"Connected to camera 1: {camera1.GetDeviceInfo().GetModelName()}")
print(f"Connected to camera 2: {camera2.GetDeviceInfo().GetModelName()}")

camera1.ExposureTime.SetValue(5000)  
camera2.ExposureTime.SetValue(5000)  

camera1.StartGrabbing(pylon.GrabStrategy_LatestImageOnly)
camera2.StartGrabbing(pylon.GrabStrategy_LatestImageOnly)
cv2.namedWindow("Live Feed", cv2.WINDOW_NORMAL)
while camera1.IsGrabbing() and camera2.IsGrabbing():
    grab1 = camera1.RetrieveResult(5000, pylon.TimeoutHandling_ThrowException)
    grab2 = camera2.RetrieveResult(5000, pylon.TimeoutHandling_ThrowException)

    if grab1.GrabSucceeded() and grab2.GrabSucceeded():
        img1 = grab1.Array
        img2 = grab2.Array

        if img1.shape[0] != img2.shape[0]:
            min_height = min(img1.shape[0], img2.shape[0])
            img1 = img1[:min_height, :]
            img2 = img2[:min_height, :]

        if len(img1.shape) == 2:
            img1 = cv2.cvtColor(img1, cv2.COLOR_GRAY2BGR)
            img2 = cv2.cvtColor(img2, cv2.COLOR_GRAY2BGR)

        combined_img = np.hstack((img1, img2))

        cv2.imshow("Live Feed", combined_img)

    grab1.Release()
    grab2.Release()

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

camera1.StopGrabbing()
camera2.StopGrabbing()
camera1.Close()
camera2.Close()
cv2.destroyAllWindows()

Is your camera operational in Basler pylon viewer on your platform

Yes

Hardware setup used

  • OS: Windows 10
  • Interface: CXP-12 Interface Card 4C

Camera(s) used

Basler boA13440-17cm (40398956)
p=xc3_imx661m/s=c/v=1.0.1/i=9513.6/h=2f9cb5e
Basler boA13440-17cm (40398962)
p=xc3_imx661m/s=c/v=1.0.1/i=9513.6/h=2f9cb5e

Runtime information:

python: 3.13.2 (tags/v3.13.2:4f8bb39, Feb  4 2025, 15:23:48) [MSC v.1942 64 bit (AMD64)]
platform: win32/AMD64/10
pypylon: 4.1.0 / 9.0.3.215
@cpt-wojtech
Copy link

The GenTL implementation in pylon does not allow to access CXP devices from multiple processes. You can see this if you try to open a CXP camera with two pylon Viewer instances opened. This could be due to technical restrictions in the core C++ runtime of pylon.

Multithreading on a single instance with multiple cameras however works fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants