Homework 2 - Image Manipulation

Objectives

  • Practice creating a program from an empty file
  • Practice image manipulation operations

Introduction

This homework is designed to help you implement some of the functionality you will be able to build off of in your Project 1 program.

In this homework we will build functions that can vertically flip an image and that can add borders to an image. Most of the functions you wrote in Lab 5 looped over every pixel in an image, allowing you to modify each pixel as an individual object. As you write the functions for this homework that flip images or add borders, you won't be able to simply loop over every pixel in the image. You'll need to think about the specific position of each pixel in the image, and how the positions of the pixels constitute the image as a whole.

All of your code should be submitted in a file named homework2.py. You can get the files for this assignment by downloading homework02.zip.

Part 1 - Flipping an Image

Task 1 - Setup

Start by opening the file called homework2.py

In this file add the following lines:

if __name__ == "__main__":
pass

The functions you write will go above this line. We'll refer to the area after this "if" statement (in place of the pass statement) as the "main code block." It could just contain a single function call (to a function named main() or run() or something similar) or it could be a series of statements to execute. It's a great place to write code to test your functions as you're working on them.

The "if" statement checks to see if you are running the code as a program (e.g. when you invoke it with python homework2.py versus when you import the file as a library by writing import homework2 at the top of another script). The code after the "if" statement only executes when you run the code as a program. You should just get in the habit of adding those lines to any file you create, since seeing and using this a lot througout this course.

Finally at the top of your file, import the Image class from the byuimage library, just like you did in Lab 5.

Task 2 - Flip the Image

In this task you will write a function that takes an original image like this:

landscape

and flips it vertically so it looks like this:

flipped-landscape

In homework2.py file create a flipped() function. As its argument it should take a filename to load the image from so the function declaration should look like this:

def flipped(filename):

You already know how to read in an image (remember Lab 5), add that code to your "flipped" function. Now we need to add the code to create the flipped image. This process has two parts: 1) you need to create a new empty image the same size as the original image, 2) you need loop over all the pixels in the original image and copy them to the correct position in the new image. Once finished, your function should return the flipped image.

To create a new image, use the Image.blank() method to create an empty image using the height and width attributes of the image you read in from the file.

When copying the pixels, remember that you can loop over the x and y dimensions:

for y in range(0, <image height>):
for x in range(0, <image width>):
## code to manipulate the pixel

Also recall that when flipping the image, the horizontal position of the pixel won't change, but its vertical position will. If you are copying from position (x, y), then the pixel should be moving to (x, <image height> - y - 1). You can access individual pixels of an image by their position with the .get_pixel(x, y) function.

After you've finished writing your flipped() function add some code to your main code block that reads in a file, calls your function flipped() and displays the result. Look at the output image and make sure it is correct. Are there any white lines at the top or bottom? If so, you probably have your indexing off in the flipped() function.

Part 2 - Borders

In this part of the homework, we'll create a function, make_borders() that will put a border of equal thickness all the way around an image. This function will take five arguments: a filename containing an image to modify, the thickness of the border, and color values for the red, green, and blue channels in the border region.

if you started with this image

landcape

and added a 30 pixel green (red = 0, green = 255, blue = 0) border, your function will return an image that looks like this

landscape-with-border

Task 1 - Create the function and read the image

Start by creating the make_borders() function. This function should have a declaration that looks like this:

def make_borders(filename, thickness, red, green, blue):

Once the file is created, add code to read in the image specified by the filename parameter.

Task 2 - Make the new image and fill in the border color

Just like in Part 1, you need to create a new image object. Unlike the new image from Part 1, it won't be the exact same size as the original image but rather will be larger having thickness pixels added to each side of the image.

After you've created the new image, you'll need to fill in the border region with the color specified by the red, green, and blue parameter values. You could just loop over the entire image and set the pixels to that color, or if you wanted to be more efficient, you could just loop over the border region. How you implement it is up to you.

At this point you should consider adding code to your main block to call this function and ensure that you are getting back a large image that has the border region filled in with the correct color.

Task 3 - Copy the original image

Now that the borders are all set up, it's time to copy the pixels from the original image into the new one. Just like in Task 2 of Part 1, you can loop over the pixels of the original image in a nested "for" loop. In this case, a pixel at position (x, y) in the original image will end up at (x + thickness, y + thickness) in the new image.

Once the original image is copied over, the function should return the new image.

If you already added code to call the function and display the result in your main code block, running it now should show the final product of the original image with the border added. Remember that you can use .show() to show your image at any point, but you will need to return the finished image from your function.

Turn in your work

Submit homework2.py on Canvas via Gradescope where it will be checked via the auto grader. We will be testing your program using a variety of image of different sizes in addition to the sample files we gave you, so make sure that you haven't "hard coded" anything specific to your data.

© 2024 Brigham Young University, All Rights Reserved