arrays obtained from Image.open with np.asarray being immutable - "assignment destination is read-only"
Asked Answered
E

7

63

My goal is to read a set of PNG files, create Image(s) with Image.open('filename') and convert them to simple 2D arrays with only 1s and 0s. The PNG is of the format RGBA with mostly only 255 and 0 as values. Quite often in the images, the edges are grey scale values, which I would like to avoid in the 2D array.

I created the 2D array from image using np.asarray(Image) getting only the 'Red' channel. In each of the 2d image array, I would like to set the cell value = 1 if the current value is non zero.

So, I loop into the 2d array and I check the cell value and try to set it to 1.

It gives me an error indicating that the array is read-only. I read through several stack overflow threads discussing that np arrays are immutable and it is a still bit unclear. I use PIL and numpy.

from PIL import Image
import numpy as np

The relevant code:

prArray = [np.asarray(img)[:, :, 0] for img in problem_images]

for img in prArray:
    for x in range(184):
        for y in range(184):
            if img[x][y] != 0:
                img[x][y] = 1

The error "assignment destination is read-only" is in the last line.

Ensphere answered 18/9, 2016 at 6:5 Comment(5)
there are numerous web links #13572948 suggests at least twoIncessant
Where did img come from, and why do you need asarray?Grogram
This whole piece of code can be better written prArray = prArray != 0Grogram
Using np.array() instead of np.asarray() likely solves thisLaughton
If you want to make your array writable, You must make a copy (copy_arr = prArray.copy()) of your array, and then you can change or write the elements of your "copy array"Fasta
S
74

Check if the array is writable with

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

If WRITEABLEis false, change it with

img.setflags(write=1)
Sanchez answered 18/9, 2016 at 6:26 Comment(4)
There might be a good reason that the array is readonly - it'd be worth trying to work out why the producer of img decided the result is readonly before changing the flags. If the reason is a sound one, consider using img = img.copy() insteadGrogram
ValueError: cannot set WRITEABLE flag to True of this array. Drat!Needleful
@MonicaHeddneck see 2nd answer by "AleksMat"Strunk
More cmd line options for img.setflags(params) from np 1.18 documentation: 1: writebool, optional; describes whether or not a can be written to. 2: alignbool, optional; describes whether or not a is aligned properly for its type. 3. uicbool, optional. Describes whether or not a is a copy of another “base” array.Strunk
T
65

Since numpy version 1.16.0 the following doesn't work anymore:

img = np.asarray(Image.open(filename))
img.setflags(write=1)

The problem is that now OWNDATA is set to False and you can't set WRITEABLE flag to True. Therefore you should simply do the following:

img = np.array(Image.open(filename))

This will make a copy of array when casting it from Pillow object to numpy array. However I tested time performance in numpy 1.16.0 and haven't found any noticable difference between both methods.

Teresiateresina answered 22/1, 2019 at 12:53 Comment(3)
This will definitely make a copy of the array so there isn't any doubt in your statement. I've edited the language accordingly to make this an assertion rather than a doubting thought.Navigation
Kind of "antipythonic," right? Empower people; don't protect them from potential mistakes!Strunk
I got an error when trying to setflags(write=1). The way I solved it was with: img = np.asarray(Image.open(filename)).copyLightship
P
9

In this case, I think you are trying to edit the image provided to you by another user and he/she made it uneditable that's why you are getting this error. For your case, you may try to make a copy of the given file and do changes on that file by using .copy().

img_copy = img.copy()
prArray = [np.asarray(img_copy)[:, :, 0] for img_copy in problem_images]

And more importantly, I do not think that most of us want to make changes to our original image, that's why I always use .copy() and recommend you to do the same.

Predetermine answered 2/6, 2019 at 21:32 Comment(0)
C
5
ValueError: cannot set WRITEABLE flag to True of this array array.setflags(write=1) 

Skip the statement using copy the array using np.copy()

Chine answered 29/11, 2020 at 12:31 Comment(0)
S
1

I recommend that you stop doing math on the original image. You can solve this problem by using img.copy()

img = plt.imread('../img/1.2.jpg')
img=img.copy()
Superimposed answered 21/2, 2023 at 9:23 Comment(1)
While this code snippet may be the solution, including a detailed explanation really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion.Salomon
G
1

I think you don't need to downgrade your numpy version. You have just to make a copy of the original image like this :

img_copy = np.copy(img)

and it works !

Gage answered 6/8, 2023 at 13:14 Comment(2)
Is there any reason you are suggesting the use of np.copy(img) instead of img.copy()?Compilation
Oh, I saw some people suggesting to downgrade numpy that is why I put this script to emphasize the fact that we don't need to downgrade it. Then, since many people are more familiar with numpy, in this particular case, I think they don't need to import another library ThanksGage
S
0

Try this one:

img = np.array(image, copy=True)
Selfrising answered 28/6, 2024 at 4:37 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.