Files
CSC110/assignments/a1/a1_part4.py
T
Hykilpikonna 01d2f7cd1f [F] Fix a1 p4
2021-09-19 22:04:34 -04:00

129 lines
4.5 KiB
Python
Executable File

"""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.
* Assumed that value is positive
>>> example_pixel = (100, 12, 155)
>>> maximize_channels(example_pixel, 128)
(128, 128, 155)
"""
return tuple([max(chan, value) for chan in old_pixel])
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.
* Assumed that denominators are positive integers.
>>> example_pixel = (100, 12, 155)
>>> divide_channels(example_pixel, 2)
(50, 6, 77)
"""
return tuple([chan // denominator for chan in old_pixel])
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.
"""
return [divide_channels(pixel, random.choice([1] * k + [256])) for pixel in pixel_data]
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.
"""
return [maximize_channels(pixel, random.choice([0] * k + [255])) for pixel in pixel_data]
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.
"""
pixel_data = add_pepper(pixel_data, k)
pixel_data = add_salt(pixel_data, k)
return pixel_data
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()
run_salt_and_pepper_example('images/horses.png', 'images/noisy-horses.png', 16)
# 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
})