Loop Through Pixel Data

You can use Python Image Library (PIL) to modify all of the pixels in an image.

You’ll want to use nested for loops if you’re doing something to every pixel in the image.

After you create an image object, you can use the load() function to access the pixel data as an array.

This example prints the RGB values for the top left pixel in an image:

import PIL
img = PIL.Image.open('fruit.jpg')
pix = img.load()
print(pix[0,0])

You need to be able to load an image file for this to work. Go back and learn that if you haven’t done that yet.
(see Python Image Library and Import PIL)

Nested for loops:

for y in range(300):
    for x in range(400):
        r = pix[x,y][0]
        g = pix[x,y][1]
        b = pix[x,y][2]
        pix[x,y] = (r, g, b)

This example code reads the RGB (red, green, blue) values in every pixel of a 400 pixel wide x 300 pixel tall image.

pix is an array. You can retrieve the (r, g, b) color values from any pixel with “pix[x, y]” where x and y are int values within the size of the image file.

Notice the 0, 1, and 2. This is because each (r, g ,b) color has three values. The red value is number [0], the green value is number [1], and the blue value is number [2].

Bonus: you can use multiple assignment to create the r, g, and b variables at the same time:

r, g, b = pix[x,y]

In the last line, it sets the color at coordinates [x,y] to the same values as before: (r, g, b). If you want to modify the image, set (r, g, b) to something else. The pixel’s color must be set to a tuple with exactly three int values from 0 to 255. (tuples are similar to lists, but they use parentheses instead of square brackets, and you can’t change the individual values of a tuple)

Things to try:
Set all three values to the same number (such as the red value)

pix[x, y] = (r, r, r)

Change one or two of the values to zero

pix[x, y] = (0, g, b)

Change one or two of the values to 255

pix[x, y] = (r, r, 255)

Average the three numbers together

avg = (r + g + b) // 3
pix[x,y] = (avg, avg, avg)

Switch the variables around: e.g. swap red and blue
Change one or two of the values to 255

pix[x, y] = (b, g, r)

Add 100 to each value

pix[x, y] = (r+100,g+100,b+100)

Subtract each value from 255

pix[x, y] = (255-r, 255-g, 255-b)

Cut the values in half (use // operator to get int division result)

pix[x, y] = (r//2, g//2, b//2)

Things to notice:

The outer loop reads every horizontal row of pixels (y coordinate). The inner loop reads each pixel within a horizontal line of pixels (x coordinate).

Setting up the “y” loop as the outer loop causes the code to read the pixels from left to right, similar to the way an English speaking person reads text on a page.

You could also set the “x” loop as the outer loop if it bothers you that y comes before x. The result would be the same, but in this case the program would be reading down the first column of pixels, then moving one column to the right and reading down that column, and so on.

The example code “hard codes” the height and width of the image as range(300) and range(400). Instead of using numbers, a smarter way would be to read the height and width of the image and loop that exact number of times. Then your loop will work for any image size.

For reference, here’s how to read the size of the image object named “img”:

img.size  #gives a tuple: (width, height)
img.size[0] #gives the width as an int
img.size[1] #gives the height as an int

Bonus: you can use multiple assignment to create the width and height variables at the same time.

width, height = img.size

If your image mode is not “RGB,” the example above won’t work. If it’s an “RGBA” image, you’ll have to change the last line of example code to include that fourth value for the alpha channel. To check the mode of an image object named “img” you can do the following:

print(img.mode)