Skip to content
⚡ Developer documentation for INFINICAM, the real-time high-speed camera (UC-1.1 / GbE-2)

SingleImage (PGM Save) Project (GbE-2 / Python)

Steps for creating a script that uses the common module puclib.py created in HelloWorld to capture and decode one frame of compressed image data from the GbE-2, and save it as a PGM (Portable Graymap) file.

  1. Create the script

    In the same folder as puclib.py, create gbe2_single_image_pgm.py and write the following code.

    gbe2_single_image_pgm.py
    from ctypes import c_uint32, c_ushort, c_ubyte, c_void_p, byref
    import numpy as np
    # Import from the common module puclib.py
    from puclib import (
    load_sdk, PUC_SUCCEEDED, PUC_DETECT_TARGET_GBE2,
    PUC_Q_COUNT, PUC_DETECT_FILTER, PUC_DETECT_INFO, PUC_XFER_DATA_INFO
    )
    def main():
    print("Starting INFINICAM GbE-2 SingleImage (PGM) capture...")
    # 1. Load and initialize the SDK
    puclib = load_sdk()
    if puclib.PUC_Initialize() != PUC_SUCCEEDED:
    print("Error: Failed to initialize the SDK.")
    return
    # 2. Search for and open the device
    detect_filter = PUC_DETECT_FILTER(nDeviceTypeFlags=PUC_DETECT_TARGET_GBE2)
    detect_info = PUC_DETECT_INFO()
    if puclib.PUC_DetectDevice2(byref(detect_filter), byref(detect_info)) != PUC_SUCCEEDED or detect_info.nDeviceCount == 0:
    print("Error: No GbE-2 camera was found.")
    return
    h_device = c_void_p()
    if puclib.PUC_OpenDevice2(0, byref(h_device)) != PUC_SUCCEEDED:
    print("Error: Failed to open the device.")
    return
    # 3. Retrieve camera parameters
    width, height = c_uint32(), c_uint32()
    puclib.PUC_GetResolution(h_device, byref(width), byref(height))
    w, h = width.value, height.value
    q_vals = (c_ushort * PUC_Q_COUNT)()
    puclib.PUC_GetQuantization2(h_device, q_vals)
    xfer_data_size = c_uint32()
    puclib.PUC_GetXferDataSize(h_device, byref(xfer_data_size))
    print(f"Resolution: {w} x {h} pixels")
    # 4. Allocate buffers
    comp_buffer = (c_ubyte * xfer_data_size.value)()
    line_bytes = (w + 3) & ~3 # 4-byte boundary alignment
    decoded_buffer = (c_ubyte * (line_bytes * h))()
    # 5. Perform the capture
    xfer_info = PUC_XFER_DATA_INFO()
    xfer_info.pData = comp_buffer
    xfer_info.nDataSize = xfer_data_size.value
    print("Capturing one frame...")
    if puclib.PUC_GetSingleXferData(h_device, byref(xfer_info)) == PUC_SUCCEEDED:
    # 6. Decode processing
    ret = puclib.PUC_DecodeData(
    decoded_buffer, 0, 0, w, h, line_bytes, comp_buffer, q_vals
    )
    if ret == PUC_SUCCEEDED:
    # 7. Convert the ctypes buffer into a NumPy array (remove padding)
    img_np = np.ctypeslib.as_array(decoded_buffer).reshape((h, line_bytes))[:, :w]
    # 8. Save the file in PGM (P5) format
    filename = "captured_image.pgm"
    with open(filename, "wb") as f:
    header = f"P5\n{w} {h}\n255\n".encode("ascii")
    f.write(header)
    f.write(img_np.tobytes())
    print(f"SUCCESS: Saved the PGM image file ({filename})")
    else:
    print(f"Error: Failed to decode the image data. ErrorCode: {ret}")
    else:
    print("Error: Failed to retrieve the image data.")
    # 9. Close
    puclib.PUC_CloseDevice(h_device)
    if __name__ == "__main__":
    main()
  2. Run the script

    Terminal window
    python gbe2_single_image_pgm.py

    After execution finishes, captured_image.pgm will be generated in the current directory.


1. Significant code reduction through the common module

Section titled “1. Significant code reduction through the common module”

By calling puclib.py, there is no longer any need to write the DLL type definitions or C struct declarations directly in the script.

from puclib import (
load_sdk, PUC_SUCCEEDED, PUC_DETECT_TARGET_GBE2,
PUC_Q_COUNT, PUC_DETECT_FILTER, PUC_DETECT_INFO, PUC_XFER_DATA_INFO
)

2. Converting a ctypes buffer into a NumPy array

Section titled “2. Converting a ctypes buffer into a NumPy array”

Using np.ctypeslib.as_array(), the decode buffer (decoded_buffer) can be turned directly into a NumPy array with no memory copy.

img_np = np.ctypeslib.as_array(decoded_buffer).reshape((h, line_bytes))[:, :w]
  • reshape((h, line_bytes)): Rearranges the data into a 2D shape that accounts for the 4-byte boundary alignment (line_bytes).
  • [:, :w]: Cuts off the extra padding bytes automatically appended to the end of each row for boundary alignment, extracting the actual image size (w x h).