1 of 24

Manipulating Images

AKA Image Processing

Loops, Conditionals, Functions

Demo/show trinket: “image processing - compliment+switch colors”

2 of 24

Images as a collection of pixels

All Images are made of pixels: some Low Resolution vs. High Resolution

3 of 24

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)

4 of 24

Encoding color

5 of 24

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.

6 of 24

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.

7 of 24

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:

  1. Create a yellow horizontal line
  2. Create a thicker black horizontal line
  3. Create a green horizontal line at row 100, and a magenta horizontal line at row 180
  4. Create a blue vertical line
  5. Create a diagonal pink line (450 angle is fine)
  6. Optional: Create a diagonal cyan line from top corner to bottom corner

8 of 24

“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)

  • What happens if you change setDelay() ?
  • What happens if you add an outside for loop:
    • for row in range(pic.getHeight()):

9 of 24

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:

10 of 24

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)

11 of 24

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 :)

* 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

12 of 24

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

13 of 24

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

14 of 24

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”

15 of 24

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

16 of 24

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

17 of 24

“Distance” Between Two Colors

  • Sometimes you need to calculate the “distance between two colors”, when for example you want to determine if the two colors are “close enough” to each other.
  • We use a color distance formula similar to the geometric distance formula between 2 points in the plane:

  • Distance between points: P1: (x1, y1) P2: (x2, y2)

And by analogy, extending this:

  • Distance between colors: Pix1: (R1, G1, B1) Pix2: (R2, G2, B2)

d

18 of 24

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

19 of 24

Image processing functions - “Red-eye Effect”

  1. Reuse your change_to_destination() to create a “picture filtering” program which reduces the red-eye effect caused by camera flashes.

Trinket:

Red-eye Effect

You can use this image

Before: After:

# image processing - functions

Use https://imagecolorpicker.com/

to figure out the ref and dest pixel colors.

20 of 24

Image processing functions - “Sunset Effect”

  • Write a function changeRed(img, factor), to modify an image by multiplying the red component of every pixel by the given factor. It returns the modified image!
  • Write similar functions for changeGreen(img, factor) and changeBlue(img, factor)
  • Experiment with each effect (assume a float factor in the range 0.1 - 5.5)
  • Create a “sunset effect” with the functions above

# 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

21 of 24

Image processing functions - “Poster-izing”

  • When creating a poster from a picture, you try to minimize the number of colors you use, since each color/layer you print costs money (possibly $$$).
  • So you look at a range of colors and try to “map” it to a single color.
  • One way to do it:

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!)

Before: After:

# image processing - functions

22 of 24

Ex-Ex-Ex: Image processing functions - “Scaling”

  1. create a Python function which takes an image and an integer number (the scaling factor), and returns a scaled up (bigger) image depending on the factor (you can assume that the valid range for scaling is 1 through 4).

# image processing - resizing (scaling, zooming in)

the original image and a factor of 2

the original image and a factor of 3

23 of 24

End of Presentation

24 of 24

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.