How to change resolution dynamically in python with Aravis

Hi there,
I’m currently working on a project with a Sony XCG-CG510 GigE camera, and I’m trying to change the camera resolution dynamically. However, if I do not completely release the stream, camera object, and buffer(like the code below), I would encounter a write error. I also feel that the method I’m using might not be ideal.

write_register error (access-denied)

Could you please provide some advice on how to handle this more effectively?
Thank you very much for your help.
Best regards,

Below is the code I use to capture the image from a camera twice(640x480 and then 2000x2000)

import sys
import gi
import numpy as np
import cv2
import time

gi.require_version('Aravis', '0.8')
from gi.repository import Aravis

Aravis.enable_interface("Fake")

# Initialize the camera and set pixel format
def initialize_camera(ip_address=None, pixel_format="Mono12Packed"):
    camera = Aravis.Camera.new(ip_address) if ip_address else Aravis.Camera.new(None)

    # Set pixel format
    try:
        if pixel_format == "Mono8":
            camera.set_pixel_format(Aravis.PIXEL_FORMAT_MONO_8)
        elif pixel_format == "Mono12Packed":
            camera.set_pixel_format(Aravis.PIXEL_FORMAT_MONO_12_PACKED)
        else:
            print(f"Unsupported pixel format: {pixel_format}")
            exit()
    except gi.repository.GLib.GError as e:
        print(f"Failed to set pixel format: {e}")
    return camera

# Set appropriate resolution
def set_camera_region(camera, width, height):
    try:
        camera.set_region(0, 0, width, height)
        print(f"Region set to: {width}x{height}")
    except gi.repository.GLib.GError as e:
        print(f"Failed to set region: {e}")
        width, height = 640, 480  # Use default conservative value
        try:
            camera.set_region(0, 0, width, height)
            print(f"Fallback: Region set to default: {width}x{height}")
        except gi.repository.GLib.GError as e:
            print(f"Failed to set default region: {e}")
            raise e
    return width, height

# Process Mono12Packed image and convert to 8-bit representation
def process_mono12_packed_image(data, width, height):
    packed_width = (width * 12) // 8
    try:
        img_12bit = np.frombuffer(data, dtype=np.uint8).reshape(height, packed_width)
    except ValueError as e:
        print(f"Error reshaping the buffer: {e}")
        exit()

    gray16 = np.zeros((height, width), dtype=np.uint16)
    gray16[:, 0::2] = (img_12bit[:, 0::3].astype(np.uint16) << 4) | (img_12bit[:, 1::3] & 0x0F).astype(np.uint16)
    gray16[:, 1::2] = (img_12bit[:, 2::3].astype(np.uint16) << 4) | ((img_12bit[:, 1::3] >> 4) & 0x0F).astype(np.uint16)

    gray16 = np.clip(gray16, 0, 4095)
    gray8 = (gray16 >> 4).astype(np.uint8)

    return gray8

# Process Mono8 image
def process_mono8_image(data, width, height):
    return np.frombuffer(data, dtype=np.uint8).reshape(height, width)

# Clear stream buffers
def clear_stream_buffers(stream):
    print("Clearing stream buffers...")
    while True:
        buffer = stream.try_pop_buffer()
        if buffer is None:
            break
        print("Buffer cleared.")
    print("All buffers cleared.")

# Main program
pixel_format = sys.argv[2] if len(sys.argv) > 2 else "Mono12Packed"
ip_address = sys.argv[1] if len(sys.argv) > 1 else None
camera = initialize_camera(ip_address, pixel_format)

# Initial resolution
width, height = set_camera_region(camera, 640, 480)

# Initialize stream object and buffer
stream = camera.create_stream(None, None)
payload = camera.get_payload()
for _ in range(10):
    stream.push_buffer(Aravis.Buffer.new_allocate(payload))

print("Start acquisition")
camera.start_acquisition()

while True:
    image = stream.pop_buffer()
    if image:
        data = image.get_data()
        if data:
            # Process image
            if pixel_format == "Mono12Packed":
                gray8 = process_mono12_packed_image(data, width, height)
            elif pixel_format == "Mono8":
                gray8 = process_mono8_image(data, width, height)

            # Display image
            cv2.imshow("8-bit", gray8)
            stream.push_buffer(image)

            # Wait for key input
            key = cv2.waitKey(1) & 0xFF
            if key == ord('q'):
                break
        else:
            print("Warning: No data in buffer.")

# Stop acquisition and release camera object
print("Stop acquisition")
try:
    camera.stop_acquisition()
    time.sleep(2)  # Extend delay to ensure acquisition stops completely
except gi.repository.GLib.GError as e:
    print(f"Error stopping acquisition: {e}")

# Clear stream buffers
clear_stream_buffers(stream)

# Delete stream object
del stream
time.sleep(2)  # Allow camera to fully release stream resources

cv2.destroyAllWindows()
camera = None  # Release camera object

time.sleep(5)  # Add extra delay to ensure all resources are released

# Second start
camera = initialize_camera(ip_address, pixel_format)

# Initial resolution
width, height = set_camera_region(camera, 2000, 2000)

# Initialize stream object and buffer
stream = camera.create_stream(None, None)
payload = camera.get_payload()
for _ in range(10):
    stream.push_buffer(Aravis.Buffer.new_allocate(payload))

print("Start acquisition")
camera.start_acquisition()

while True:
    image = stream.pop_buffer()
    if image:
        data = image.get_data()
        if data:
            # Process image
            if pixel_format == "Mono12Packed":
                gray8 = process_mono12_packed_image(data, width, height)
            elif pixel_format == "Mono8":
                gray8 = process_mono8_image(data, width, height)

            # Display image
            cv2.imshow("8-bit", gray8)
            stream.push_buffer(image)

            # Wait for key input
            key = cv2.waitKey(1) & 0xFF
            if key == ord('q'):
                break
        else:
            print("Warning: No data in buffer.")

# Stop acquisition and release camera object
print("Stop acquisition")
try:
    camera.stop_acquisition()
except gi.repository.GLib.GError as e:
    print(f"Error stopping acquisition: {e}")

# Clear stream buffers
clear_stream_buffers(stream)

# Delete stream object
del stream
cv2.destroyAllWindows()
camera = None  # Release camera object

As far as I understand, the protocol does not allow for this. Reception buffers are allocated to match the resolution requested, so you need to stop streaming (that would be the requirement on the camera side) and re-allocate buffers (requirement on the receiver side), set new value for resolution, re-allocate reception buffers and start streaming again.

1 Like

Hi,

It is possible to allocate buffers larger than the current resolution. See tests/arvroitest.c.

Emmanuel.

1 Like

Hi Emmanuel,
Thank your for sharing the idea.
I will try this method on my side.
Althrough it might just be easier for me stop the stream and
the just re-alloacate a buffer for the coming image from the camera. :joy:

Best Regards,