Putpixel function not generating all the pixels

Viewed 553

My goal is to generate a color per pixel in order to fill up the whole canvas however the image generated always turns out black with only one of its pixels changed color, I can't seem to figure what I'm doing wrong.

import random
from PIL import Image

canvas = Image.new("RGB", (300,300))

y = random.randint(1, canvas.width)
x = random.randint(1, canvas.width)

r = random.randint(0,255)
g = random.randint(0,255)
b = random.randint(0,255)

rgb = (r,g,b)

for i in range(canvas.width): 
    canvas.putpixel((x,y), (rgb))

canvas.save("test.png", "PNG")

print("Image saved successfully.")
2 Answers

The problem with your code is that you are not iterating over every pixel. I've modified your code to iterate over every pixel, check whether or not it is black (0,0,0), then place a pixel on that iteration with your randomly-generated rgb value. Then, I regenerate 3 new random numbers and place them back into the rgb tuple causing the next pixel in the loop to have a different rgb value.

The x and y definitions are redundant, as you want a random color for every pixel but do not want random pixels, so I have removed them. I added a declaration, pixels = canvas.load() which allocates memory for the pixels so you can iterate over them and change each individual color. I heavily relied on this similar stackoverflow question, if you want further information. Here is my code:

canvas = Image.new("RGB", (300,300))
pixels = canvas.load()

width, height = canvas.size

for i in range(width): 
    for j in range(height):
        if pixels[i,j] == (0,0,0):
            r = random.randint(0,255)
            g = random.randint(0,255)
            b = random.randint(0,255)
            rgb = (r,g,b)
            canvas.putpixel((i,j), (rgb))
            
canvas.save("test.png", "PNG")

print("Image saved successfully.")

Here is the output produced:

enter image description here

You really should try and avoid using for loops in any Python image processing - they are slow and error-prone.

The easiest and fastest way to make a random image is using vectorised Numpy functions like this:

import numpy as np
from PIL import Image

# Create Numpy array 300x300x3 of random uint8
data = np.random.randint(0, 256, (300,300,3), dtype=np.uint8)

# Make into PIL Image
im = Image.fromarray(data)

enter image description here

Related