[+] Add a1 files

This commit is contained in:
Hykilpikonna
2021-09-17 15:19:56 -04:00
parent 08a1648a77
commit c1b09b7f4c
9 changed files with 526 additions and 2 deletions
+98
View File
@@ -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}
+49
View File
@@ -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)
+109
View File
@@ -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'])
+115
View File
@@ -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
# })
+148
View File
@@ -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
})
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 381 KiB

+5
View File
@@ -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
View File
@@ -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
View File
@@ -9,4 +9,4 @@ python-ta
plotly
pygame
requests~=2.25.1
requests