Hi Stereolabs,
I am trying to do the opposite of sl.Mat.get_data(), namely creating an sl.Mat, object that contains the data from an existing numpy.ndarray.
Is this possible with the Python API?
Kind regards
Hi Stereolabs,
I am trying to do the opposite of sl.Mat.get_data(), namely creating an sl.Mat, object that contains the data from an existing numpy.ndarray.
Is this possible with the Python API?
Kind regards
Hello and thank you for reaching out to us !
If you don’t use the deep_copy option when creating your numpy array, the sl.Mat and the numpy array share the same pointer. Meaning the if you modify the numpy array, the sl.Mat will be modified too.
You can use that to do what you need here :
Regards
Thank you @alassagne for your quick response! This order of operations did the job for me.
Although, I do think a classmethod such as sl.Mat.from_numpy() would have come in handy in this case. Maybe it is an idea for some added functionality but I will use your workaround for now.
Indeed. Glad the workaround did the trick in the meantime, we’ll think about a feature.
Hi,alassagne.
If, as you said, I want to extract data from a certain area of Mat, how do I do it?
Hi, please create a new thread for your question (and put more explanations / context within it)
Hey, Is there really no way of exchanging the pointer the sl::Mat points to? I’d like to share the underlying memory buffer as numpy.ndarray via a python multiproccessing.Array. I cannot find a way to either tell the multiprocessing.Array to use the sl::Mat data or vise versa.
@gartangh at the end I didn’t understand how did you create an sl.Mat() from a numpy array ![]()
can you explain please or give an example if possible.
The answer from @alassagne with the sharing memory doesn’t seem to work or I am applying it wrongly.
ok, after playing around the following code snippet seems to do the trick. For future reference:
tmp = sl.Mat(your_numpy_array.width, your_numpy_array.height, sl.MAT_TYPE.F32_C1, sl.MEM.CPU) # choose correctly your channels, based on the dimensions of your numpy array
tmp_np = tmp.get_data()
tmp_np = your_numpy_array
tmp.get_data() # now you should be able to see the data in your sl.Mat() variable
Hello everyone,
I’m trying to do what is in the thread subject, that is, creating a sl.Mat object from an existing numpy array.
The workaround by @alassagne is to create a sl.Mat and then create a numpy array with get_data(). Modifying either the numpy array or the sl.Mat will reflect the change on the other variable since they point to the same memory. In fact the following minimal reproducible example works as expected.
import numpy as np
import pyzed.sl as sl
width, height = 4, 3
zed_frame = sl.Mat(width, height, sl.MAT_TYPE.U8_C3, sl.MEM.CPU)
np_frame = zed_frame.get_data()
zed_frame.set_to([64, 64, 64])
print(np_frame) # prints all 64
np_frame.fill(128)
print(zed_frame.get_data()) # prints all 128
print(zed_frame.get_pointer() == np_frame.ctypes.data) # prints True
However, I think this doesn’t address the original post, because it creates a numpy array from a sl.Mat object and not the other way around.
In my application, I am given a numpy array to fill with acquired camera frames and subsequent operations expect to work on the numpy array, so I need retrieve_image() to fill the pre-existing numpy array and copying data is not feasible because it takes too long.
So I tried the code snippet by @ttsesm but I cannot make it work.
import numpy as np
import pyzed.sl as sl
width, height = 4, 3
np_frame = np.zeros(shape=(height, width, 3), dtype=np.uint8)
zed_frame = sl.Mat(width, height, sl.MAT_TYPE.U8_C3, sl.MEM.CPU)
zed_frame_data = zed_frame.get_data()
zed_frame_data = np_frame
zed_frame.set_to([64, 64, 64])
print(np_frame) # prints all 0, expected all 64
np_frame.fill(128)
print(zed_frame.get_data()) # prints all 64, expected all 128
print(zed_frame.get_pointer() == np_frame.ctypes.data) # prints False, expected True
Changes to the numpy array or the sl.Mat don’t reflect on the other and in fact they point to a different memory address. Apparently, the pass-by-reference trick didn’t work in this case. Maybe I’m missing something or the underlying behaviour has changed since that solution was posted.
Searching the ZED SDK documentation I found the init_mat_cpu() method to initialise a new sl.Mat from an existing data pointer, which seems exactly what is needed here to do the job.
However, the following example does not work as expected.
import numpy as np
import pyzed.sl as sl
width, height = 4, 3
np_frame = np.zeros(shape=(height, width, 3), dtype=np.uint8)
zed_frame = sl.Mat(width, height, sl.MAT_TYPE.U8_C3, sl.MEM.CPU)
zed_frame.init_mat_cpu(width, height, sl.MAT_TYPE.U8_C3, str(np_frame.ctypes.data), np_frame.ctypes.strides[0])
zed_frame.set_to([64, 64, 64])
print(np_frame) # prints all 0, expected all 64
np_frame.fill(128)
print(zed_frame.get_data()) # prints all 64, expected all 128
print(zed_frame.get_pointer() == np_frame.ctypes.data) # prints False, expected True
I couldn’t find code examples using the init_mat_cpu() method, so I proceeded by trial and error.
For example, I tried to use the default constructor zed_frame = sl.Mat(), but then calling set_to() fails. In fact, is_init() returns False, so apparently init_mat_cpu() is not really initialising the sl.Mat object.
Maybe I’m not using init_mat_cpu() correctly. For example, it’s not clear how to pass the pointer to the data array. Initially I used np_frame.ctypes.data, but I got an AttributeError: ‘int’ object has no attribute ‘encode’, so I assumed it wanted a string, but I could be wrong.
Same for the step parameter, it makes sense to me to use np_frame.ctypes.strides[0] but maybe it is expecting something else.
Overall, is there a way to create a sl.Mat object from a pre-existing numpy array, either numpy’s pass-by-reference, init_mat_cpu() method or any other means?
Sorry for the lengthy post and thanks in advance for any help!
For completeness, here is my system configuration: