Chapter 2: Pixels¶
Section 1: Inverted Sheep¶
We saw the negation or color inverting program in class. It generates negated picture like this:

The program that generates this looks like this:

Explaining the Snap program¶
As we talked in class, each component (or channel) color (red, green, and blue) is encoded as a single byte, and colors go from (0,0,0) to (255,255,255).
In the main body of the code, it starts with a for loop that selects each pixel in the pixels of the “sheep”. Then we set pixel red, pixel green, and pixel blue to a certain number. To achieve negating (reversing or inverting the color), we take 255 minus that value – we use 255 to minus the red pixel value in the picture, then 255 minus the green pixel value in the picture, then 255 minus the blue pixel value in the picture.
The Python Version¶
Let’s replicate this in Python. Here is the picture we will be manipulating.
sheepjpg
Press run to see this image get inverted/negated.
Let’s talk about how this works.
img = image.Image(“sheep.jpg”) creates a picture from the sheep.jpg file. This part is invisible in Snap – it happens when you drag the picture into the costumes tab.
pixels = img.getPixels() creates a list of all the pixels in the picture.
for p in pixels does the exact same thing as the for each pixel in pixels.
Each of the set functions changes the channel or component of that pixel.
255-p.getRed() means to subtract from 255 the current red channel of the pixel p.
img.updatePixel(p) tells the image to change itself from the newly manipulated pixel p. That happens in Snap, but inside the blocks.
The last two lines tell the browser to create an image window and to drag the sheep (in the variable img) in that window.
Try answering these questions about the code above.
- We want to change all pixels in the picture.
- Yes, JavaScript has `for` loops for repetition.
- That's a necessary part of all Python programs.
- Nope, only if you want a loop.
- It declares our intention to use the variable `p`
- No -- it does put values in `p` but that's not the only purpose.
- It's unnecessary
- No, it's critical to process the pixels.
Q-3: Why do we have the for loop above?
- No real difference
- No -- try it.
- Turns the picture black
- It's dark, but the picture is still there.
- Turns the picture white
- No, try it.
- Inverts, but much darker.
- Yes, because all values greater than 120 go to 0, which is very dark.
Q-4: What would happen if we changed all the 255 values to 120? (Yes, it’s totally fair to actually try it.)
- No real difference
- Yes, it's true. For many pictures, red works as a luminance value
- Turns the picture black
- No, try it.
- Turns the picture white
- No, try it.
- Turns the picture red.
- No, it's still grayscale because red=green=blue.
Q-5: What if we set all three of red, green and blue to 255-p.getRed()? (Yes, it’s totally fair to actually try it.)
Section 2: Posterize Big Ben¶
We saw a program that reduces the range of colors in two of the channels in class. It generates pictures like this:

The program that generates this looks like this:

Explaining the Snap program¶
Most pictures have a range of values in red, green, and blue channels – 0 to 255 in each, for 256 * 256 * 256 possible colors, well over 14 million. When we posterize, we reduce that possible range of colors. In this example, we are making all red channels one of two values (80 or 160) and all blues to one of two values (100 or 50). If we also limited to greens to two values, there would only be 8 possible colors in the whole picture. When you make a picture with poster paint, you usually only have a handful of colors – thus, posterizing is reducing the number of colors available.
The Python Version¶
Let’s replicate this in Python. Here is the picture we will be manipulating.
bigbenjpg
Press run to see this image get inverted/negated.
Let’s talk about how this works.
If-else means that either one path is taken (if the red is greater than 120), or the other is taken (if the red is less than or equal to 120). Always one of those two paths are taken. Thus, at the end of the loop, red will be either 80 or 160 and blue will be either 100 or 50.
Notice the indentation. That’s critical in Python. Python uses indentation to figure out which part happens if red is greater than 120 (p.setRed(80)), and then that the else: matches the if (because they’re indented the same). Notice the img.updatePixel(p) is indented the same as the if statements, but indented more than the for loop. That means the if statements and the update of the pixel are all inside the for loop. What’s in the loop and what’s outside the loop is easier to see with the shapes and colors of Snap.
Now, answer some questions about the code, please.
- We want to change all pixels in the picture.
- Yes, JavaScript has `for` loops for repetition.
- That's a necessary part of all Python programs.
- Nope, only if you want a loop.
- It declares our intention to use the variable `p`
- No -- it does put values in `p` but that's not the only purpose.
- It's unnecessary
- No, it's critical to process the pixels.
Q-8: Why do we have the for loop in this example above?
- We would add `p.setGreen()` to one of the existing `if` statements
- No, just adding one setGreen wouldn't split all the green values.
- We would add `p.setGreen()` to each of the `if` and `else` clauses of one of the `if` statements.
- Yes, that would reduce the green, but if you didn't choose the green values based on what was there before, it would probably look green.
- Need to add a statement like `if (p.getGreen()>100)`
- Yes, we would want to choose where to split the green values.
Q-9: If we wanted to reduce the range of green, we’d add to this program:
- It doesn't really matter, as long as we have two values of red.
- It's true that any values will result in posterizing, but if we want the picture to look like the original, the new values should be inside the split.
- It's probably a mistake.
- Nope, definitely picked those values on purpose.
- We're almost inverting red, since large values go lower and small values go higher.
- Yes, exactly. Try it the other way and see what you think.
- It wouldn't work any other way.
- Nope, any value between 0 and 255 would work.
Q-10: Something weird about this posterize is that if red is larger than 120, we’re setting it to a value less than 120 (80) and otherwise setting it to a value larger than 120 (160). The effect is:
Section 3: Grayscale and Invert¶
We saw a program in Snap in class that does two different effects to each side of the picture. It generates pictures like this:

The program that generates this looks like this:

Explaining the Snap program¶
This program is making a choice based on the x value of the pixel. The left of center is negative x, and right of center is positive x. This program inverts the right side (greater than 0), and computes grayscale for the leftside. To compute the grayscale, we compute the average of the red, green, and blue components as a luminance. We set all three of red, green, and blue to that luminance value.
The Python Version¶
Let’s replicate part of this in Python. Here is the picture we will be manipulating.
waterfalljpg
Press run to see this image get inverted/negated.
This program is creating grayscale, but to the whole picture. Like in the original Snap program, lum is a variable that will store the luminance. We set it to the average of red, green, and blue.
Now, answer some questions about the code, please.
- We see grayscale still.
- Turns out that it mostly works! Red is a good value for grayscale.
- We will see all red.
- No, it will be gray if red = green = blue.
- We will see no red.
- Sort of, but we won't see green or blue either.
- It will go black.
- No, that won't happen.
Q-13: What happens if we set lum = p.getRed()? (Feel free to try it!)
- `lum` is a predefined value for luminance.
- No, we could have named that variable anything.
- `lum` is the same value for all pictures.
- No, it will be different for *ever* pixel.
- `lum` is a temporary, local value for storing the luminance.
- Yes, exactly.
Q-14: Which of the following about lum in both programs is true?
- It will be the same grayscale.
- No, blue contains important information.
- It will be mostly grayscale, with a slight green colored tinge.
- Exactly -- try it!
- It will go black entirely.
- Nope, pixels will still be different values and still distinct.
Q-15: What would happen if you deleted the line p.setBlue(lum)? (Feel free to try it!)