讲解Digital Image、辅导Java编程语言、辅导IDE留学生、Java讲解
- 首页 >> Java编程Fundamentals of Programming in Java
Exercises 2
Digital Image Processor
Marks available: 100
Date issued: 01/10/2018
Deadline: 1200, 19/11/2018
Submission instructions
Submit your work by the deadline above. The accepted submission format is zip. Submit only .java source
files in your archive. Do NOT submit .class files. All of your Java files must be in the same zip file. Please
do not submit Eclipse (or other IDE) projects.
Do not output anything to the console unless explicitly asked to.
Your Java file must have the following declaration at the top of it.
package com.bham.pij.exercises.e2a;
Since all of your methods will be in the same file, you will only need this precise package declaration and
no others.
In each of these exercises, you are not restricted to only creating the required methods. If you want to,
you can create others. However, you must create at least the required methods.
Do not import any libraries other than those already imported. Do not use code from other libraries in
any other way. You must implement your methods using only the built-in arrays. Do not copy code from
elsewhere that uses other techniques. If in doubt, please ask Ian.
Introduction
For this set of exercises you will complete some methods in an image processing tool. You do not need
to create the tool itself. That is provided for you on Canvas as the file ImageProcessor.java. You are
simply completing some methods so that the functionality is fully present.
1
Digital images
A digital image is essentially a 2D array of color values. Each color element of the 2D array is called a
‘pixel’ (short for ‘picture element’). Each pixel has a color. This color can be represented in a number of
ways. One of the most common ways is to represent each pixel color as a combination of the colors red
(R), green (G) and blue (B). This is the RGB color model. Using this model, each pixel usually has three
bytes of data associated with it: one for red, one for green and one for blue. (Another byte of data called
the ‘transparency’ is also usually associated with each pixel but we aren’t going to worry about that value).
If using an integer type, we can see that one byte of data per color per pixel leads to a range of 0 to 255
different values. If the value of that color (red, green or blue) is set to zero it means that none of that color
is represented in that pixel. If it is set to 255 it means that the maximum level of that color is represented
in that pixel. Since each pixel has a value for each of the RGB values, this means that we can mix the
colors together to get the colors we want.
If we set all three RGB values to zero we obtain the color black. If we set them all to 255 we get the color
white. If we set them all to the same value, somewhere between 0 and 255, we get gray. If we set them
to different values we then get other colors. There are many online tools for playing around with colors in
this way and I recommend doing that if you are unfamiliar with this topic.
Image filters
Image processing involves amending the color values of the pixels in an image in some way, or creating a
new image from an old one having processed the old one in some way. In these set of exercises you will be
largely applying filters1
to images (but there are some slightly different techniques to be used - described
below).
A filter is a 2D array of values. The filter is usually a small array, for example 3 rows by 3 columns (3x3).
The values in the filter are used to modify each pixel in the source image in a specific way, to be described
below. Each single pixel in the source image is modified by the entire filter.
The color value of each pixel to be filtered is computed as follows.
Consider a filter matrix f of dimension 3x3:
x00 x01 x02
x10 x11 x12
x20 x21 x22
Consider a digital image img, of dimension 8x82
, represented as a matrix of colors:
c00 c01 c02 . . . c07
c10 c11 c12 . . . c17
c20 c21 c22 . . . c27
c70 c71 c72 . . . c77
1Also called kernals.
2This is just an example. This would be an incredibly small image.
2
As an example, consider pixel c22. The color of pixel c22 after applying the filter is computed as follows:
(1)
c
new
22 = x00 × c11 + x01 × c12 + x02 × c13
+ x10 × c21 + x11 × c22 + x12 × c23
+ x20 × c31 + x21 × c32 + x22 × c33
Note that this is not a regular matrix multiplication. It is a matrix convolution.
Essentially, we consider the filter as being placed centrally on the pixel for which we want to compute the
new value. Thus, the element [1,1] in the filter is positioned ‘over’ the pixel to be computed.
This computation is applied to all of the pixels in the image. This means that the filter is ‘moved’ across the
image from the top-left corner, pixel by pixel. Thus every new pixel value is the sum of nine multiplications.
Consider the identity filter. The identity filter leaves the source image unchanged. The 3x3 identity filter
is shown below:
0 0 0
0 1 0
0 0 0
If you consider this filter, and the equation for the computation of the new pixel value shown above, you
will see that this matrix will leave the color of the pixel unchanged. Only the element [1,1] will contribute
to the result (since all other terms will be zero), and element [1,1] is positioned over the original pixel
value.
Edge cases
How do we compute the value of pixel [0,0]? If we position the filter over this pixel, it means that parts of
the filter will not be over the image since the filter element [1,1] will be placed over the target pixel. This
means, for example, that filter element [0,0] will not be over the image.
This is literally an ‘edge case’. What should we do? Well, you can read up about the various techniques
that are used to overcome this issue, but the solution used for the tool you are working on is a very simple
one and is explained below under ‘Implementation details’.
Implementation details
As you will see below under the specific exercises below, you need to implement four methods. The methods
you will implement are largely about producing a new color array from an original color array. For the
filtering techniques, this requires the specification of a filter. For sepia and grayscale, the process is slightly
different, as shown below.
Dealing with the edge problem
For the applyFilter() method, the Color pixel array that will be passed to your method will have been
augmented as described here.
3
To overcome the edge case issue described above, the array that your method receives has been increased
in size compared to the original image array. A one-pixel border (set to the color white) has been added
around the image. This is so that you can apply your filter without having to worry about the edge of
the image. This does mean that, at the edges of your filtered image, there will be a slightly odd color for
each pixel because it will have been mixed with varying degrees of white (apart from for the identity filter).
Thus, an image of dimensions n×m pixels will be passed to your method as an array of n+2×m+2 pixels.
However, the array returned by your applyFilter() method must be the same size as the original image,
so you do not include this border in your result. In the example above, your returned array would be be
n × m.
The Color class
Spend some time looking at the Java Color class API. You don’t need to know too much about it but
please note the following.
Although we described the RGB values above as being in the range [0,255], you will actually specify them
using double values in the range [0,1]. These are exactly equivalent. The value 0 maps to 0 and 1 maps
to 255.
To compute a Color value you must compute the red, green and blue components. Note that this means
that equation (1) must be used three times: once for each component to create a new red, green and blue
value.
To create a new Color value from three double values called red, green and blue you do the following:
Color color = new Color(red,green,blue,1.0);
Note that the final parameter is the transparency value and you should always set that to 1.0.
One other thing to consider: when you compute the new red, green and blue values that you want for a
pixel, you must ensure that the values are still in the range [0,1] otherwise you will cause an Exception.
Sepia
The creation of a sepia image requires a different process. It is not filtered, as such. For sepia, each pixel’s
color value is simply changed according to the following formula:
red (2) new = redoriginal × 0.393 + greenoriginal × 0.769 + blueoriginal × 0.189
green (3) new = redoriginal × 0.349 + greenoriginal × 0.686 + blueoriginal × 0.168
blue (4) new = redoriginal × 0.272 + greenoriginal × 0.534 + blueoriginal × 0.131
Grayscale
The creation of a grayscale image also requires a different process that has more in common with the
process for a sepia image than with filtering.
4
For grayscale, each pixel’s color value is simply changed according to the following formula:
rednew = greennew = bluenew = (redoriginal+greenoriginal+blueoriginal)÷3 (5)
The Exercises
Exercise 2a: createFilter() [10 marks]
For this task you should create a method with the following signature:
public float[][] createFilter(String filterType)
As you can see, this method receives a String as a parameter and returns a 2D array of floats.
The parameter will have one of the following values:
{"IDENTITY","BLUR", "SHARPEN", "EMBOSS", "EDGE"}
The method should return a 3x3 array containing the appropriate values for the parameter. These are:
Identity {{0,0,0},{0,1,0},{0,0,0}}
Blur {{0.0625f,0.125f,0.0625f},{0.125f,0.25f,0.125f},{0.0625f,0.125f,0.0625f}}
Sharpen {{0,-1,0},{-1,5,-1},{0,-1,0}}
Edge {{-1,-1,-1},{-1,8,-1},{-1,-1,-1}}
Emboss {{-2,-1,0},{-1,0,1},{0,1,2}}
Therefore, for example, for the Identity filter, your method must return a 2D array of dimensions 3X3 with
all elements set to zero except for element [1][1] which will have the value 1.
For these filters you must use these exact values. Do not use other values that you have looked up elsewhere.
Of course, if you want to experiment with other filters, you can set those values to anything you wish.
Just make sure you implement the ones required here.
Exercise 2b: applyFilter() [40 marks]
For this task you must create a method with the following signature.
public Color[][] applyFilter(Color[][] pixels, float[][] filter)
This method receives as parameters one of the filters (created by your method from Exercise 2a) and a 2D
array of Color values. Remember that the pixel array that your method receives will have been augmented
by a one-pixel border, as described above. Your method will apply the filter to the Color array and return
a 2D Color array minus the one-pixel border.
5
Exercise 2c: applySepia() [10 marks]
For this task you must create a method with the following signature.
public Color[][] applySepia(Color[][] pixels)
The Color array passed to this method will not have the one-pixel border. To create the sepia image you
must apply the equations (2), (3) and (4) to the colors in the input array,
Exercise 2d: applyGrayscale() [10 marks]
For this task you must create a method with the following signature.
public Color[][] applyGrayscale(Color[][] pixels)
The Color array passed to this method will not have the one-pixel border. To create the grayscale image
you must apply the equation (5) to the colors in the input array,