BYU logo Computer Science

More with images

clouds

Using range()

range(n)

  • generates a sequence of numbers
  • starts from 0
  • counts up to and not including n
for number in range(10):
    print(number)
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9

Nested for loops!

for y in range(10):
    for x in range(5):
    0 0
    1 0
    2 0
    3 0
    4 0
    0 1
    1 1
    ...
    1 9
    2 9
    3 9
    4 9

Accessing pixels

  • uses an x,y coordinate scheme, (0,0) at upper left
  • x values move from left to right
  • y values move from top to bottom
  • each pixel is one color, a mixture of three RGB values

image pixels

New image functions

  • image.height: height of the image in pixels
  • image.width: width of the image in pixels
  • image.get_pixel(x,y): get the pixel at location (x,y)
from byuimage import Image

image = Image("mount-timpanogos.jpeg")
print(image.height)
print(image.width)
print(f"Height: {image.height}")
print(f"Width: {image.width}")
    427
    640
    Height: 427
    Width: 640

Let’s loop over the pixels a different way

  • nested for loops!
  • y = 0, then x = 0, 1, 2, 3, 4
  • y = 1, then x = 0, 1, 2, 3, 4

Let’s loop over the pixels a different way

  • nested for loops!
from byuimage import Image
def red_channel(filename):
    image = Image(filename)
    for y in range(image.height):
        for x in range(image.width):
            pixel = image.get_pixel(x,y)
            pixel.green = 0
            pixel.blue = 0

    return image

red_flower = red_channel("mount-timpanogos.jpeg")
red_flower.show()

Things to try:

  • add a print statement inside the nested loops to examine the values of x,y
  • try range(image.width - 20)
  • try swapping the for loops so we loop on x first, then y

Make an image darker

from byuimage import Image

def darker(image):
    """ Pass in an image, modify it """
    for y in range(image.height):
        for x in range(image.width):
            pixel = image.get_pixel(x, y)
            pixel.red = pixel.red * 0.5
            pixel.green = pixel.green * 0.5
            pixel.blue = pixel.blue * 0.5


image = Image("mount-timpanogos.jpeg")
darker(image)
image.show()

What if we don’t want to modify the original?

from byuimage import Image

def darker(image):
    """ Pass in an image, modify it """
    for y in range(image.height):
        for x in range(image.width):
            pixel = image.get_pixel(x, y)
            pixel.red = pixel.red * 0.5
            pixel.green = pixel.green * 0.5
            pixel.blue = pixel.blue * 0.5


image = Image("mount-timpanogos.jpeg")
darker(image)
image.show()

Making new images

Copying pixels

  • Imagine you have two pixels, a and b
  • How can you copy a so that b is the same?
b.red = a.red
b.green = a.green
b.blue = a.blue

Create a new, blank image

image = Image("mount-timpanogos.jpeg")

# create a blank white 100 x 50 image, store in variable named "new_image"
new_image = Image.blank(100, 50)

# create a blank image the same size as the original
copy_image = Image.blank(image.width, image.height)

# create an image twice as wide as the original
wide_image = Image.blank(image.width * 2, image.height)
wide_image.show()

Copy and make image darker

def darker(image):
    # Create out image, same size as original
    out =  Image.blank(image.width, image.height)
    for y in range(image.height):
        for x in range(image.width):
            pixel = image.get_pixel(x, y)
            pixel_out = out.get_pixel(x, y)
            pixel_out.red = pixel.red * 0.5
            pixel_out.green = pixel.green * 0.5
            pixel_out.blue = pixel.blue * 0.5
    return out

original = Image("mount-timpanogos.jpeg")

darker_image = darker(original)
darker_image.show()

original.show()

Aqua Stripe Problem

Create an image that has a 100 pixel wide aqua stripe on the left side, with a copy of the image next to it

aqua stripe solution

Planning — How big is the image?

original = Image("mount-timpanogos.jpeg")
print(f"Height: {original.height}, Width: {original.width}")
    Height: 427, Width: 640

Planning — What do we want?

aqua stripe planning

Planning — What do we need to do?

(1) create a new image

aqua stripe new image

Planning — What do we need to do?

(2) Make an aqua stripe, 100 pixels wide

aqua stripe make stripe

Planning — What do we need to do?

(3) Copy original image to right side of new image

aqua stripe copy image

Planning — What do we need to do?

original xoriginal yaqua xaqua y
001000
101010
201020
011001
111011
211021
  • reduced image
  • what is the relationship between original pixel and aqua pixel?
def aqua_stripe(original):
    """
    Put an aqua stripe to the left of an image, 100 pixels wide
    """
    border_width = 300
    # Create a blank image 100 pixels wider than the original.
    new_image = Image.blank(original.width + border_width, original.height)
    # Put an aqua colored vertical stripe 100 pixels wide at the left by setting red to 0.
    for y in range(new_image.height):
        for x in range(border_width):
            new_pixel = new_image.get_pixel(x, y)
            new_pixel.red = 0
            new_pixel.green = 0
            new_pixel.blue = 0
    # Copy the original image just to the right of the aqua stripe.
    for y in range(original.height):
        for x in range(original.width):
            original_pixel = original.get_pixel(x, y)
            new_pixel = new_image.get_pixel(x + 100, y)  # the key line
            new_pixel.red = original_pixel.red
            new_pixel.green = original_pixel.green
            new_pixel.blue = original_pixel.blue
    return new_image

original = Image("mount-timpanogos.jpeg")
aqua = aqua_stripe(original)
aqua.show()

Can we generalize our solution?

  • not a good idea to put the number 100 everywhere
  • could easily have off-by-one errors
    • see what happens if you use 101 or 99 in some places
  • have to be sure we use “100” in 3 different places
  • can we make a version that takes any width we specify?
def aqua_stripe(original, width):
    """
    Put an aqua stripe to the left of an image
    """
    # Create a blank image "width" pixels wider than the original.
    new_image = Image.blank(original.width + width, original.height)
    # Put an aqua colored vertical stripe at the left by setting red to 0.
    for y in range(new_image.height):
        for x in range(width):
            new_pixel = new_image.get_pixel(x, y)
            new_pixel.red = 0
    # Copy the original image just to the right of the aqua stripe.
    for y in range(original.height):
        for x in range(original.width):
            original_pixel = original.get_pixel(x, y)
            new_pixel = new_image.get_pixel(x + width, y)  # the key line
            new_pixel.red = original_pixel.red
            new_pixel.green = original_pixel.green
            new_pixel.blue = original_pixel.blue
    return new_image

original = Image("mount-timpanogos.jpeg")
aqua = aqua_stripe(original,10)
aqua.show()

Mirror Image Problem

mirror image solution

Planning

  • What do you think the steps are?
  • Class activity — talk to your neighbors

Planning

  • create a blank image that is twice as wide as the original
  • copy original image to new image on the left half
  • copy flip of original image to new image on the right half
    • what is the formula for this?

Planning

(1) create a blank image that is twice as wide as the original

mirror image new image

Planning

(2) copy original image to new image on the left half

mirror image left half

Planning

(3) copy flip of original image to new image on the right half

mirror image right half

What is the formula?

  • Pretend the original image is only 100 pixels wide

image formula

  • what are the equivalent coordinates in the new image? (talk to your neighbor)

  • A: (0, 0), B: (1, 0), C: (2, 0), D: (99, 0)

What is the formula?

original xoriginal ymirror xmirror y
001990
101980
201970
9901010

What is the formula?

original xoriginal ymirror xmirror y
001990
101980
201970
9901010
  • mirror_x = 200 - original_x - 1 = “new image width” - original_x - 1
  • mirror_y = original_y
def create_blank_double_wide(original):
    """ create a blank image that is twice as wide as the original

        original: original image
        returns: new image
    """
    doubled = Image.blank(2 * original.width, original.height)
    return doubled
def copy_left_half(original, doubled):
    """ copy original image into left half of new image

        original: original image
        image: image to copy the original into
    """
    for y in range(original.height):
        for x in range(original.width):
            pixel = original.get_pixel(x, y)
            pixel_left = doubled.get_pixel(x, y)
            pixel_left.red = pixel.red
            pixel_left.green = pixel.green
            pixel_left.blue = pixel.blue
def copy_right_half_mirror(original, doubled):
    """ copy a mirror of the original image into right half of new image

        original: original image
        image: image to copy original into
    """
    for y in range(original.height):
        for x in range(original.width):
            pixel = original.get_pixel(x, y)
            pixel_right = image.get_pixel(doubled.width - 1 - x, y)
            pixel_right.red = pixel.red
            pixel_right.green = pixel.green
            pixel_right.blue = pixel.blue
def mirror(original):
    # create a blank image that is twice as wide as the original
    doubled = create_blank_double_wide(original)
    # copy original image to new image on the left half
    copy_left_half(original, doubled)
    # copy flip of original image to new image on the right half
    copy_right_half_mirror(original, doubled)

    return image

original = Image("mount-timpanogos.jpeg")
mirror_image = mirror(original)
mirror_image.show()