""" CS146 Image Analysis Examples Adapted from: https://ethicalcs.github.io/#manipulators """ import PIL.Image import urllib.request from io import BytesIO # Python has rejected the certificate used for the CS dept. server so we bypass some of those checks import ssl ssl._create_default_https_context = ssl._create_unverified_context BASE_URL = "https://www.cs.middlebury.edu/~mlinderman/courses/cs146/f24/classes/" class Pixel: """Single RGB pixel Public Attributes: red (int): Red color component as integer in range [0,255] green (int): Green color component as integer in range [0,255] blue (int): Blue color component as integer in range [0,255] """ def __init__(self, red=0, green=0, blue=0): """Create a new RGB pixel Args: red (int, optional): Red color component. Defaults to 0. green (int, optional): Green color component. Defaults to 0. blue (int, optional): Blue color component. Defaults to 0. """ self.red = red self.green = green self.blue = blue class Image: """Image class providing a simple interface to a PIL image Public attributes: None """ def __init__(self, url): """Load an image from a URL Args: url: Image URL, e.g,, http://.... """ with urllib.request.urlopen(url) as url: self.img = PIL.Image.open(BytesIO(url.read())) self.img_pix = self.img.load() self.width = self.img.size[0] self.height = self.img.size[1] def get_width(self): """Return image width in pixels""" return self.width def get_height(self): """Return image height in pixels""" return self.height def get_pixel(self, row, col): """Return Pixel object at location starting at (0,0) in upper left corner Args: row: Integer row index col: Integer column index Returns: Pixel object with RGB values """ pix = self.img_pix[col, row] return Pixel(pix[0], pix[1], pix[2]) def set_pixel(self, row, col, pixel): """Set pixel at location starting at (0,0) in upper left corner Args: row: Integer row index col: Integer column index pixel: New pixel value with red, green and blue components """ self.img_pix[col, row] = (pixel.red, pixel.green, pixel.blue) def save_image(self, filename): """Save image to local file Args: filename: String filename with image extension, e.g., "result.jpg" """ try: self.img.save(filename) except IOError: print(f"Cannot save image to {filename}") def show(self): """Display image in a new window""" self.img.show() def red_shift(in_file, out_file): """Red shift image, saving result to local file Args: in_file: String with URL to original image out_file: String filename with image extension to save modified image """ # Load image from URL img = Image(in_file) # TODO: Iterate over all pixels, shifting red component by 100 # Save modified image to local file img.save_image(out_file) # Example testing code for `red_shift` function. # red_shift(BASE_URL + "linderman.jpg", "linderman_red.jpg") # Horizontal blur filter window (declared here to keep examples together) WINDOW = 4 def blur(in_file, out_file): """Apply horizontal blur filter to image, saving result to local file Args: in_file: String with URL to original image out_file: String filename with image extension to save modified image """ # Load image from URL img = Image(in_file) for row in range(img.get_height()): # We will ignore right-most pixels in the image (where blur filter would extend # beyond the image boundary) for col in range(img.get_width()-WINDOW+1): # TODO: Delete pass and implement horizontal blur filter pass # Save modified image to local file img.save_image(out_file) # Example testing code for `blur` function. # blur(BASE_URL + "linderman.jpg", "linderman_blur.jpg") def average(in_files, out_file): """Average a set of images, saving result to local file Args: in_files: List of string URLs for original images out_file: String filename with image extension to save modified image """ # Load original images as Image objects from URLs imgs = [] for url in in_files: imgs.append(Image(url)) # Update first image with average of all images first_img = imgs[0] # TODO: Iterate over all pixels, averaging corresponding pixels in all images # Save modified image to local file first_img.save_image(out_file) # Example testing code for `average` function. # Experiment with different (sub)sets of faces # # Face files adapted from Peck E. et al. and faceresearch.org # face_files = ["alex.jpg", "alexander.jpg", "alfred.jpg", "ambroz.jpg", "arnold.jpg"] # # face_files = ["zelmira.jpg","zita.jpg", "zlata.jpg", "zlatica.jpg", "zora.jpg"] # # # Transform the list of face files into a list of URLs # face_urls = [] # for face in face_files: # face_urls.append(BASE_URL + "faces/" + face) # # average(face_urls, "average_face.jpg")