# Initialize Otter
import otter
grader = otter.Notebook("lab3-image.ipynb")

πŸ§ͺπŸ–₯ Lab 3: Image Processing#

This lab explores basic image processing in Python.

Entering Your Information for Credit#

To receive credit for assignments it is important we can identify your work from others. To do this we will ask you to enter your information in the following code block.

Before you begin#

Run the block of code at the top of the notebook that imports and sets up the autograder. This will allow you to check your work.

# Please provide your first name, last name, Drexel ID, and Drexel email. Make sure these are provided as strings. "STRINGS ARE TEXT ENCLOSED IN QUOTATION MARKS."

# In the assignments you will see sections of code that you need to fill in that are marked with ... (three dots). Replace the ... with your code.
first_name = ...
last_name = ...
drexel_id = ...
drexel_email = ...
grader.check("q0-Checking-Your-Name")
import matplotlib.pyplot as plt
import numpy as np

Loading and viewing Images

The matplotlib.pyplot module, which has been imported, can be used to load and view images. The following code loads an image called "bird.jpeg", scales it to have floating point pixel values from 0 to 1 (instead of 0 to 255), and stores it in a variable called img. Make sure the provided bird.jpeg file is in the same directory as this notebook.

img = plt.imread("bird.jpeg").astype("float") / 255

To view the image, we can use plt.imshow()

plt.imshow(img)

This image is represented in Python as a 3 dimensional array with dimensions (\(H\), \(W\), \(C\)), where

\(H\) = height

\(W\) = width

\(C\) = number of color channels

To view the dimensions, we can print the img array’s β€œshape” as below:

print(img.shape)

From this, we can see that this image has a height of 854 pixels, a width of 1000 pixels, and 3 color channels. The 3 color channels represent the red, green, and blue components of an image. The color of each pixel in the full color image is determined by its RGB components.

The following code lets us extract the three separate color channels from the image. We store these color channels – each with dimensions (\(H\),\(W\)) – in variables R, G, and B.

# For red, get the contents of the image at color channel index 0
R = img[:,:,0]

# For green, get the contents of the image at color channel index 1
G = img[:,:,1]

# For blue, get the contents of the image at color channel index 2
B = img[:,:,2]

We can view the 3 color channels individually like this:

# create a plot containing 3 subplots
figure, plots = plt.subplots(ncols=3, nrows=1)

### plotting the red component
# start with an empty image array of zeros
r_img = np.zeros(img.shape)
# populate the image with the red color channel data from img
r_img[:,:,0] = R
# plot the red component image
plots[0].imshow(r_img)
# turn off the axis to make the plot look tidy
plots[0].set_axis_off()

### plotting the green component
# start with an empty image array of zeros
g_img = np.zeros(img.shape)
# populate the image with the green color channel data from img
g_img[:,:,1] = G
# plot the red component image
plots[1].imshow(g_img)
# turn off the axis to make the plot look tidy
plots[1].set_axis_off()

### plotting the blue component
# start with an empty image array of zeros
b_img = np.zeros(img.shape)
# populate the image with the blue color channel data from img
b_img[:,:,2] = B
# plot the red component image
plots[2].imshow(b_img)
# turn off the axis to make the plot look tidy
plots[2].set_axis_off()

Task 1: To Black and White

Your task is to write a function that computes a black and white version of an image. A black and white (or grayscale) image has equal values for its \(R\), \(G\), and \(B\) components. One way to create a black and white version of a color images, that we will use in this lab, is to average the three color components. The new components newR, newG, and newB would be computed as follows.

newR = newG = newB = \(\frac{1}{3} \) (R \( + \) G \( + \) B \()\)

Hint: Numpy arrays of equal size can be added, subtracted, multiplied, etc. as if the were numbers. For instance, two arrays of equal dimensions a and b can be added pixel-by-pixel with the single line:

a + b

Write python code to do the following:

  • Define a function called to_bw which accepts as input a single argument, I, an array containing a color image.

  • In the function, first extract the red, blue, and green color components of the image. (You may replicate how this was done above.)

  • Compute the new components newR, newG, and newB, from R, G, and B using the equation above.

  • Create an array of zeros called bwI and give it the same shape as the input array I.

  • Populate the color channels of bwI to have the color components newR, newG, and newB.

  • Return the grayscale image bwI

Hint: If you have a numpy array X and you want to create an array of zeros that has the same shape as X, do the following: np.zeros(X.shape)

Your code replaces the prompt: ...

...
grader.check("task1-toBW")

View your black and white image:

plt.imshow(to_bw(img));

Task 2: To Sepia Tone

Sepia toning is a chemical process used in photography which gives an image a brownish coloring. Image editing software can approximate the effect of sepia toning using the given set of equations.

newR = 0.393 R + 0.769 G + 0.189 B

newG = 0.349 R + 0.686 G + 0.168 B

newB = 0.272 R + 0.534 G + 0.131 B

Finally, any resulting pixel values > 1.0 get assigned a value of 1.0.

Write python code to do the following:

  • Define a function called to_sepia which accepts as input a single argument, I, an array containing a color image.

  • As before, first extract the red, blue, and green color components of the image.

  • Compute the new components newR, newG, and newB, from R, G, and B using the set of equations above.

  • Create an array of zeros called sepiaI and give it the same shape as the input array I.

  • Populate the color channels of sepiaI to have the color components newR, newG, and newB.

  • For any values in the resulting image greater than \(1\), replace them with the value \(1\)

  • Return the sepia tone image sepiaI

Hint: Use np.where(sepiaI > 1.0) to get the indices in the sepia image where the value is greater than 1.

Your code replaces the prompt: ...

...
grader.check("task2-sepia")

View your sepia tone image:

plt.imshow(to_sepia(img));

Task 3: Cropping

It can be helpful to crop an image to make its size smaller and focus around an object of interest. Some AI image classification systems require training data that is cropped to a square region of interest.

In this problem your task is to crop the black and white image of the bird so that it is a square image centered around the bird. Specifically, you should crop a \(601\) x \(601\) square centered around the pixel with \((x,y)\) coordinates \((565,375)\). Note: The point \((0,0)\) is the top left of the image, and \(y\) coordinates increase towards the bottom.

Write python code to do the following:

  • Determine the desired range of \(x\)- and \(y\)-coordinates to crop

  • Use array slicing to crop the black and white bird image and store it in a variable called bw_bird_cropped.

Hint: The code I_crop = I[y1:y2+1,x1:x2+1] crops image I between \(x\) bounds [x1,x2] and \(y\) bounds [y1,y2] and stores the resulting image in a variable called I_crop.

Your code replaces the prompt: ...

...
grader.check("task3-cropping")

Let’s view the cropped image.

plt.imshow(bw_bird_cropped);

Task 4: Processing your own image

In this final task, you will load your own image and process it as if it were an input in an AI image classification network. You will choose an image relevant to your area of engineering, filter it to be black and white, and perform a square cropping around a region of interest.

Write python code to do the following:

  • Load an image of your choosing and store it in a variable called my_img

  • Store a black and white version of the image in a varialbe called bw_my_img

  • Store a cropped version of the black and white image in a variable called bw_my_img_cropped

  • Your crop should be square of an appropriate size, centered around the region of interest.

Hint: You will need to upload your image so that it is in the same directory as this notebook.

Your code replaces the prompt: ...

...
grader.check("task4-own-image")

View your cropped image:

plt.imshow(bw_my_img_cropped);

Submitting Your Assignment#

To submit your assignment please use the following link the assignment on GitHub classroom.

Use this link to navigate to the assignment on GitHub classroom.

Important: Make sure you submit your image file with your ipynb file.

If you need further instructions on submitting your assignment please look at Lab 1.

Viewing your score#

Each .ipynb file you have uploaded will have a file with the name of your file + Grade_Report.md. You can view this file by clicking on the file name. This will show you the results of the autograder.

We have both public and hidden tests. You will be able to see the score of both tests, but not the specific details of why the test passed or failed.

Note

In python and particularly jupyter notebooks it is common that during testing you run cells in a different order, or run cells and modify them. This can cause there to be local variables needed for your solution that would not be recreated on running your code again from scratch. Your assignment will be graded based on running your code from scratch. This means before you submit your assignment you should restart the kernel and run all cells. You can do this by clicking Kernel and selecting Restart and Run All. If you code does not run as expected after restarting the kernel and running all cells it means you have an error in your code.

Fin#