Extension : Extension 1.2: Image Processor

Authors:

  • Anne Bracy
  • Ron Cytron
  • Ken Goldman
  • Logan Sorentino

Background

Pixels

The word pixel stands for Picture Element. A pixel is a small part of a picture. Pixels are the little dots that make up LCD screens. When you see a low-resolution picture that is grainy, the grains you’re seeing are the pixels.

Representing color in Java

Pixels are made up of 3 colors: red, green, and blue (hence the term RGB). The color of a pixel is made up of a combination of the intensities of each of red, green, and blue components. In computing it’s common for intensities range from 0 (meaning none of that color is present) to 255 (meaning as much as possible of that color is present). (The reason for 255 is the maximum is because computer use binary numbers. The “why” isn’t important not, but keep in mind that color values go from 0 to 255)

You create a new color for a pixel with the code:

new Color(redValue, greenValue, blueValue)

where redValue is the intensity (an integer between 0 and 255) of red, greenValue is the intensity of green, and blueValue is the intensity of blue.

For example, you get the color black with new Color (0,0,0) (0 intensity for all colors). You get red with new Color (255,0,0) (highest intensity for red, 0 intensity for green and blue).

Filters

This work involves writing a number of filters that are applied to images to achieve a given result. There are two kinds of methods that you complete, and each is described below.

Single image intensity filters

Simple uniform intensity filters are created with code that looks like this:

public static int someName(int pixelComponent) {
	return  // <- Your code goes after the word return and uses the variable named pixelComponent
}

This someName thing is referred to as a method. This will be explored more later, but for now you can think of it as describing the how to do some computation. I.e., the method for a computation. Methods like this take in a single pixel component intensity value: an integer between 0 and 255 inclusively. In this case you can use the variable pixelComponent, which will already contain a number. Special variables like pixelComponent that are used in methods are called parameters. The method is obligated to return an intensity value as their result.

These methods are used by the course software as shown below:

Color Intensity

  1. A Color object is broken into its red, green, and blue components.
  2. Each component is passed to your someName method, and the returned value of method is retained.
  3. The three results are combined into a new Color object for you.

In other words, the someName method is used as a filter on each of a Color’s three components. The someName method is unaware of which component it is processing: it treats each equally.

The darker method is already completed for you:

public static int darker(int pixelComponent) {
	return pixelComponent/2;
}

Notice how it uses pixelComponent and returns the result of dividing pixelComponent by 2. So each color of every pixel will have half of it’s original intensity (it’ll get a lot darker), but the overall colors stay the same.

Project: Image Processing Methods

  1. open the imageprocessor package. Find and open the Filters class. This is the place you will add all your code. Notice that file contains several lines with comments that say FIXME. You’ll place your work on these lines. Go ahead and run it as-is. You should see a window pop up with some images preloaded.

  2. Try the darker filter, which was already completed for you. It should produce an image in the Target window that resembles the image in the source1 window, but is a bit darker.

  3. Try the combine filter. It has also been implemented but its effects may seem a bit strange. You will soon implement a smarter version of this kind of a filter.

  4. The other methods are not yet implemented, but you are free to try them.

  • You can test work visually by opening and running the ImageProcessor class.
  • By the way, you can drag images between the icon panel at the top and the working panels in the middle, or vice versa, so that you can manipulate other images than the ones that are preloaded.
  • You can also load your own images by clicking on the icon that resembles a plus sign.

Directions

Right click on the ImageProcessorTest class, and Run As and then JUnit Test. It’ll open a new window pane labelled JUnit:

  • On the left you should see a list with names like darkerTest. Some have green check marks while others have a blue x.
    • Each check mark or x represents a test (some may test many things though).
    • Green check marks indicate successful tests (the code worked in the way the test expected)
    • The blue x’s indicate tests that did not work as expected.
    • Every time you complete a piece of code correctly, one of the tests will pass, and a small green x will appear beside it.
  • There’s also an indicator of the number of errors and failures as well as a bar indicating the success or failure. It’s all red now, but once all of the tests pass it’ll be green. (This extension is only about part of the tests, so it won’t need to turn green yet)
  • Pay attention to the number of failures listed (after Failures: ). Your goal is to get this to decrease.

Now open the Filters class and begin your work as described below.

  1. As you make changes re-run the Unit test after each change. This will help you gauge your progress. You can simply click on the Play button on the JUnit tab.

  2. Use use mathematical expressions for each of the following (Do NOT use if statements). Each can be done by changing the words following the word return in each method.

  3. Intensity filters

    1. Complete the method called copy, so that each provided intensity value is copied exactly from the source to the target panel. Hint: This is a very simple method.

    2. Complete the method called negative that will produce the negative image by inverting the intensity of each component. For example, if the parameter value is 0, you should return 255. If the parameter value is 1, you should return 254, and so on.

    3. Complete the posterize method that will reduce the number of possible colors in an image. For a given color component, your method will choose between two intensities, 0 or 255, which correspond to that color component being turned off or on completely. Since each color has three components (red, green, and blue), you will end up with an image that has only 8 different colors. Remember that you are not allowed to use conditionals (if) statements or ternary operations for this part of the lab! Hint If you want a hint, highlight the next lines to reveal it.
      Recall that color components are in the range 0-255. Also, recall that if you divide an int by another int, the result number will be truncated. For example, 130 / 128 is 1, but 125 / 128 is 0.

  4. Complete the composite method, which will combine the images in the two source panels by averaging their components. This method accepts two parameters, which are color components from the two source panels.

Color filters

These filters are a little more complex. You are given the entire Color object and can make decisions based on all three parts separately. Consequently you need to return a new Color object. This can do a different class of changes than the simple intensity filters. They look like:

public static Color someName(Color c) {
	return Color.black;  // FIXME
}

In this case the parameter is an entire Color object. In the example the variable is called c, and you can get the individual components of c by using c.getRed(), c.getGreen(), and c.getBlue().

If the darker had been designed with this approach it could look like:

public static Color darkerColor(Color c) {
	int r = c.getRed()/2;
	int g = c.getGreen()/2;
	int b = c.getBlue()/2;
	return new Color(r,g,b);
}

Notice that this does essentially the same work to the intensities, but it changes all three at once and replaces an entire pixel. Notice the word new is used to make a new Color.

  • Continue to use no conditional execution for this part: only arithmetic expressions as you have learned them in Module 1.
  • To create a new Color, you must specify its red, green, and blue components in that order, as shown in the darkerColor
  • Notice how you can get the individual components of a Color via the get style methods.

Create and test methods (whose parameters and return values are Colors) with the following specifications.

  1. Complete the method brighter that will return a brighter version of the original Color.
    • The Color class conveniently provides a method named brighter() that returns a brighter color. If c is a Color, then c.brighter() is a brighter version of c’s color.

  2. Complete the method grayscale that will make a grayscale image from a color image. To do this, use the Color parameter to produce a new Color where all the components (red, green, and blue) have the same value. Hint If you want a hint, highlight the next lines to reveal it.
    Try averaging the three components of the original color to pick the components of the new color.

More Color filters

OK, now you can use ?: statements!

  1. Complete the method blackAndWhite that produces a black and white image by returning a Color that is either black or white, depending upon the overall intensity of the original color.

    For your return value, use the constant Color.BLACK or Color.WHITE. It’s up to you how to decide when a color’s components, taken as a whole, should be considered black or white.

  2. Complete the method combineBrighter that combines two images by choosing for each pixel the color from the image that has the brighter pixel in that location. To determine which pixel is brighter, compare the sums of the red, green, and blue components of the two pixels. Since the ProcessorTool will run your method for every pair of pixels, the resulting image will have some pixels from the first image and some from the second image.