Assignment 1: Problem Solving Example
First, an outline
Let's start with what we know:
- We know both the input and output:
- The input is a 2D array.
- The output is a 2D array.
- This suggests that, at least, the overarching method
that "does the job" should look like this:
public static double[][] strangeAverage (double[][] A)
{
// Make a new array B whose entries we compute,
// perhaps calling other methods as needed.
// return B;
}
- Does the 2D array have to be square?
- Each element of the second array depends on neighbors of
the corresponding element in the first.
- There does not seem to be any requirement that the array
be square.
- Here's one important observation:
- Each element of B can be computed independently of
any other element of B.
- This means we don't need to track anything through the iterations.
- Let's now add just a little more detail:
public static double[][] strangeAverage (double[][] A)
{
// We're doing to need space: same size as A. And note that
// the array could be rectangular.
double[][] B = new double [A.length][A[0].length];
// Since we are computing each element of B, at this time,
// we can fill in the outline of the iteration:
for (int i ... ) {
for (int j ...) {
// Let some method do the work ...
B[i][j] = findBoxAverageInSomeMethod (i, j)
}
}
return B;
}
- What do we need to pass into the method that'll do the average
for that particular element?
A1.3 Exercise:
Before reading ahead, think about what needs to go into the
method as parameters, and what the structure of that method
ought to be.
Next steps: the nitty gritty of the computation
Notice that once we know which cell we're doing the average for,
all we need is the location in the first array ... and of
course the array itself.
B[i][j] = boxAverage (A, i, j)
We'll call it
boxAverage().
It returns a single number (the neighbor average) that goes
into the i,j-th element of B.
What's nice is that, all we need now is the details of this
method:
- If we're at the i,j-th entry, how do we iterate through
its neighbors?
A1.4 Exercise:
Before reading ahead, try thinking through this.
- The key observation: the neighborhood box is itself like a mini
2D array.
- Thus, if we can set up an iteration through this
mini-array, we can sum up its values.
- Once we have the sum, we can compute the average.
- The idea can be outlined as follows:
static double boxAverage (double[][] A, int i, int j)
{
double sum = 0;
// One row behind: i-1. One row ahead: i+1
// Same thing for the column:
for (int m=i-1; m<=i+1; m++) {
for (int n=j-1; n<=j+1; n++) {
// m and n iterate through neighbors of i,j.
// Accumlate A[m][n] in the sum.
}
}
// Compute average and return.
}
- However, there are two issues to resolve:
- There are "corner" cases (all four corners, and the edge rows
and columns).
- The average will depend on how many values are counted
in the corner cases.
- How do we handle the special treatment for corner cases.
There are a couple of options:
- First handle the inner elements, then separately handle the
special cases.
- Try and integrate the special cases directly.
- We'll use the latter approach as follows:
static double boxAverage (double[][] A, int i, int j)
{
// ... initialize sum ..
double sum = 0;
// m and n iterate through potentially invalid locations
for (int m=i-1; m<=i+1; m++) {
for (int n=j-1; n<=j+1; n++) {
// Check if m and n are valid array locations
// If so, then include in sum
}
}
}
// Compute average and return ...
}
- With a little more detail ...
static double boxAverage (double[][] A, int i, int j)
{
double sum = 0;
// One row behind: i-1. One row ahead: i+1
// Same thing for the column:
for (int m=i-1; m<=i+1; m++) {
for (int n=j-1; n<=j+1; n++) {
if ( isValidElement (A,m,n) ) {
// Include this in the sum, and increment a counter
// to track the number values added sum.
}
}
}
// Compute average and return.
double avg = sum / count;
return avg;
}
- Luckily for us, it's easy to determine whether any two integers
m,n
are valid array locations (array indices).
A1.4 Exercise:
In
StrangeAverage2D.java
write up all the above code and complete the remaining parts
to make it work.
To test your code, use the following in
main()
public static void main (String[] argv)
{
// Test 1:
double[][] A = {
{0,1,0,1,0,1},
{1,0,1,0,1,0},
{0,1,0,1,0,1}
};
print (strangeAverage(A));
// Test 2:
double[][] A2 = {
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,16}
};
print (strangeAverage(A2));
}
static void print (double[][] A)
{
// Neater printing with printf:
for (int i=0; i<A.length; i++) {
for (int j=0; j<A[i].length; j++) {
System.out.printf (" %6.3f", A[i][j]);
}
System.out.println ();
}
}
You should get
0.500 0.500 0.500 0.500 0.500 0.500
0.500 0.444 0.556 0.444 0.556 0.500
0.500 0.500 0.500 0.500 0.500 0.500
3.500 4.000 5.000 5.500
5.500 6.000 7.000 7.500
9.500 10.000 11.000 11.500
11.500 12.000 13.000 13.500
An application
When your code is working, replace the code in
main()
with
// Display an image, unmodified:
ImageTool imTool = new ImageTool ();
int[][] pixels = imTool.imageFileToGreyPixels ("eniac.jpg");
imTool.showImage (pixels, "ENIAC");
// Our strange-average uses a double array, so copy over
// the integer pixels into a double 2D array:
double[][] A = convertToDouble (pixels);
// Our strange average:
double[][] B = strangeAverage (A);
// Convert back to an integer array, ENSURING that all
// values are between 0 and 255. (Truncate if out of these bounds).
int[][] pixels2 = convertToPixels (B);
// Display the resulting image:
imTool.showImage (pixels2, "ENIAC2");
A1.5 Exercise:
Write the additional code needed to make this work. What is the
effect on an image. You can use
eniac.jpg or your own black-and-white JPEG image.
You will also need ImageTool.java.
So, at last we know why the strange averaging method was used.
About this type of averaging:
- This is one of several such "image operators", small
computations that act on images.
- They are called convolutions in the image processing
literature.
- Variations of the basic procedure allows one to sharpen an
image, reduce noise, identify edges and so on.
Back to the assignment
© 2017, Rahul Simha