Author Topic: read buffer from memory  (Read 36976 times)

hi,
i m trying to get to work numpy with the sds api; in particular i m interested in getting the values from a certain
node in numpy format:
so far i ve got some results, but is seems that they are not correct. any clue how to use it?!

    sdTex = outProperty.get()
    buffaddr = sdTex.getPixelBufferAddress()
    print(buffaddr)
    print(os.getpid())
    val = read_process_memory(os.getpid(), buffaddr, 1024)
    print(np.frombuffer(val,dtype=np.uint16))




Hey, were you successful with that in the meantime? I just started using the API and was looking for something similar.
The below code should work for 1 selected node. I left out all the safety checks for brevity.

I haven't tested the numpy part inside designer though, because I didn't install numpy into its python distribution, but I did check the conversions from the bytes to array in another python environment.

Basically I only used the ctypes.string_at function to read the buffer and converted using either uint8 or uint16, since the returned values can have different bits per channel (8/16).

Code: [Select]
from ctypes import string_at

import sd
from sd.api.sdproperty import SDPropertyCategory
from sd.api.sdvaluetexture import SDValueTexture

import numpy as np


def get_ui_manager():
    ctx = sd.getContext()
    app = ctx.getSDApplication()
    ui_manager = app.getUIMgr()
    return ui_manager


def get_sd_tex(node):
    prop = node.getProperties(SDPropertyCategory.Output)[0]  # Take the first output.
    print(prop.getLabel())
    value = node.getPropertyValue(prop)
    sd_texture = SDValueTexture.get(value)
    return sd_texture


def print_tex_info(sd_tex):
    dim_x, dim_y = sd_tex.getSize()
    print(f"Dimensions: {dim_x} x {dim_y}")
    print(f"Bytes per pixel: {sd_tex.getBytesPerPixel()}")
    address = sd_tex.getPixelBufferAddress()
    print(f"Buffer Address: {address}")
   
   
def get_tex_bytes(sd_tex):
    dim_x, dim_y = sd_tex.getSize()
    address = sd_tex.getPixelBufferAddress()
    tex_b = string_at(address, dim_x * dim_y * sd_tex.getBytesPerPixel())
    return tex_b


def get_dtype(bpp):
    if bpp in [1, 4]:
        return np.uint8
    else:
        return np.uint16
   

def get_shape(sd_tex):
    dim_x, dim_y = sd_tex.getSize()
    if sd_tex.getBytesPerPixel() == 1:
        return (dim_x, dim_y)
    else:
        return (dim_x, dim_y, 4)
   
   
def get_tex_array(sd_tex):
    tex_b = get_tex_bytes(sd_tex)
    dt = get_dtype(sd_tex.getBytesPerPixel())
    shape = get_shape(sd_tex)
    a = np.frombuffer(tex_b, dtype=dt).reshape(shape)  # row x column (x rgba)
    return a


if __name__ == '__main__':
    ui_mgr = get_ui_manager()
    node = ui_mgr.getCurrentGraphSelection()[0]  # Assume we have 1 node of interest selected.
    tex = get_sd_tex(node)
    print_tex_info(tex)
    img = get_tex_array(tex)

Last Edit: October 20, 2019, 05:16:55 am

Having had a look at your output again, I think your results are actually correct. You only provided the wrong size to read from the buffer. There's a 1024² grayscale texture with 16 bits per channel (2 bytes per pixel) and you read only 1024 bytes, giving you the first 512 pixels of the first row of the node. I think you should read size of 2097152.
Last Edit: October 20, 2019, 01:04:44 pm