Get HDR output from buffer

Hi, I would like to get HDR pixel values output of the viewport buffer. In the viewport_thumbneil_generator example, a low dynamic range image is processed as RGBA.

try:
            ctypes.pythonapi.PyCapsule_GetPointer.restype = ctypes.POINTER(ctypes.c_byte * buffer_size)
            ctypes.pythonapi.PyCapsule_GetPointer.argtypes = [ctypes.py_object, ctypes.c_char_p]
            content = ctypes.pythonapi.PyCapsule_GetPointer(buffer, None)
        except Exception as e:  # pylint: disable=broad-except
            carb.log_error(f"[Thumbnail] Failed to get capture buffer: {e}")
            return

        # Crop and down sample
        data = self._generate_thumbnail_data(content.contents, (width, height))

I can use this to get the pixel values from the buffer.
image_array = np.frombuffer(raw_data, dtype=np.uint8)

If I use capture_viewport_to_buffer(camera_viewport, on_viewport_captured, True) to get the HDR to the buffer, how do I get the pixel values, how many bits for each pixel?

The RTX Renderer works natively in High Dynamic Range full 32bit float. It will only write 8bit when asked to. The buffer will be in 32bit. If you ask it to write out to EXRs, it will stay in 32bit.

Thank you Richard, would it be possible to give an example on how to read HDR to the buffer? I used viewport utility function and use Ture for is_hdr flag:
capture_viewport_to_buffer(camera_viewport, on_viewport_captured, True)
But it seems the callback is never reached.

Try this…

import omni.kit.app
from omni.kit.viewport.utility import get_active_viewport, capture_viewport_to_buffer
import asyncio
import carb

async def capture_viewport_buffer(viewport_api, in_capture_callback, is_hdr: bool = False, wait_frames: int = 3):
is_hdr = bool(is_hdr)
capture_callback = in_capture_callback
hdr_setting_path = “/app/captureFrame/hdr”

settings = carb.settings.get_settings()
prev_is_hdr = bool(settings.get(hdr_setting_path))
if prev_is_hdr != is_hdr:
    settings.set(hdr_setting_path, is_hdr)

    app = omni.kit.app.get_app()
    for _ in range(max(1, wait_frames)):
        await app.next_update_async()

    # Wrap capture-callback in a local version that puts  
    def capture_wrapper(*args, **kwargs):
        settings.set(hdr_setting_path, prev_is_hdr)
        in_capture_callback(*args, **kwargs)

    capture_callback = capture_wrapper

capture_viewport_to_buffer(viewport_api, capture_callback, is_hdr=is_hdr)

def capture_callback(capsule_bytes, num_bytes, width, height, byte_format, *args, **kwargs):
expected_num_bytes = 0
if byte_format == byte_format.RGBA16_SFLOAT:
expected_num_bytes = width * height * 4 * 2
elif byte_format == byte_format.RGBA8_UNORM:
expected_num_bytes = width * height * 4 * 1

print("width", width)
print("height", height)
print("byte_format", byte_format)
print("num_bytes", num_bytes)
print("expected_num_bytes", expected_num_bytes)
assert num_bytes == expected_num_bytes

asyncio.ensure_future(capture_viewport_buffer(get_active_viewport(), capture_callback, is_hdr = True))

Hi Richard, Thank you very much for the example. It works great! I tried to get the number of bytes and use it in the main but some how it keeps freezing Omniverse. Any suggestions?

import omni.kit.app
from omni.kit.viewport.utility import get_active_viewport, capture_viewport_to_buffer
import asyncio
import carb

# Global variable to store the number of bytes
captured_num_bytes = 0
# Event to signal when capture is complete
capture_complete_event = asyncio.Event()

async def capture_viewport_buffer(viewport_api, in_capture_callback, is_hdr: bool = False, wait_frames: int = 3):
    is_hdr = bool(is_hdr)
    capture_callback = in_capture_callback
    hdr_setting_path = "/app/captureFrame/hdr"

    settings = carb.settings.get_settings()
    prev_is_hdr = bool(settings.get(hdr_setting_path))
    
    if prev_is_hdr != is_hdr:
        settings.set(hdr_setting_path, is_hdr)

        app = omni.kit.app.get_app()
        for _ in range(max(1, wait_frames)):
            await app.next_update_async()

        # Wrap capture-callback in a local version that puts  
        def capture_wrapper(*args, **kwargs):
            settings.set(hdr_setting_path, prev_is_hdr)
            in_capture_callback(*args, **kwargs)

        capture_callback = capture_wrapper

    capture_viewport_to_buffer(viewport_api, capture_callback, is_hdr=is_hdr)

def capture_callback(capsule_bytes, num_bytes, width, height, byte_format, *args, **kwargs):
    global captured_num_bytes
    expected_num_bytes = 0
    if byte_format == byte_format.RGBA16_SFLOAT:
        expected_num_bytes = width * height * 4 * 2
    elif byte_format == byte_format.RGBA8_UNORM:
        expected_num_bytes = width * height * 4 * 1

    print("width", width)
    print("height", height)
    print("byte_format", byte_format)
    print("num_bytes", num_bytes)
    print("expected_num_bytes", expected_num_bytes)
    assert num_bytes == expected_num_bytes
    
    # Store the number of bytes in the global variable
    captured_num_bytes = num_bytes
    # Set the event to signal that capture is complete
    capture_complete_event.set()

async def capture():
    # Start the capture process
    await capture_viewport_buffer(get_active_viewport(), capture_callback, is_hdr=True)
    # Wait for the capture to complete
    await capture_complete_event.wait()

# Run the main function and wait for it to complete
asyncio.run(capture())

# Print the captured number of bytes after the main function completes
print("Captured number of bytes:", captured_num_bytes)

The asyncio.run(capture()) should be changed to asyncio.ensure_future(capture())

asyncio.ensure_future does NOT seem to wait for the capture to finish. Is there a way to wait for the capture() to finish so I could use the updated global variable? Many thanks.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.