# image_processor.py # YOUR NAME(S) AND NETID(S) HERE # DATE COMPLETED HERE """This module provides all of the image processing operations that are called whenever you press a button. All other controller functionality (loading files, etc.) is provided in imager.py""" import image_array # GLOBAL CONSTANTS GRAY = 0 SEPIA = 1 class ImageProcessor(object): """Instance is a collection of image transforms Instance variables: original (ImageArray): The original state of the image. This variable is set only by __init__ and never changes. current (ImageArray): The current state of the image. This variable is updated (either by modifying the pixels in the array or by replacing it with a new array) by all the image processing operations. """ def __init__(self, array): """Set up an ImageProcessor for the given image. Pre: array is an ImageArray Attribute is a direct reference to . However, attribute is a copy of this ImageArray.""" self.original = array self.current = array.copy() def restore(self): """Restore the original image""" self.current = self.original.copy() def invert(self): """Invert the current image, replacing each element with its color complement""" r = 0 while r < self.current.rows: c = 0 while c < self.current.cols: rgb = self.current.get_pixel(r, c) red = 255 - rgb[0] green = 255 - rgb[1] blue = 255 - rgb[2] rgb = (red,green,blue) # New pixel value self.current.set_pixel(r, c, rgb) c = c + 1 # Remember to increment r = r + 1 # Remember to increment def transpose(self): """Transpose the current image Follow this plan: Create a new ImageArray ia, which has no data (it is an empty image), but which has the number of rows and columns swapped from their current values in self.current Store the transpose of the self.current in ia, using self.current's get_pixel function and ia's set_pixel function. Assign ia to self.current. The transposed image will be drawn on the screen immediately afterwards.""" ia = image_array.ImageArray(rows=self.current.cols,cols=self.current.rows) r = 0 # Invariant: rows 0..r-1 have been copied to ia[.., 0..r-1] while r < ia.rows: c = 0 # Invariant: elements [r..0..c-1] have been copied to ia[0..c-1, r] while c < ia.cols: ia.set_pixel(r, c, self.current.get_pixel(c, r)) c = c + 1 # Remember to increment r = r + 1 # Remember to increment # Replace the image self.current = ia def horizReflect(self): """Reflect the current image around the horizontal middle.""" h = 0 k = self.current.cols-1 # Invariant: cols 0..h-1 and k+1.. have been inverted while h < k: r = 0 # Invariant: pixels 0..r-1 of cols h and k have been swapped while r < self.current.rows: self.current.swap_pixels(r, h, r, k) r = r + 1 # Remember to increment # Must change two variables to satisfy invariant h = h + 1 # Move h forward k = k - 1 # Move k backward def rotateLeft(self): """Rotate the image 90 degrees counterclockwise.""" self.transpose() self.vertReflect() def rotateRight(self): """Rotate the image 90 degrees clockwise.""" self.transpose() self.horizReflect() def vertReflect(self): """ Reflect the current image around the vertical middle.""" pass def jail(self): """Put jail bars on the current image: Put 3-pixel-wide horizontal bars across top and bottom, Put 4-pixel vertical bars down left and right, and Put n 4-pixel vertical bars inside, where n is (number of columns - 4) / 50. The n+2 vertical bars should be as evenly spaced as possible.""" pass def _drawHBar(self, row, pixel): """Helper function for jail. Pre: row an int, 0 <= row, row+3 < self.current.rows pixel is a tuple of 3 values in 0..255. Draw a horizontal 3-pixel-wide bar at row of the current image. So the bar is at pixels row, row+1, and row+2. The bar uses the color given by pixel.""" # Invariant: pixels self.current[row..row+2][0..col-1] are color pixel col = 0 while col < self.current.cols: self.current.set_pixel(row, col, pixel) self.current.set_pixel(row+1, col, pixel) self.current.set_pixel(row+2, col, pixel) col = col + 1 # Remember to increment def monochromify(self, color): """Convert the current image to monochrome according to parameter color. Pre: color == GRAY or color == SEPIA If color is `GRAY`, then remove all color from the image by setting the three color components of each pixel to that pixel's overall brightness, defined as 0.3 * red + 0.6 * green + 0.1 * blue. If color is `SEPIA`, set red to brightness, set green to 0.6 * brightness and blue to 0.4 * brightness.""" pass def vignette(self): """Simulate vignetting (corner darkening) characteristic of antique lenses. Darken each pixel in the image by multiplying each color component by 1 - (d / hfD)^2 where d is the distance from the pixel to the center of the image and hfD (for half diagonal) is the distance from the center of the image to any of the corners.""" pass def blur(self): """Change the current image so that every pixel that is not on one of the four edges of the image is replaced with the average of its current value and the current values of its eight neighboring pixels. When implementing this function: FIRST, make a copy of the image. Use the method ImageArray.copy() THEN transform the current image using the values in the copy. Thus, the average will be the average of values in the "original" current image, NOT of values that have already been blurred.""" pass def bilateral(self, threshold): """Change the current image so that every pixel that is not on one of the four edges of the image is replaced with the average of its current value and the current values of a subset of the eight neighboring pixels. Pixels are included in the average if the maximum difference (max absolute value difference in red, green, and blue) between the neighbor and the center pixel is less than or equal to . Precondition: threshold >= 0. When implementing this function: FIRST, make a copy of the image. Use the method ImageArray.copy() THEN transform the current image using the values in the copy. Thus, the average will be the average of values in the "original" current image, NOT of values that have already been averaged.""" pass