Programming Assignment: Image Processing

    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 just needs the pixel information at a pixel location whereas the latter requires the pixel information at a pixel location and its adjacent pixels. Some processed sample images can be found at here. Also, this page shows some sample images with blurry effect.

  2. In this program, you need to create two classes: Pixel and Image, as given below. You are not allowed to modify the instance variables and methods given in the two classes, but feel free to add additional methods as needed. A skeleton program can be found on the Canvas. Additionally, read this flow chart to help you understand the work flow for this assignment.

    class Pixel
    {
            //Private data fields (instance variables)
    	private int value; //This 32-int integer contains four 8-bit integers for opacity, red, green, and blue.
    	private int row;
    	private int col;
    
    	//If a pixel value is beyond the range 0-255, 
            //"normalize" it to the border value 0 or 255.
            //For example, use the class name to call the normalize() method: Pixel.normalize(-13) = 0. 
            //Pixel.normalize(278) = 255. 
    	public static int normalize(double p)
    	{
    		return (int)((p < 0)?0:((p > 255)?255:p));
    	}
    
        
    	//Below are public methods including constructors
    	
    	// ...
    }
    
    class Image
    {
    	private int rows;
    	private int cols;	
    	private Pixel [][] pixels;
    
    	//Constructor. arr is a 2D array of pixel values. r: rows; c: columns
    	public Image(int [][] arr, int r, int c)
    	{
    		//Create a 2D array of Pixel objects (of type Pixel)
    		pixels = new Pixel[r][c];		
    		rows = r;
    		cols = c;
    
    		//Use pixel values in arr to create Pixel objects at each location
    		for(int i = 0; i< r; i++)
    			for(int j = 0; j < c; j++)
    				pixels[i][j] = new Pixel(arr[i][j], i, j);
    	}
    	
    	//Below are other member methods
    	
    	// ....
    }
    
    In the Image class, 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 to a pixel in an image would be equivalent to calculating an average value of its 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:
    int [][] filter = {{1.0/9.0, 1.0/9.0, 1.0/9.0}, 
                       {1.0/9.0, 1.0/9.0, 1.0/9.0},
                       {1.0/9.0, 1.0/9.0, 1.0/9.0}
                      }; 
    for (int ii = -1; ii < 2; ii++)
      for (int jj = -1; jj < 2; jj++)
          p[i][j] += filter[ii+1][jj+1] * 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
    int [][] filter = {{-2, -1, 0}, 
                       {-1,  1, 0},
                       {0,   1, 2}
                      };
    for (int ii = -1; ii < 2; ii++)
      for (int jj = -1; jj < 2; jj++)
          p[i][j] += filter[ii+1][jj+1] * p[i + ii][j + jj];
      
      where ii and jj are offsets from the coordinates of the pixel being processed.
    

    The first three methods fall into the category of single pixel-based processing. The last two are filter-based processing and require a filter. Your program will prompt the user to specify an input image file, a processed output image file, a processing method to be carried out. In the ImageProc class, 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.
  3. Sample main method in the 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[0];
    	String outputFile = args[1];
    	String op = args[2];
    
    	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[0].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!");
      }
    }
    
  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!