[+] Add a1 files
This commit is contained in:
Executable
+98
@@ -0,0 +1,98 @@
|
||||
\documentclass[fontsize=11pt]{article}
|
||||
\usepackage[utf8]{inputenc}
|
||||
\usepackage[margin=0.75in]{geometry}
|
||||
|
||||
\title{CSC110 Fall 2021 Assignment 1: Written Questions}
|
||||
\author{TODO: FILL IN YOUR NAME HERE}
|
||||
\date{\today}
|
||||
|
||||
\begin{document}
|
||||
\maketitle
|
||||
|
||||
\section*{Part 1: Data and Comprehensions}
|
||||
|
||||
\begin{enumerate}
|
||||
\item[1.] \textbf{Imagine this scenario...}
|
||||
\begin{enumerate}
|
||||
\item[(a)]
|
||||
TODO: Write your answer here.
|
||||
|
||||
\item[(b)]
|
||||
TODO: Write your answer here.
|
||||
|
||||
\item[(c)]
|
||||
TODO: Write your answer here.
|
||||
|
||||
\item[(d)]
|
||||
TODO: Write your answer here.
|
||||
|
||||
\item[(e)]
|
||||
TODO: Write your answer here.
|
||||
\end{enumerate}
|
||||
|
||||
\item[2.] \textbf{Exploring comprehensions.}
|
||||
|
||||
\begin{enumerate}
|
||||
\item[(a)]
|
||||
\begin{enumerate}
|
||||
\item[i.] TODO: Write your answer here.
|
||||
\item[ii.] TODO: Write your answer here.
|
||||
\end{enumerate}
|
||||
\item[(b)]
|
||||
\begin{enumerate}
|
||||
\item[i.] TODO: Write your answer here.
|
||||
\item[ii.] TODO: Write your answer here.
|
||||
\item[iii.] TODO: Write your answer here.
|
||||
\end{enumerate}
|
||||
\item[(c)]
|
||||
TODO: Write your answer here.
|
||||
\item[(d)]
|
||||
TODO: Write your answer here.
|
||||
\end{enumerate}
|
||||
\end{enumerate}
|
||||
|
||||
\section*{Part 2: Programming Exercises}
|
||||
|
||||
Complete this part in the provided \texttt{a1\_part2.py} starter file.
|
||||
Do \textbf{not} include your solution in this file.
|
||||
|
||||
\section*{Part 3: Pytest Debugging Exercise}
|
||||
|
||||
% TIP: In LaTeX, the underscore (_) is a special character, so if you want to use it
|
||||
% in normal text, you have to put a backslash in front of it. E.g., a1\_part2.py,
|
||||
% not a1_part2.py.
|
||||
|
||||
\begin{enumerate}
|
||||
\item[1.]
|
||||
TODO: Write your answer here.
|
||||
|
||||
\item[2.]
|
||||
TODO: Write your answer here.
|
||||
|
||||
\item[3.]
|
||||
TODO: Write your answer here.
|
||||
\end{enumerate}
|
||||
|
||||
\section*{Part 4: Adding Noise to an Image}
|
||||
|
||||
Complete this part in the provided \texttt{a1\_part4.py} starter file.
|
||||
Do \textbf{not} include your solution in this file.
|
||||
|
||||
\newpage
|
||||
|
||||
\section*{Part 5: Removing Noise From an Image}
|
||||
|
||||
\subsection*{Implementation}
|
||||
|
||||
Complete this part in the provided \texttt{a1\_part5.py} starter file.
|
||||
Do \textbf{not} include your solution in this file.
|
||||
|
||||
\subsection*{Exploration}
|
||||
|
||||
\begin{enumerate}
|
||||
\item[1.] TODO: Write your answer here.
|
||||
\item[2.] TODO: Write your answer here.
|
||||
\item[3.] TODO: Write your answer here.
|
||||
\end{enumerate}
|
||||
|
||||
\end{document}
|
||||
Executable
+49
@@ -0,0 +1,49 @@
|
||||
"""CSC110 Fall 2021 Assignment 1, Bitmap Handling
|
||||
|
||||
Instructions (READ THIS FIRST!)
|
||||
===============================
|
||||
|
||||
Do not make changes to this file.
|
||||
|
||||
Copyright and Usage Information
|
||||
===============================
|
||||
|
||||
This file is provided solely for the personal and private use of students
|
||||
taking CSC110 at the University of Toronto St. George campus. All forms of
|
||||
distribution of this code, whether as given or with any changes, are
|
||||
expressly prohibited. For more information on copyright for CSC110 materials,
|
||||
please consult our Course Syllabus.
|
||||
|
||||
This file is Copyright (c) 2021 Mario Badr and Tom Fairgrieve.
|
||||
"""
|
||||
|
||||
from PIL import Image
|
||||
|
||||
|
||||
def load_image(filename: str) -> tuple:
|
||||
"""Return a three-element tuple containing data on the image found at filename.
|
||||
|
||||
The first element of the tuple is a list of all the pixels in the image. Each pixel is a
|
||||
three-element tuple that represents the red, green, and blue colour channels.
|
||||
The second element of the tuple is the width of the image, in pixels.
|
||||
The third element of the tuple is the height of the image, in pixels.
|
||||
|
||||
Assumes that a valid image can be found at filename.
|
||||
"""
|
||||
image = Image.open(filename)
|
||||
|
||||
pixel_data = image.load()
|
||||
width, height = image.size
|
||||
pixel_1d = [pixel_data[x, y] for y in range(height) for x in range(width)]
|
||||
|
||||
return pixel_1d, width, height
|
||||
|
||||
|
||||
def save_image(filename: str, pixels: list, width: int, height: int) -> None:
|
||||
"""Create a width by height image containing pixels and save it to a file called filename.
|
||||
"""
|
||||
image = Image.new('RGB', (width, height))
|
||||
|
||||
[image.putpixel((x, y), pixels[x + y * width]) for x in range(width) for y in range(height)]
|
||||
|
||||
image.save(filename)
|
||||
Executable
+109
@@ -0,0 +1,109 @@
|
||||
"""CSC110 Fall 2021 Assignment 1, Part 3: Debugging Exercises
|
||||
|
||||
Instructions (READ THIS FIRST!)
|
||||
===============================
|
||||
|
||||
This Python module contains the program and tests described in Part 3.
|
||||
You can run this file as given to see the pytest report given in the handout.
|
||||
Your task is to fix all errors in this file so that each test passes
|
||||
(see assignment handout for details).
|
||||
|
||||
Copyright and Usage Information
|
||||
===============================
|
||||
|
||||
This file is provided solely for the personal and private use of students
|
||||
taking CSC110 at the University of Toronto St. George campus. All forms of
|
||||
distribution of this code, whether as given or with any changes, are
|
||||
expressly prohibited. For more information on copyright for CSC110 materials,
|
||||
please consult our Course Syllabus.
|
||||
|
||||
This file is Copyright (c) 2021 David Liu, Mario Badr, and Tom Fairgrieve.
|
||||
"""
|
||||
import math
|
||||
import pytest
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Professor Xavier's program
|
||||
###############################################################################
|
||||
def class_average(class_grades: list) -> float:
|
||||
"""Return the weighted average grade of students for all grades in class_grades.
|
||||
|
||||
Each element of class_grades is itself a list, containing three floats
|
||||
representing the grades of a particular student on the three assignments.
|
||||
|
||||
See assignment handout for details.
|
||||
|
||||
You may ASSUME that:
|
||||
- class_grades is non-empty
|
||||
- class_grades contains only lists
|
||||
- the lists in class_grades contain exactly three floats
|
||||
- each float in each list is between 0.0 and 100.0.
|
||||
|
||||
"""
|
||||
student_averages = [student_average(grades) for grades in class_grades]
|
||||
|
||||
# Return the average grade across all students in this section
|
||||
return sum(student_averages) / len(student_averages)
|
||||
|
||||
|
||||
def student_average(grades: list) -> float:
|
||||
"""Return the weighted average of a student's grades.
|
||||
|
||||
You may ASSUME that:
|
||||
- grades consists of exactly three float values
|
||||
"""
|
||||
# Sort the student's grades
|
||||
sorted_grades = sorted(grades)
|
||||
|
||||
# These are the weights for the assignment grades
|
||||
weights = [0.4, 0.35, 0.25]
|
||||
|
||||
return (
|
||||
weights[0] * sorted_grades[0] +
|
||||
weights[1] * sorted_grades[1] +
|
||||
weights[2] * sorted_grades[2]
|
||||
)
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Tests for section_average
|
||||
###############################################################################
|
||||
def test_section_average_all_grades_equal() -> None:
|
||||
"""Test section_average when students have the same grade on each assignment.
|
||||
"""
|
||||
grades = [[80.0, 80.0, 80.0],
|
||||
[90.0, 90.0, 90.0]]
|
||||
|
||||
expected = 85.0
|
||||
actual = class_average(grades)
|
||||
assert math.isclose(actual, expected)
|
||||
|
||||
|
||||
def test_class_average_no_grades_equal() -> None:
|
||||
"""Test class_average when every grade is different.
|
||||
"""
|
||||
grades = [['60.0', '70.0', '75.0'], ['80.0', '65.0', '85.0']]
|
||||
|
||||
expected = 73.875
|
||||
actual = class_average(grades)
|
||||
assert math.isclose(actual, expected)
|
||||
|
||||
|
||||
def test_class_average_many_students() -> None:
|
||||
"""Test class_average when there are a lot of students in a section.
|
||||
"""
|
||||
grades = [[80.0, 70.0, 75.0],
|
||||
[90.0, 78.0, 65.0],
|
||||
[66.0, 74.0, 60.0],
|
||||
[60.0, 55.0, 75.0],
|
||||
[82.0, 80.0, 88.0],
|
||||
[50.0, 88.0, 73.0]]
|
||||
|
||||
expected = 74.15
|
||||
actual = class_average(grades)
|
||||
assert math.isclose(actual, expected)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pytest.main(['a1_part3.py', '-v'])
|
||||
Executable
+115
@@ -0,0 +1,115 @@
|
||||
"""CSC110 Fall 2021 Assignment 1, Part 4
|
||||
|
||||
Instructions (READ THIS FIRST!)
|
||||
===============================
|
||||
|
||||
Please follow the instructions in the assignment handout to complete this file.
|
||||
|
||||
Copyright and Usage Information
|
||||
===============================
|
||||
|
||||
This file is provided solely for the personal and private use of students
|
||||
taking CSC110 at the University of Toronto St. George campus. All forms of
|
||||
distribution of this code, whether as given or with any changes, are
|
||||
expressly prohibited. For more information on copyright for CSC110 materials,
|
||||
please consult our Course Syllabus.
|
||||
|
||||
This file is Copyright (c) 2021 Mario Badr and Tom Fairgrieve.
|
||||
"""
|
||||
import random
|
||||
|
||||
import a1_image
|
||||
|
||||
|
||||
def maximize_channels(old_pixel: tuple, value: int) -> tuple:
|
||||
"""Return a new pixel that has colour channels set to the larger of value or the corresponding
|
||||
colour channel in old_pixel.
|
||||
|
||||
>>> example_pixel = (100, 12, 155)
|
||||
>>> maximize_channels(example_pixel, 128)
|
||||
(128, 128, 155)
|
||||
"""
|
||||
|
||||
|
||||
def divide_channels(old_pixel: tuple, denominator: int) -> tuple:
|
||||
"""Return a new pixel that has colour channels set to the quotient from dividing the
|
||||
corresponding colour channel in old_pixel by denominator.
|
||||
|
||||
>>> example_pixel = (100, 12, 155)
|
||||
>>> divide_channels(example_pixel, 2)
|
||||
(50, 6, 77)
|
||||
"""
|
||||
|
||||
|
||||
def add_pepper(pixel_data: list, k: int) -> list:
|
||||
"""Return a new list of pixels formed from the corresponding pixels in pixel_data that has some
|
||||
randomly chosen black pixels.
|
||||
|
||||
The chance that a new pixel will be black is based on k. The probability that a pixel is
|
||||
black is to be : 1 / (k + 1)
|
||||
|
||||
Assume that k >= 0.
|
||||
|
||||
You must use the divide_channels function (above).
|
||||
|
||||
Hint: use the function random.choice to choose from a list of denominators. What denominator,
|
||||
passed to divide_channels, causes a pixel to not change its colour? What denominator causes a
|
||||
pixel to become black?
|
||||
|
||||
Because of the randomness, we can't specify an exact doctest.
|
||||
"""
|
||||
|
||||
|
||||
def add_salt(pixel_data: list, k: int) -> list:
|
||||
"""Return a new list of pixels formed from the corresponding pixels in pixel_data that has some
|
||||
randomly chosen white pixels.
|
||||
|
||||
The chance that a new pixel will be white is based on k. The probability that a pixel is
|
||||
white is to be : 1 / (k + 1)
|
||||
|
||||
Assume that k >= 0.
|
||||
|
||||
You must use the maximize_channels function (above).
|
||||
|
||||
Hint: use the function random.choice to choose from a list of values. What value, passed to
|
||||
maximize_channels, causes a pixel to not change its colour? What value causes a pixel to become
|
||||
white?
|
||||
|
||||
Because of the randomness, we can't specify an exact doctest.
|
||||
"""
|
||||
|
||||
|
||||
def add_salt_and_pepper(pixel_data: list, k: int) -> list:
|
||||
"""Return a new list of pixels formed from the corresponding pixels in pixel_data
|
||||
that has some randomly chosen white pixels and some randomly chosen black pixels.
|
||||
|
||||
You must use the add_pepper then add_salt functions, in that order, with both using noise
|
||||
probabilities determined by k.
|
||||
|
||||
Because of the randomness, we can't specify an exact doctest.
|
||||
"""
|
||||
|
||||
|
||||
def run_salt_and_pepper_example(source: str, destination: str, k: int) -> None:
|
||||
"""Add salt and pepper noise to an example image file at source and save the result in
|
||||
destination, where noisiness is a function of k.
|
||||
|
||||
You can run this function with an image of your choice. Make sure the image is not too large or
|
||||
this will take a long time.
|
||||
"""
|
||||
original_pixel_data, width, height = a1_image.load_image(source)
|
||||
noisy_pixel_data = add_salt_and_pepper(original_pixel_data, k)
|
||||
a1_image.save_image(destination, noisy_pixel_data, width, height)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
||||
# When you are ready to check your work with python_ta, uncomment the following lines.
|
||||
# (Delete the "#" and space before each line.)
|
||||
# import python_ta
|
||||
# python_ta.check_all(config={
|
||||
# 'extra-imports': ['random', 'a1_image'],
|
||||
# 'max-line-length': 100
|
||||
# })
|
||||
Executable
+148
@@ -0,0 +1,148 @@
|
||||
"""CSC110 Fall 2021 Assignment 1, Part 5
|
||||
|
||||
Instructions (READ THIS FIRST!)
|
||||
===============================
|
||||
|
||||
Please follow the instructions in the assignment handout to complete this file.
|
||||
|
||||
Throughout this module, we assume that images are at least 4 pixels wide and 4 pixels high.
|
||||
|
||||
Copyright and Usage Information
|
||||
===============================
|
||||
|
||||
This file is provided solely for the personal and private use of students
|
||||
taking CSC110 at the University of Toronto St. George campus. All forms of
|
||||
distribution of this code, whether as given or with any changes, are
|
||||
expressly prohibited. For more information on copyright for CSC110 materials,
|
||||
please consult our Course Syllabus.
|
||||
|
||||
This file is Copyright (c) 2021 Mario Badr and Tom Fairgrieve.
|
||||
"""
|
||||
from statistics import median
|
||||
|
||||
import a1_image
|
||||
|
||||
|
||||
def create_example_pixel_data() -> list:
|
||||
"""Return a new list of pixels that can be used in the doctest examples. The list describes
|
||||
an image that is 4 pixels wide and 4 pixels high. Each element in the list is a three-element
|
||||
tuple that corresponds to the red, green, and blue colour channels, respectively.
|
||||
|
||||
The pixels appear in the order of left-to-right, bottom-to-top (i.e., the same as
|
||||
a1_image.load_image).
|
||||
"""
|
||||
return [(128, 128, 128), (35, 50, 65), (210, 32, 68), (32, 208, 43), # y = 0 (bottom)
|
||||
(130, 20, 42), (43, 44, 45), (17, 243, 82), (61, 85, 92), # y = 1
|
||||
(201, 23, 23), (23, 23, 23), (42, 180, 19), (16, 58, 29), # y = 2
|
||||
(1, 52, 128), (26, 123, 128), (71, 234, 82), (23, 108, 34)] # y = 3 (top)
|
||||
|
||||
|
||||
def get_pixel(pixel_data: list, image_width: int, x: int, y: int) -> tuple:
|
||||
"""Return a new RGB-tuple of the pixel at location (x, y) from the pixels in pixel_data that has
|
||||
width image_width.
|
||||
|
||||
Assume that pixel_data was obtained from an image using a1_image.load_image.
|
||||
|
||||
>>> example_pixels = create_example_pixel_data()
|
||||
>>> get_pixel(example_pixels, 4, 0, 0)
|
||||
(128, 128, 128)
|
||||
>>> get_pixel(example_pixels, 4, 1, 2)
|
||||
(23, 23, 23)
|
||||
"""
|
||||
index = x + y * image_width
|
||||
r, g, b = pixel_data[index]
|
||||
|
||||
return r, g, b
|
||||
|
||||
|
||||
def get_pixel_window(pixel_data: list, width: int, x: int, y: int) -> list:
|
||||
"""Return a new list of RGB-tuples of the pixel at (x, y), along with its neighbours, from the
|
||||
pixels in pixel_data that has width image_width.
|
||||
|
||||
A neighbouring pixel is a pixel that "touches" the pixel at (x, y), including diagonals.
|
||||
|
||||
Assume that the location (x, y) is not on any edge of the image described in pixel_data.
|
||||
|
||||
>>> example_pixels = create_example_pixel_data()
|
||||
>>> get_pixel_window(example_pixels, 4, 1, 1)
|
||||
[(201, 23, 23), (23, 23, 23), (42, 180, 19), (130, 20, 42), (43, 44, 45), (17, 243, 82), \
|
||||
(128, 128, 128), (35, 50, 65), (210, 32, 68)]
|
||||
>>> get_pixel_window(example_pixels, 4, 2, 2)
|
||||
[(26, 123, 128), (71, 234, 82), (23, 108, 34), (23, 23, 23), (42, 180, 19), (16, 58, 29), \
|
||||
(43, 44, 45), (17, 243, 82), (61, 85, 92)]
|
||||
"""
|
||||
return [get_pixel(pixel_data, width, x + j, y + i) for i in range(1, -1 - 1, -1)
|
||||
for j in range(-1, 1 + 1)]
|
||||
|
||||
|
||||
def separate_colour_channels(rgb_pixels: list) -> dict:
|
||||
"""Return a dictionary mapping the strings 'r', 'g', and 'b' to a list of the red, green, and
|
||||
blue colour channels, respectively, in rgb_pixels. The value lists should have the same order
|
||||
as rgb_pixels.
|
||||
|
||||
>>> example_pixels = create_example_pixel_data()
|
||||
>>> separate_colour_channels(example_pixels) == \
|
||||
{'r': [128, 35, 210, 32, 130, 43, 17, 61, 201, 23, 42, 16, 1, 26, 71, 23],\
|
||||
'g': [128, 50, 32, 208, 20, 44, 243, 85, 23, 23, 180, 58, 52, 123, 234, 108],\
|
||||
'b': [128, 65, 68, 43, 42, 45, 82, 92, 23, 23, 19, 29, 128, 128, 82, 34]}
|
||||
True
|
||||
"""
|
||||
|
||||
|
||||
def calculate_median_colour(colour_channels: dict) -> tuple:
|
||||
"""Return the median colour in colour_channels.
|
||||
|
||||
The median colour is the median value of each colour channel, type converted to an integer.
|
||||
|
||||
Hint: use median from the statistics module. Be careful because the call to median may return a
|
||||
float.
|
||||
|
||||
>>> example_pixels = create_example_pixel_data()
|
||||
>>> separated_colour_channels = separate_colour_channels(example_pixels)
|
||||
>>> calculate_median_colour(separated_colour_channels)
|
||||
(38, 71, 55)
|
||||
"""
|
||||
|
||||
|
||||
def apply_median_filter(pixel_data: list, image_width: int, image_height: int) -> list:
|
||||
"""Return a new list of pixels formed from the corresponding pixels in pixel_data (that
|
||||
represents an image with width image_width and height image_height), except with a median filter
|
||||
applied to the pixels.
|
||||
|
||||
The median filter should not process boundaries (i.e., the edges of the image), so the returned
|
||||
new list of pixels represents an image with width image_width - 2 and height image_height - 2.
|
||||
|
||||
>>> example_pixels = create_example_pixel_data()
|
||||
>>> apply_median_filter(example_pixels, 4, 4)
|
||||
[(43, 44, 45), (35, 58, 45), (42, 52, 45), (26, 108, 45)]
|
||||
"""
|
||||
windows = [get_pixel_window(pixel_data, image_width, x, y)
|
||||
for y in range(1, image_height - 1) for x in range(1, image_width - 1)]
|
||||
window_channels = [separate_colour_channels(window) for window in windows]
|
||||
return [calculate_median_colour(window_channel) for window_channel in window_channels]
|
||||
|
||||
|
||||
def run_median_filter_example(source: str, destination: str) -> None:
|
||||
"""Apply the median filter to an example image file at source and save the result in
|
||||
destination.
|
||||
"""
|
||||
original_pixel_data, original_width, original_height = a1_image.load_image(source)
|
||||
|
||||
new_pixel_data = apply_median_filter(original_pixel_data, original_width, original_height)
|
||||
|
||||
new_width = original_width - 2
|
||||
new_height = original_height - 2
|
||||
a1_image.save_image(destination, new_pixel_data, new_width, new_height)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
||||
# When you are ready to check your work with python_ta, uncomment the following lines.
|
||||
# (Delete the "#" and space before each line.)
|
||||
import python_ta
|
||||
python_ta.check_all(config={
|
||||
'extra-imports': ['statistics', 'a1_image'],
|
||||
'max-line-length': 100
|
||||
})
|
||||
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 381 KiB |
Executable
+5
@@ -0,0 +1,5 @@
|
||||
# References
|
||||
|
||||
Links to where the images came from.
|
||||
|
||||
1. [horses.png](https://i2.pickpik.com/photos/83/964/942/horses-embracing-affectionate-equestrian-thumb.jpg)
|
||||
+1
-1
@@ -14,7 +14,7 @@ In some function descriptions, we have written "You may ASSUME..." This means th
|
||||
when you are writing each function body, you only have to consider possible values
|
||||
for the parameters that satisfy these assumptions.
|
||||
|
||||
We have marked each place you need to write a doctest/code with the word
|
||||
We have marked each place you need to write a doctest/code with the word
|
||||
As you complete your work in this file, delete each TO-DO comment---this is a
|
||||
good habit to get into early! To check your work, you should run this file in
|
||||
the Python console and then call each function manually (you can also copy-and-paste)
|
||||
|
||||
+1
-1
@@ -9,4 +9,4 @@ python-ta
|
||||
plotly
|
||||
pygame
|
||||
|
||||
requests~=2.25.1
|
||||
requests
|
||||
|
||||
Reference in New Issue
Block a user