2

I am working with .png files, having pixels values 1 and 255.
I have to map pixel values 255 to 0 and, in other cases, pixels with values 1 to 2.
I tried:

for img_name in good_imgs:
  img = Image.open(img_name)
  pixels = img.load() 
  for i in range(img.size[0]):
    for j in range(img.size[1]):
        if pixels[i,j] == 255:
          pixels[i,j] = 0
  img.save(img_name)

for img_name in bad_imgs:
  img = Image.open(img_name)
  pixels = img.load() 
  for i in range(img.size[0]):
    for j in range(img.size[1]):
        if pixels[i,j] == 255:
          pixels[i,j] = 0
        elif pixels[i,j] == 1:
          pixels[i,j] == 2
  img.save(img_name)

but the images saved in this way, have the same pixels values as the originals.
What is wrong with the above code? How can I change pixels values in this kind of images?

Updtate:
I have noticed that if I modified the pixel of a single image, the pixels are mapped correctly, i.e. now I suppose the issue is about saving images with img.save()

Simone
  • 4,800
  • 12
  • 30
  • 46
  • 1
    post one sample image – Colim Jul 13 '22 at 12:44
  • While not a full duplicate, your question is very similar to [https://stackoverflow.com/questions/45613544/python-opencv-cannot-change-pixel-value-of-a-picture](https://stackoverflow.com/questions/45613544/python-opencv-cannot-change-pixel-value-of-a-picture) There are several ways to set pixel values with OpenCV described there. – Barry the Platipus Jul 13 '22 at 10:59
  • 1
    Your image is likely a palette image, see here... https://stackoverflow.com/a/52307690/2836621 – Mark Setchell Jul 14 '22 at 08:49
  • 1
    Using `for` loops for image processing is seriously slow, inefficient and error-prone. You really should be using PIL functions, or Numpy functions https://stackoverflow.com/a/72846363/2836621 – Mark Setchell Jul 14 '22 at 08:53

1 Answers1

1

As I mentioned in the comments, for loops are slow, inefficient and error-prone for processing images in Python.

Here's a more efficient way of doing what you ask. Your colours of 0, 1, 2 and 255 are hard to see on StackOverflow's background and hard to differentiate from each other because 3 of them are essentially black, so I am transforming 64 and 150 into 192 and 32 but you can adapt to your own numbers:

enter image description here

from PIL import Image

# Load image and ensure greyscale, i.e. 'L'
im = Image.open('image.png').convert('L')

# Remap colours 150 -> 32, 64 -> 192
res = im.point((lambda p: 32 if p==150 else (192 if p==64 else 0)))

res.save('result.png')

enter image description here


If you want to use Numpy instead, which is also vectorised and optimised, it might look like this (other techniques are also possible):

from PIL import Image
import numpy as np

# Load image and ensure greyscale, i.e. 'L'
im = Image.open('image.png').convert('L')

# Make into Numpy array
na = np.array(im)

# Anywhere pixels are 150, make them 32
na[na==150] = 32

# Anywhere pixels are 64, make them 192
na[na==64] = 192

# Convert back to PIL Image and save
Image.fromarray(na).save('result.png')
Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
  • Now it works! I left images in `mode P`, because I don't need to visualize them, but only to change pixels values. – Simone Jul 15 '22 at 15:03