Numpy: assignment destination is read-only - broadcast
Asked Answered
T

1

9

I start with a 2D array and want to broadcast it to a 3D array (eg. from greyscale image to rgb image). This is the code I use.

>>> img_grey = np.random.randn(4, 4)
>>> img_rgb = np.broadcast_to(np.expand_dims(img_grey, axis=-1), (4, 4, 3))

This creates an array img_rgb that works as expected: 3 colored channels (last dimension), each slice being equal to the original greyscale image. However, if I do

>>> img_rgb[0, 0, 0] = 0.
ValueError: assignment destination is read-only

I can't change the rgb image!

Tiga answered 5/4, 2018 at 13:38 Comment(0)
T
8

The reason is that broadcast_to does not create a new array in memory. Instead, you just get a view of the original data. This can be seen by inspecting the flags.

>>> img_rg.flags
C_CONTIGUOUS : False
F_CONTIGUOUS : False
OWNDATA : False
WRITEABLE : False
ALIGNED : True
UPDATEIFCOPY : False

In particular, the OWNDATA flag is set to False (which means the array borrows the memory from another object), as well as the WRITEABLE flag being False (this is why you can't change the object). See the numpy flags documentation.

The workaround is to create a copy of the array.

>>> img_rgb = np.broadcast_to(np.expand_dims(img_grey, axis=-1), (4, 4, 3)).copy()
>>> img_rgb[0, 0, 0] = 0.  # works!

This gives the rgb image its own memory space, which can be changed without altering the greyscale image. The OWNDATA and WRITEABLE flags are thus also set to True.

Tiga answered 5/4, 2018 at 13:38 Comment(2)
The OWNDATA and WRITEABLE flags still remain FALSE, but i can now edit the array. Is there any other way to check if copy worked?Consanguineous
I'm not aware when these flags would remain False after copy; it seems a bit weird. The easiest way to test if the copy actually worked is to try modifying the elements: if this does not affect the original array, then it is properly copied.Tiga

© 2022 - 2024 — McMap. All rights reserved.