Randy Dodgen Lin - CS 315H 9/5/08 Prog1 - Image Manipulation Overview -------- This first assignment deals with image processing. The primary task is to implement a number of predetermined 'image effects,' such as reflecting the image across either axis or removing a particular color channel. Secondary is the more creative venture of applying the newly implemented effects (though relatively simple) to create pleasing results. The user interface and lower-level image handling are both handled by the provided code - only image effects need to be implemented. The primary goals for this submission are reliable transformations that don't make unnecessary assumptions about image content/dimensions, and of course implementation of all required transformations. There is also intent to implement at least one optional neighborhood filter as described in Section 4 of the handout. Design ------ One observation from the list of required filters was that the first six were near identical - differing only in which color (or set of colors) is to be removed. Noting that, finding a way to avoid duplicating that behavior each time was important. As noted in the comments within Transformations.java, it was a simple matter of creating a base class for this behavior and marking it abstract. Of course, this is not a surprising or unconventional solution - the difficulty was in making sure that doing so would not break the provided code (which attempts to create an instance of anything deriving from ImageEffect on startup). There was otherwise nothing noteworthy regarding the color-masking effects. The black and white effect required some thought. First of all, this implementation takes a more technical meaning of 'black and white' - whereas it is common to refer to 'black and white television' for example, such an image contains many shades of gray (known as grayscale). Given this interpretation, a B&W filter was a simple matter of thresholding the average of the 3 color components. In this way, white maps to white (average value of 255 is greater than threshold) while a darker color (such as (64, 10, 10) as an arbitrary example) can be consider closer to black. It is unfortunate that this threshold cannot be configured - this point will later be expanded upon. A grayscale effect is also included. This is due to later clarification as to the intended meaning of 'black and white' in the handout. It operates simply by replacing each color component of each pixel with the average of the three original color components. The horizontal and vertical reflections are an application of basic reversal of an array. One must simply examine the first half of the array and swap with its mirrored counterpart (in an array of length 100, 0 would map to 99 due to a zero base - the equation is thus (size - index - 1) ). The threshold effect is implemented in a base class, in the same way as the color masking effects. Since there is no means to request user input to specify a threshold value, it was instead decided to provide two subclasses differing only in this value - 'Threshold (127)' and 'Threshold (64).' This is the same limitation faced in implementing the B&W filter. Edge detection operates by examining for each pixel its neighbors both 1 and 2 pixels to the right and 1 and 2 pixels down (this leaves two rows and two columns to be excluded). If the average color value difference or a single color value difference exceeds a preset threshold (different threshold for average and single) the result pixel is white. Otherwise, black. Note that there is also an "experimental" edge detect algorithm (consider it unfinished), which for brevity will only be documented in the comments within Transformations.java. It should be noted that these algorithms may have been influenced by prior experience in a high-school course which covered image processing. Beyond original goals, a de-noise effect was also implemented. It operates simply by replacing each pixel with the median of a 3x3 neighborhood. Completed Assignment -------------------- All goals were met for this project, including the planned bonus (Edge Detection) and an additional de-noise effect. The code works for most any sane input as originally desired - things would certainly break given a non-rectangular array of pixels (possible - given that the input is an 'array of arrays' rather than a multidimensional array as seen in C and relatives) though this could not happen as long as the calling test UI is behaving properly. Such checking was thus deemed extraneous. The 'Shrink' effect is the only one uniquely sensitive to weird image dimensions. A possible bug exists in the case that the input image has either one or both dimensions equal to 1. Since the result array dimensions are calculated by dividing the original dimensions by 2, dividing a dimension of 1 doesn't make sense. This case has not been tested, however one can speculate. The result array would have length 0 for at least one of its dimensions, and the way that such a value would be treated by the provided code is unknown. It was decided to not handle this case specially on the grounds that leaving the offending dimesnion(s) unchanged would (technically) violate the requirements of the transform, and also that fixing potential issues in the provided code is outside the scope of the assignment. The decision would have been different if there was an already defined means to report an error condition to the user interface. The 'Edge Detect' bonus effect is very image dependant and is also in need of tweaking of the threshold values. For example, it fails on the Flower and Neuron images due to blur (more gradual change -> neighborhood not big enough). The Landscape image works surprisingly well. Results vary of course based on threshold values. The 'experimental' version gives better results in some cases. Each effect was tested on at least one test image (incl. those provided) and verified visually. The images used for testing (as well as any transformed images deemed sufficiently pretty) are available for viewing and download at: http://www.cs.utexas.edu/~randy/