Manipulating Images
AKA Image Processing
Loops, Conditionals, Functions
Demo/show trinket: “image processing - compliment+switch colors”
Images as a collection of pixels
All Images are made of pixels: some Low Resolution vs. High Resolution
A Picture is a 2D collection of pixels
A picture has two dimensions: width and height.
column & row pinpoint a location
We need an indication of color at that location
Rows, columns, colors
width (columns)
height (rows)
Encoding color
Each RGB color component (Red, Green, Blue) is a number represented in 8 bits (called 1 byte). Therefore we can store 256 (28) variations per component.
Image Components
We need the library
We need an image (“content”)
We can get some info
We need a window (“frame”)
Establish refresh rate*
Draw image in window (“put content in frame”)
* (mSec delay, nFrames update)
Examples of creating objects from a module/library:
my_turtle = turtle.Turtle() # from the turtle lib.
my_image = image.Image(“filename”) # from the image lib.
my_win = image.ImageWin(width, height) # from the image lib.
Looping through image pixels
We need the library
We need an image (“content”)
We need a window (“frame”)
Establish refresh rate
Draw image in window
Remix Starter project and rename it “Image Processing 1”: https://trinket.io/library/trinkets/914466336d
Remix the starter project below and then:
“Visiting”/Going Through ALL Pixels of an Image
Replacing (using set() ) Pixels:
Traversing the image
One pixel at a time
Going through every columns
From row to row
for row in range(the whole pic height):
for col in range(the whole pic width):
# “read” a pixel from the image:
existing_pixel = pic.getPixel(col, row)
# do some manipulation to existing colors
new_pixel = … #Create a new pixel
# “write” the new pixel into the image:
pic.setPixel(col, row, new_pixel)
https://trinket.io/library/trinkets/914466336d (WIP)
Image Library/Module Objects
pic = image.Image(“...”)
image library/Module
win = image.ImageWin(w, h)
pic.getWidth()
pic.getHeight()
pic.setDelay()
pic.draw(win)
pxl = pic.getPixel(x, y)
pic.setPixel(x, y, pxl)
pxl = image.Pixel(r, g, b)
pxl.getRed()
pxl.getGreen()
pxl.getBlue()
Similar to the turtle library/module having methods for turtles:
abbie = turtle.Turtle(), abbie.forward(100), abbie.xcor(), abbie.color()
Get and set every pixel in the image
create:
create:
create:
Uploading an Image File (in Trinket)
1. Switch to images tab (top right)
2. Click “+ Add Image” or
“+ Image Library”
Upload a 400 x 400 pixel image
from your computer (.png, .gif, .jpg)
Manipulating pixels
Changing pixels with
getPixel() and setPixel():
pic = image.Image(“...”)
current_pixel = pic.getPixel(column, row)
current_red = current_pixel.getRed()
…
new_red = current_red + 70 # caps at 255*
…
new_pixel = image.Pixel(new_red, new_green, new_blue)p
pic.setPixel(column, row, new_pixel)
What is the purpose of the double loop?
for …
for ...
Extra Fun: Remix and play with it.
No need to turn in :)
Starter Code at https://trinket.io/library/trinkets/5b4241e759
Image is here
* image.Pixel(R+x, G+y, B+z) maxes out at 255,255,255
image.Pixel(R-x, G-y, B-z) floors at 0,0,0
Image effects
for row in range(pic.getHeight()):
for col in range(pic.getWidth()):
old_pixel = pic.getPixel(col, row)
old_red = old_pixel.getRed()
old_green = old_pixel.getGreen()
old_blue = old_pixel.getBlue()
new_pixel = image.Pixel(old_blue, old_red, old_green) # 1
#new_pixel = image.Pixel(old_green, old_blue, old_red) # 2
pic.setPixel(col, row, new_pixel)
for row in range(pic.getHeight()):
for col in range(pic.getWidth()):
...
new_pixel = image.Pixel((old_green*15)%255, (old_blue*5)%255, (old_red*10)%255)
pic.setPixel(col, row, new_pixel)
for row in range(pic.getHeight()):
for col in range(pic.getWidth()):
old_pixel = pic.getPixel(col, row)
old_red = old_pixel.getRed()
old_green = old_pixel.getGreen()
old_blue = old_pixel.getBlue()
if row > img.getHeight() / 2:
new_pixel = image.Pixel(100, old_blue, old_red)
else:
new_pixel = image.Pixel(old_red, 50, old_green)
pic.setPixel(col, row, new_pixel)
#1 #2
The Original
Conditional Execution for “Shady Characters”
(next exercise on the next slide)
New Trinket: “Shady Characters”
Filename:
image processing - compliment+switch colors
For each “shady character” create a different function.
Put EACH Shady effect/character
In its own
FUNCTION
Image Manipulation (Trinket Name: “Shady Characters”)
The ‘Washed-out’
(make it whiter)
‘Prince of darkness’
(take color away)
Remember:
(red, green, blue) = (0, 0, 0) is total black
(red, green, blue) = (255, 255, 255) is total white
(red, green, blue) = (same, same, same) is grayscale
Image is here
When done: DO IN THE SAME TRINKET, the ones from Problem of the Day (PotD) “More Shady Characters”
The ‘Jailbird’
(setDelay(1, 1))
‘Of multiple minds’
The ‘Smallpoxed’
The Mesh (optional)
The ‘Graybeard’
(gray = same rgb)
Mesh (detail)
“M”
See hint on the
last slide
Smallpoxed (detail: a 2-by-2 pix every 2 pix)
“W” “G” “D”
“J” “MM” “S”
Image Manipulation - Combining Images
You can combine multiple images into a single image.
You can eliminate some pixels (e.g., transparent, white, black, etc.), as desired.
You can reposition, flip, rotate, etc.
Don’t use it for dishonest purposes! (e.g. “Deepfake - Moon Disaster”)
step 1
Instructions in PotD: New Trinket: “Combining Images” (remix starter project)
Hint: draw the Eiffel image. Then use getPixel() to “grab” a pixel from the original Armstrong image and setPixel() to place it wherever you want/need in the Eiffel image.
step 2
Hints on Combining Images - Don’t use it for dishonest purposes!
Step 1
width
height
P(x,y)
P(dx+x,dy+y)
P(wx-x,dy+y)
width
height
Step 2
P(x,y)
dx
x
dy
x
wx
x
x
dy
“Distance” Between Two Colors
And by analogy, extending this:
d
Image processing functions - change by distance
Preparing for Red-Eye Effect (next slide): Write a function change_to_destination(img, ref_pix, distance, dest_pix) which will be called by your main program (see below), and will replace each pixel in the image with dest_pix, if its color is “close” (in terms of ‘distance’) to the color of the ref_pix, otherwise it’ll leave the pixel as-is (i.e., won’t replace it).
# main:
img = image.Image("jack_of_diamonds3.png")
win = image.ImageWin(img.getWidth(), img.getHeight())
img.setDelay(1, 100) # fast update . setDelay(0) turns off animation
img.draw(win)
ref_pixel = image.Pixel(255, 0, 0) # red - reference pixel
dest_pixel = image.Pixel(0, 0, 0) # black - destination pixel
# if a pixel is close (within a distance of 100) to red, change it to black:
distance = 100
change_to_destination(img, ref_pixel, distance, dest_pixel)
img.draw(win)
You can use this image
Before After
Image processing functions - “Red-eye Effect”
Before: After:
# image processing - functions
Use https://imagecolorpicker.com/
to figure out the ref and dest pixel colors.
Image processing functions - “Sunset Effect”
# main:
img = image.Image("beach_normal.png")
win = image.ImageWin(img.getWidth(), img.getHeight())
img.setDelay(1, 100) # fast update . setDelay(0) turns it off
img.draw(win) # original: pic. 1 (see on the right)
# do the processing with changeRed(), changeGreen(), changeBlue()
# one at a time (pic’s 2 & 3 show intermediate results)
img = changeRed(img, factor1) # does NOT actually turn it to sunset
img = changeBlue(img, factor2) # reduce Green and Blue
img = changeGreen(img, factor3)
img.draw(win) # sunset - final: pic. 3 (see on the right)
-----------------------------------------------------------------
See PotD for requirements and image:
Image Manipulation instructions: “Sunset Effect”
Image/picture: “daylight beach”
1
2
3
Image processing functions - “Poster-izing”
get the red color and :
If 0 <= color <= 64, make it 32.
If 65 <= color <= 128, make it 97.
Similarly, for
the range up to 192, and
the range up to 255.
Similarly, do it for green and blue.
Note: Minimize the number of if/else’s
when coding (i.e., use/code common/reusable functions!)
PotD: Poster-izing
Before: After:
# image processing - functions
Ex-Ex-Ex: Image processing functions - “Scaling”
PotD: Image Scaling
# image processing - resizing (scaling, zooming in)
the original image and a factor of 2 | the original image and a factor of 3 |
End of Presentation
Hint: Shady Characters - The Mesh
col -> row v | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
0 | 1 | -1 | 1 | -1 | 1 | -1 | 1 | -1 | 1 | -1 | 1 | -1 | 1 | -1 |
1 | -1 | 1 | -1 | 1 | -1 | 1 | -1 | 1 | -1 | 1 | -1 | 1 | -1 | 1 |
2 | 1 | -1 | 1 | -1 | 1 | -1 | 1 | -1 | 1 | -1 | 1 | -1 | 1 | -1 |
3 | -1 | 1 | -1 | 1 | -1 | 1 | -1 | 1 | -1 | 1 | -1 | 1 | -1 | 1 |
4 | 1 | -1 | 1 | -1 | 1 | -1 | 1 | -1 | 1 | -1 | 1 | -1 | 1 | -1 |
5 | -1 | 1 | -1 | 1 | -1 | 1 | -1 | 1 | -1 | 1 | -1 | 1 | -1 | 1 |
Hint: The picture above shows that with a help of a “flip” variable “oscillating” between 1 and -1 you can detect a pattern which creates the mesh.