How can I change the RGB values for given indices in an image? This gives me a blank picture:
import numpy as np
from PIL import Image
target_image = Image.open("img.png")
target_image_array = np.array(target_image)
pixels = target_image_array.reshape(-1, 3)
skip_indices = np.arange(101_600, 254_000)
indices_to_grey_out = np.delete(pixels, skip_indices, 0)
pixels_greyed_out = pixels.copy()
pixels_greyed_out[indices_to_grey_out, [0, 1, 2]] = 0
pixels_greyed_out = pixels_greyed_out.reshape(target_image_array.shape)
modified_img = Image.fromarray(pixels_greyed_out)
modified_img.show()
I don't understand what you are trying to do with flattened and discontiguous indices at all, but going purely off your comments, I understand you want to affect some specific colours in an image so I'll try and demonstrate that.
Here is a radial gradient image that is rgb(20, 50, 140)
at the centre and rgb(40, 70, 160)
at the edge, so I happen to know there are 4,884 (non lineaarly adjacent, if that matters) pixels with value rgb(25,55,145)
Now, let's open it and make it into a Numpy array:
from PIL import Image
import numpy as np
# Open image and make into Numpy array
im = Image.open('a.png').convert('RGB')
na = np.array(im)
# Make Boolean (True/False) mask of interesting pixels
mask = np.all(na==[25,55,145], axis=-1)
# Briefly save the mask so we can see what it selects
Image.fromarray(mask).save('DEBUG-mask.png')
# Let's also count the number of pixels selected by the mask
print(np.count_nonzero(mask)) # prints 4,884
Now we can use the mask to change the selected pixels. Let's make the masked pixels red in the original image:
na[mask] = [255,0,0]
Image.fromarray(na).save('DEBUG-1.png')
Now use the inverse of the mask to affect unselected pixels. Let's make them grey:
na[~mask] = [128,128,128]
Image.fromarray(na).save('DEBUG-2.png')
If you want to mask more than one colour, use can use logical operations to combine the masks together. So, let's say you wanted to additionally mask the colour rgb(28,58,148), you could add the following to the end of the code above:
# Mask for second colour
mask2 = np.all(na==[28,58,148], axis=-1)
# Combine the two masks into new, bigger mask
both = mask | mask2
# Make masked pixels yellow and display
na[both] = [255,255,0]
Image.fromarray(na).show()
If you want to mask a range of colours, I would suggest OpenCV inRange()
which lets you set a lower and upper limit for R, G and B and then selects everything in-between.
import cv2
# Mask range 25>R>35, 55>G>65, 145<B<160
colRange = cv2.inRange(na,np.array([25,55,145]) ,np.array([35,65,160]))
# Make range of colours lime green
na[colRange>0] = [0,255,0]
If anyone is curious about how I made the radial gradient to start off with, I used ImageMagick in the Terminal and the following command:
magick -size 500x500 radial-gradient:"rgb(20, 50, 140)-rgb(40, 70, 160)" -depth 8 a.png
A simpler, clearer version might be:
magick -size 500x500 radial-gradient:lime-magenta -depth 8 a.png