## Programming Assignment: Image Processing Part II

Instructions:

1. You are about to write Java programs to process real images. In general, there are two types of processing: single pixel based manipulation and filter-based manipulation. The former requires single pixel information whereas the latter requires the pixel information from adjacent pixels. Sample images can be found at here.

2. Expand your Java program for the image processing Part I you just completed by modifying and adding the following:

Your program should have three classes: Pixel, Image, and ImageProc. In class ImageProc, add a main method, a method extracting pixel values from a real input image, and a method writing a 2D array of pixel values into a real output image preferably in JPEG format. In class Image, add the following image processing methods:
1. grayscale()
2. invert()
3. addBars()
4. blur()
5. emboss()
In the blur() and emboss(), you need to pass a filter (3x3 array) that specifies weights from adjacent pixels. For the blur operation, the filter has weights like:
 1/9 1/9 1/9 1/9 1/9 1/9 1/9 1/9 1/9
Applying this filter would be equivalent to calculating an average value of eight neighbor pixels and the pixel being processed.
```p[i][j] = (p[i-1][j-1]+p[i-1][j]+p[i-1][j+1]+p[i][j-1]+p[i][j]+p[i][j+1]+p[i+1][j-1]+p[i+1][j]+p[i+1][j+1])/9
```
This can also be done easily by using double loops like:
```for (int ii = -1; ii < 2; ii++)
for (int jj = -1; jj < 2; jj++)
p[i][j] += 1.0/9.0 * p[i + ii][j + jj];

where ii and jj are offsets from the coordinates of the pixel being processed.
```
For the emboss(), the filter has weights like:
 -2 -1 0 -1 1 1 0 1 2
The first three methods fall into the category of single pixel based processing. The last two are filter-based processing and require a filter provided. Your program will prompt the user to choose which processing to be carried out.
3. To create a Buffered image object, use the following:
```    BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
```
For more details, refer to the official Java documentation.
4. Sample command line:

```//C:\Users\yzhang\ImageProc>javac ImageProc.java

//C:\Users\yzhang\ImageProc>java ImageProc model.jpg model_invert.jpg invert
//Input image file: model.jpg
//Output image file: model_invert.jpg
//What operation do you want to perform: invert
//Image Processing is complete!
```
5. Sample main method in ImageProc class (driver)

```//Driver Class for Image Processing
public class ImageProc{
public static void main(String args[])throws IOException{

//The user enters input, output image files and the type of operation through command line arguments
if(args.length == 0){
System.out.println("Missing input, output file names and the type of operation");
}

String inputFile = args;
String outputFile = args;
String op = args;

System.out.println("Input image file: " + inputFile);
System.out.println("Output image file: " + outputFile);
System.out.println("What operation do you want to perform: " + op);

//Extract pixel values from a real image file and return to a 2D integer array
int [][] arr = extract(inputFile);

//Create an Image object
Image image = new Image(arr, arr.length, arr.length);

//Operation menu
switch(op)
{
case "grayscale":
image.grayscale();
break;
case "invert":
image.invert();
break;
case "add_bars":
image.addBars();
break;
case "blur":
image.blur();
break;
case "emboss":
image.emboss();
break;
}

//Get pixel values (a 2D array of integers) from the Image object
arr = image.getPixels();

//Create a real output image file with pixel values from the Image object
write(arr, outputFile);

System.out.println("Image Processing is complete!");
}

//More member methods here ...
}
```