Complex Pixmap Transformations
Images are stored by computers in a variety of formats, such as gif, jpg, tiff, and png. These formats differ in how faithfully they represent the original picture, how well they can be compressed to reduce the space each image takes up, or how well they can be copied from one type of computer to another. However, no matter what format the image is stored in, it can always be represented of as a mapping of (x, y) pixel position to a color (the range of colors may be restricted to values of grey or just black and white). Thus, for the remainder of this project, we will refer to all formats of digital images as pixmaps.
This programming project involves manipulating pixmaps by transforming each color in the original pixmap using the same algorithm. Your program will be able to read in gif, jpg, and png image formats, and perform several operations on these images including smoothing and embossing.
To start, download the program files using Eclipse as assignments/03_pixmap.
For each of the problems below, you will complete the execute method
of the appropriate class that, given a Pixmap parameter
representing an image, changes it using the methods given below based on the described algorithm and returns nothing. Changes to the given image will be reflected within the running program as they are made. To test your solution, right-click on the file
named Main.java within your project and select Run -> Java
Application from the menu that appears. This will cause a Java program
to appear that allows you to open, transform, and save images. To load a different
image to test, click on the Open button and select an image from
the images folder there.
A Pixmap object can be used to access or set
the color of an individual pixel and to access or set the total size of the
image. Methods that you will use include:
- getSize(): returns the Dimension of the entire image
- getColor(int x, int y): returns the Color of the pixel at (x, y)
- setSize(int width, int height): changes the Dimension of the entire image to the given width and height
- setColor(int x, int y, Color value): sets the color of the pixel in the Pixmap to the specified color
Note, you can only change the image displayed on the screen by calling one of the last two methods described above (the ones that start with set). If you make changes to a copy of the Pixmap, they will not be visible on the screen.
Complete the following image effects.
- Mirror effects
An image can be reflected along an axis (usually horizontal, vertical, or diagonal) to create the effect of rotating the image 90, 180, or 270 degrees, resectively.
- Complete the
executemethod of classMirrorVertically.Transform the image such that it looks like it has been reflected along a vertical axis through the middle of an image. This "flips" the image so that it is facing the opposite direction (i.e., left instead of right). Note, if the image is symmetrical about this axis, it will not appear to have changed. Algorithmically, this is the same as reversing the contents of each row.
The example on the right shows this effect applied to the dinosaur image given at the top of this page.
- Complete the
executemethod of classMirrorHorizontally.Transform the image such that it looks like it has been reflected along a horizontal axis through the middle of an image. This "flips" the image so that it is upside down from the original image. Note, if the image is symmetrical about this axis, it will not appear to have changed. Algorithmically, this is the same as reversing the contents of each column.
The example on the right shows this effect applied to the dinosaur image given at the top of this page.
- Refactor your code
Create a superclass, such that
MirrorHorizontallyandMirrorVerticallyare subclasses and that they contain no duplicated code. Instead everything in common has been factored out into the superclass you create. - Complete the
- Emboss effect
Complete the
executemethod in the classEmboss.Transform the image such that it looks like it has been indented into paper (embossed) by greying out most of the image except where there are areas of high contrast. This effect is accomplished by shifting the image, inverting it, and then adding that version to the original. The amount by which you shift the image determines how deeply indented it appears. The fact that most of the image is similarly colored means that it will be mostly grey when you are finished. Edges, areas of high contrast, will stand out more. To shift an image, simply move its pixels slightly (for example, over 2 and down 2). To add two images together, add the individual color values together and then take the average (i.e., divide by two).
- Expand effect
Complete the
executemethod in the class Expand.The method already prompts the user for the scale factors and correctly grows the pixmap to the new, expanded, size by expanding it horizontally, vertically, or in both directions using the setSize method. Your task is to fill in the now expanded image with a copy of the colors from the original image. To do this, take each single color value and copy it so that it represents a rectangle of color in the expanded image whose width and height is the scale factors given by the user.
In the figure below, an image is shown partially expanded by three vertically, and by two horizontally. If you are not careful about the order in which copy the colors, you will destroy the original image by changing its colors before you have copied them into the correct new position in the expanded image. Thus, to start, you might want to create a separate pixmap that is a copy of the original.
- Blur and EdgeDetect effect
Image processing operations use the current pixel and its neighboring pixels to calculate its new color value. In these operations, you must make a copy of the original image from which to gather your neighborhoods so that the effects do not cascade as you compute a new value for each pixel. For example, the diagrams below represent part of a grey scale image: a 3-neighborhood and a 5-neighborhood of the middle pixel whose grey-scale value is 28. You do not need to worry about neighborhoods with an even width or height.
Suppose we wanted to write an image processing operation to replace the middle pixel's color by the median of the values in its neighborhood. The nine values in the 3-neighborhood are (10 10 12 25 25 28 28 32 32). The median, or middle, value is 25 --- there are four values above 25 and four values below 25. The values in the 5-neighborhood are (10 10 10 10 10 10 12 12 12 18 18 18 25 25 25 25 25 25 32 32 32 32 32 32 32), and again the median value is 25 because there are 12 values above and 12 values below 25. The easiest way to find the median of a list of values is to sort them and take the middle element.
Applying a 3 x 3 median-filter to the image on the left below results in the image on the right (these images look better on the screen than they do on paper).


What happens at the edges, though? The source pixel will not have neighbors on at least one side, so it will not have a "complete" neighborhood. Rather than dealing with this problem, you can just leave all the edge pixels values unmodified.
- Complete the
executemethod of classBlur
The color of a pixel is calculated by sampling the neighboring elements in the pixmap and taking the the average, not the median as shown in the example above. Applying this operation should give your image a soft, slightly impressionist feel.
- Complete the
executemethod of classEdgeDetect
The color of a pixel is determined by scaling the pixel values to use the largest values possible. If max and min are the maximum and minimum color values in the neighborhood, the scaled value of a pixel should be calculated as follows:
newColorValue = (oldColorValue - min) * maxPossiblePixelValue / (max - min)
Applying this operation adds contrast to an image, especially around the edges within the image.
- Refactor your code
Create a superclass, such that
BlurandEdgeDetectare subclasses and that they contain no duplicated code. Instead everything in common has been factored out into the superclass you create. - Complete the
- Your Choice
Complete the
executemethod in the class Student and replace the string it passes to its superclass that is displayed on the button to name the effect you have created. You may use a "buggy" effect you created while trying to do one of the other problems. You may try to do a more advanced effect like those from Photoshop or some of these student effects. You may try to do something abstract that changes colors based on a mathematical function (like fading in the shape of a circle). In any case, you must document what you tried to do so that it is not simply random chance. - Submit an image that you created using your program with your code. In class, we will display the images and may vote on the best ones using a variety of criteria.
Submitting Your Work
When you are satisfied you have completed the problems above, you should electronically submit your project through Eclipse. A submission is not considered complete unless it includes all the Java code for the project (both what you have written and the code provided when you downloaded the project) and a README file as described here.