CS 171 & 171L Introduction to Computer Science I & Lab Fall 2017 

Lab 11: Images

Goals and Objectives

The main goal this lab is for you to get a more practice with multidimensional array storage structures in the context of images.

Task

You will complete methods that perform some basic image transformation operations.

Introductions

Introduce yourself to your lab partner(s). Do you have a fun experience using photoshop or other image processing programs to create useful or funny pictures? Talk about this with your lab partner.

Download the lab

Download the source file ImageDisplay.java. It contains the stubs of several static methods. Save it directly to your folder with your other lab files and open it in jGRASP. Complete the methods as shown below. After you complete each method, demonstrate it to your instructor. Change the driver/navigator roles after each method.

Note the code can display .png or .jpg images. There are several image options for the 2016 presidential election. You can "vote" by selecting an image of on e of the candidates on the Michigan ballot. You can also use a non-offensive image of your choice.


// David A. Reimann
// Example  code for using Processing from java and jGRASP

// Note you must also set the classpath to locate Processing's core.jar file


// imports always needed

import processing.core.*; 
import java.util.Random; 


// lines is the name of this file and program
// must be stored in a file named "lines.java"
// Change this name to suit your needs
public class ImageDisplay extends PApplet {
   static Random random;
  
// lines must also be changed below
   static public void main(String args[]) {
      random = new Random();
      PApplet.main(new String[] {"ImageDisplay" });  // change lines to match class name
   }
   
   static PImage original;
   PImage display;
   
   public void  settings() {
      size(1000,500); 
   }
    
  // typical setup method
   public void setup() {
      surface.setResizable(true);
      // change for a more interesting non-offensive image.
      original = loadImage("http://zeta.albion.edu/~dreimann/dave2010f.jpg");
      surface.setSize(original.width,original.height); // resize if needed
      System.out.printf("%d %d\n", original.width, original.height);
      display = original;
      //display = blueChannel(original);
   //noLoop();
   }
  
  
  // typical draw method
   public void draw() {  
      background(0);
   // float scale = (1+sin(frameCount/10.f))/2;
   //image(img, 0,0,width*scale,height);
      image(display, 0,0,display.width,display.height);
   }
   
   
   static PImage redChannel(PImage img) {
      int w1 = img.width;
      int h1 = img.height;
      PImage img2 = new PImage(w1, h1);
      img.loadPixels();
      img2.loadPixels();
      for (int i = 0;  i < img.pixels.length;  i++) {
         //img2.pixels[i] = rgb(Red(img.pixels[i]),0,0);
         img2.pixels[i] = img.pixels[i]&0xff0000;
      }
      img2.updatePixels();
      return img2;
   }
   
   
   static PImage greenChannel(PImage img) {
      int w1 = img.width;
      int h1 = img.height;
      PImage img2 = new PImage(w1, h1);
      img.loadPixels();
      img2.loadPixels();
      for (int i = 0;  i < img.pixels.length;  i++) {
         //img2.pixels[i] = rgb(Red(img.pixels[i]),0,0);
         img2.pixels[i] = img.pixels[i]&0xff00;
      }
      img2.updatePixels();
      return img2;
   }
   
   
   static PImage blueChannel(PImage img) {
      int w1 = img.width;
      int h1 = img.height;
      PImage img2 = new PImage(w1, h1);
      img.loadPixels();
      img2.loadPixels();
      for (int i = 0;  i < img.pixels.length;  i++) {
         //img2.pixels[i] = rgb(Red(img.pixels[i]),0,0);
         img2.pixels[i] = img.pixels[i]&0xff;
      }
      img2.updatePixels();
      return img2;
   }
   
   
   static PImage negate(PImage img) {
      int w1 = img.width;
      int h1 = img.height;
      PImage img2 = new PImage(w1, h1);
      img.loadPixels();
      img2.loadPixels();
      for (int i = 0;  i < img.pixels.length;  i++) {
         int r = 255-Red(img.pixels[i]);
         int g = 255-Green(img.pixels[i]);
         int b = 255-Blue(img.pixels[i]);
         img2.pixels[i] = rgb(r,g,b);
      }
      img2.updatePixels();
      return img2;
   }
   
   
   // Grayscale: G = 0.2126*Red + 0.7152*Green + 0.0722*Blue
   static PImage grayScale(PImage img) {
      int w1 = img.width;
      int h1 = img.height;
      PImage img2 = new PImage(w1, h1);
      img.loadPixels();
      img2.loadPixels();
      for (int i = 0;  i < img.pixels.length;  i++) {
         int r = Red(img.pixels[i]);
         int g = Green(img.pixels[i]);
         int b = Blue(img.pixels[i]);
         int v = (int)(0.2126*r + 0.7152*g + 0.0722*b);
         img2.pixels[i] = rgb(v,v,v);
      }
      img2.updatePixels();
      return img2;
   }
   
   //  for a 1D position t
   // a row r, column c
   // image width w
   // image height h
   // t = r*w+c
   // r = t/w (integer division, no remainder)
   // c = t%w
   
   static PImage transpose(PImage img) {
      int w1 = img.width;
      int h1 = img.height;
      int w2 = h1;
      int h2 = w1;
      PImage img2 = new PImage(w2, h2);
      img.loadPixels();
      img2.loadPixels();
      for (int t1 = 0;  t1 < img.pixels.length;  t1++) {
         int r1 = t1/w1;
         int c1 = t1%w1;
         int r2 = c1;
         int c2 = r1;
         int t2 = r2*w2+c2;
         img2.pixels[t2] = img.pixels[t1];
      }
      img2.updatePixels();
      return img2;
   }   
   
   
   static PImage Pascal(int n) {
      int w1 = n;
      int h1 = n;
      
      // Paascal's triangle mod 2
      int p[][] = new int[n][];
      for (int i = 0;  i < n;  i++) {
         p[i] = new int[i+1];
         p[i][0] = 1;
         p[i][i] = 1;
         for (int j = 1;  j < i;  j++) {
            p[i][j] = (p[i-1][j-1] + p[i-1][j])%2;
         
         }
      }
      
      PImage img2 = new PImage(w1, h1);
      img2.loadPixels();
      for (int t1 = 0;  t1 < img2.pixels.length;  t1++) {
         int r1 = t1/w1;
         int c1 = t1%w1;
         if (c1 < p[r1].length) {
            int v = 255*p[r1][c1];
            img2.pixels[t1] = rgb(v,v,v);
         }
         else {
            img2.pixels[t1] = 0;
         }
      }
      img2.updatePixels();
      return img2;
   }
  

   public static PImage uniformNoise(int n) {
      int w1 = n;
      int h1 = n;
      PImage img1 = new PImage(w1, h1);
      img1.loadPixels();
      for (int r1 = 0;  r1 < h1;  r1++) {
         for (int c1 = 0;  c1 < w1;  c1++) { 
            int t1 = r1*w1+c1;
            int r = random.nextInt(256);
            int g = random.nextInt(256);
            int b = random.nextInt(256);
            img1.pixels[t1] = rgb(r,g,b);
         }
      }
      img1.updatePixels();
      return img1;
   }
   
   
   
  // flip horizontally about a vertical axis
   public static PImage horizontalFlip(PImage img) {
      System.out.println("Horizontal Flip");
      // do this without calls to other rotation, transpose, or flipping functions
      return img;
   }
  
  
  // flip vertically about a horizontal axis
   public static PImage verticalFlip(PImage img) {
      System.out.println("Vertical Flip");
      return img;
      // do this without calls to other rotation, transpose, or flipping functions
   }
  
  
  // rotate counter-clockwise
   public static PImage rotateLeft(PImage img) {
      System.out.println("Rotate Left");
      // do this without calls to other rotation, transpose, or flipping functions
      
      return img;
   }
  
  
  // rotate clockwise
   public static PImage rotateRight(PImage img) {
      System.out.println("Rotate Right");
      // do this without calls to other rotation, transpose, or flipping functions
      return img;
   }
  
  // 8x8 checkerboard (use two contrasting colors of your choice)
  // place in an n x n image
   public static PImage checkerboard(int n) {
      System.out.println("checkerboard");
      return original;
   }
  
  // Hermann grid illusion
  // http://www.michaelbach.de/ot/lum_herGrid/index.html
  // place in an n x n image
   public static PImage HermannGrid(int n) {
      System.out.println("Hermann grid illusion");
      return original;
   }
  
  // Kitaoka bulge illusion
  // place in an n x n image
  // http://www.ritsumei.ac.jp/~akitaoka/Bulge02.jpg
   public static PImage KitaokaBulge(int n) {
      System.out.println("Kitaoka bulge illusion");
      return original;
   }
  
  // Cafe wall illusion
  // place in an n x n image
  // http://mathworld.wolfram.com/CafeWallIllusion.html
   public static PImage cafeWall(int n) {
      System.out.println("Cafe wall illusion");
      return original;
   }
  
  
  // Wolfram Rule 30 pattern
  // http://mathworld.wolfram.com/Rule30.html
  // https://en.wikipedia.org/wiki/Rule_30
  // start with a random top row
   public static PImage wolframRule30(int n) {
     // randomly assign values to the top row
     // wrap rule horizontally
      System.out.println("Wolfram Rule 30");
      return original;
   }
   
         
   static int Red(int c) {
      return (c&0xFF0000)>>16;
   }
   
   
   static int Green(int c) {
      return (c&0xFF00)>>8;
   }
   
   
   static int Blue(int c) {
      return c&0xFF;
   }
   
   
   static int rgb(int r, int g, int b) {
      return (r<<16) | (g<<8) | b;
   }    
  
  
   public void keyPressed() {
      if (key == 'o' || key == 'O') {
         display = original;
      }
      if (key == 'n' || key == 'N') {
         display = negate(display);
      }
      if (key == 'y' || key == 'Y') {
         display = grayScale(display);
      }
      if (key == 'g' || key == 'G') {
         display = greenChannel(display);
      }
      if (key == 'b' || key == 'B') {
         display = blueChannel(display);
      }
      if (key == 'r' || key == 'R') {
         display = redChannel(display);
      }
      if (key == 't' || key == 'T') {
         display = transpose(display);
      }
      if (key == 'p' || key == 'P') {
         display = Pascal(1000);
      } 
      if (key == 'u' || key == 'U') {
         display = uniformNoise(1000);
      } 
      
      if (key == 'h' || key == 'H') {
         display = horizontalFlip(display);
      }
      if (key == 'v' || key == 'V') {
         display = verticalFlip(display);
      }
      if (key == 'l' || key == 'L') {
         display = rotateLeft(display);
      }
      if (key == 'k' || key == 'k') {
         display = rotateRight(display);
      }
      if (key == 'c' || key == 'C') {
         display = checkerboard(800);
      } 
      
      if (key == '1') {
         display = HermannGrid(800);
      } 
      
      if (key == '2') {
         display = cafeWall(800);
      } 
      
      if (key == '3') {
         display = KitaokaBulge(800);
      } 
      if (key == 'w' || key == 'W') {
         display = wolframRule30(1000);
      } 
   }
}

Getting Started

In this lab, you will practice writing loops. You should start off with s1 driving and s2 navigating. Complete the methods as indicated. You should change driver/navigator roles after each method is completed.

There are several independent methods in this lab. These are listed in roughly easiest to hardest, but if you get stuck on a part, you should consider trying the next step.

Send me your .java file at the end of lab. You should try and complete any methods you did not finish in class.

Have Fun!


Copyright © 2017, David A. Reimann. All rights reserved.