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

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 Lab11.pde. It contains the stubs of several methods. Save it directly to your folder with your other lab files and open it in Processing.You will need the Video library installed.

This program displays and allows you to change images. There is no printing in this lab, only graphical output. This program uses key strokes to execute different functions. The display image is based on an "original image". Some functions will change the display image, while others will change both the display and original image. The default image is a picture of Albion College. You can download that or choose an image on you local computer to reduce network download time.

The keystrokes functions avilable (see the keyPressed function)are as follows:

f
Read an image from a file and set it to by the original and display images
v
Capture an image from the video camera and set it to by the original and display images
u
Change the original image so that it contains a grayscale image (red=green=blue) where each pixel is a random value
o
Reset the display image to the original image
b
Change the display image to the blue channel of the display image
g
Change the display image to the green channel of the display image
r
Change the display image to the red channel of the display image
y
Change the display image to the gray representation of the display image
H
Change the display image so that it is flipped horizontally (each row is reveresed)
V
Change the display image so that it is flipped vertically (each column is reveresed)
R
Change the display image so that it is rotated counter-clockwise 90 degrees
c
Change the original image so that it is cropped to the selected rectangle. Pressing, then dragging the mouse will define a rectangle with (x1,y1) as the starting corner and (x2,y2) as the opposite corner. It may be that x1 < x2 or that x2 < x1. Similarly, y1 < y2 or y2 < y1.
N
Change the display image so that it has a random value added to it that is at most plus or minus 1/2 sqrt(pixel value)
p
Change the display image so that it has an artistic rendering of the display image

You can also use a non-offensive image of your choice.

Code


//import processing.video.*;
//Capture video;

PImage original;
PImage display;
int scale = 1;
int x1, y1, x2, y2;
boolean selecting = false;


public void  settings() {
  size(500, 500);
}


public void setup() {
  surface.setResizable(true);
  //video = new Capture(this, 320, 240);
  //video.start();
  original = loadImage("https://www.albionpleiad.com/wp-content/uploads/2015/03/Albion-College-640x381.jpg"); 
  display = original;
  rescale();
}


// determining a scaling factor so that the image fits into a displayable window on the screen
void rescale() {
  scale = 1;
  while (original.width/scale > displayWidth || original.height/scale > displayHeight)
    scale *= 2;
  surface.setSize(original.width/scale, original.height/scale);
}


// read an image from the camera when available
//void captureEvent(Capture video) {
//  video.read();
//}


public void draw() {
  background(128);
  image(display, 0, 0, display.width/scale, display.height/scale);
  // draw selection rectangle
  if (selecting) {
    stroke(255, 0, 0);
    noFill();
    rectMode(CORNERS);
    rect(x1, y1, x2, y2);
  }
}


public void mousePressed() {
  x1 = mouseX;
  y1 = mouseY;
  x2 = mouseX;
  y2 = mouseY;
  selecting = true;
}


public void mouseDragged() {
  if (!selecting) return;
  x2 = mouseX;
  y2 = mouseY;
}


public void keyPressed() {
  if (key=='f') { // read a file
    selectInput("Select and image file:", "readImage");
    display = original;
    rescale();
  }
  //if (key=='v') {
  //  original = videoCapture(); // video capture
  //  display = original;
  //  rescale();
  //}
  if (key=='o') {
    display = original; // reset to original image
  }
  if (key=='b') {
    display = blueChannel(display);
  }
  if (key=='g') {
    display = greenChannel(display);
  }
  if (key=='r') {
    display = redChannel(display);
  }
  if (key=='y') {
    display = grayScale(display);
  }
  if (key=='n') {
    display = negate(display); // crop to selection
  }
  if (key=='H') {
    display = horizontalFlip(display); // horizontal flip
  }
  if (key=='V') {
    display = verticalFlip(display); // vertical flip
  }
  if (key=='R') {
    display = rotateCCW(display); // rotate counter clockwise
  }
  if (key=='c') {
    original = crop(display); // crop to selection
    display = original;
    rescale();
    selecting = false;
  }
  if (key=='u') {
    original = uniformNoise(500); // uniform noise
    display = original;
    rescale();
  }
  if (key=='N') {
    display = noisify(display); // add random noise
  }
  if (key=='p') {
    display = pointillism(display); // add random noise
  }
}


//PImage videoCapture() {
//  // snap picture
//  PGraphics pg = createGraphics(320, 240);
//  pg.beginDraw();
//  pg.image(video, 0, 0);
//  pg.endDraw();
//  // copy to an image
//  PImage img = createImage(320, 240, RGB);
//  img.loadPixels(); // ESSENTIAL to do this first!
//  for (int t = 0; t < img.pixels.length; t++) {
//    img.pixels[t] = pg.pixels[t];
//  }
//  img.updatePixels(); // ESSENTIAL to do this last!
//  return img;
//}


public void readImage(File selection) {
  if (selection == null) 
    return;
  original=loadImage(selection.getAbsolutePath());
  display = original;
  rescale();
}


PImage pointillism(PImage srcImg) {
  srcImg.loadPixels();
  PImage img = createImage(srcImg.width, srcImg.height, RGB);
  img.loadPixels(); // ESSENTIAL to do this first!
  for (int t = 0; t < img.pixels.length; t++) {
    int row = t/img.width;
    int col = t%img.width;
    if (row%5 == 0 && col%5 == 0) {
      img.pixels[t] = srcImg.pixels[t];
      if ((row < img.height-1) && (col < img.width-1)) img.pixels[t+img.width+1] = srcImg.pixels[t];
      if ((row < img.height-2) && (col < img.width-2)) img.pixels[t+2*(img.width+1)] = srcImg.pixels[t];
      if ((row < img.height-3) && (col < img.width-3)) img.pixels[t+3*(img.width+1)] = srcImg.pixels[t];
    }
  }
  img.updatePixels(); // ESSENTIAL to do this last!
  return img;
}


PImage blueChannel(PImage srcImg) {
  srcImg.loadPixels();
  PImage img = createImage(srcImg.width, srcImg.height, RGB);
  img.loadPixels(); // ESSENTIAL to do this first!
  for (int t = 0; t < img.pixels.length; t++) {
    int blueValue = blueValue(srcImg.pixels[t]);
    img.pixels[t] = blueValue;
  }
  img.updatePixels(); // ESSENTIAL to do this last!
  return img;
}


PImage greenChannel(PImage srcImg) {
  srcImg.loadPixels();
  PImage img = createImage(srcImg.width, srcImg.height, RGB);
  img.loadPixels(); // ESSENTIAL to do this first!
  for (int t = 0; t < img.pixels.length; t++) {
    int greenValue = greenValue(srcImg.pixels[t]);
    img.pixels[t] = greenValue << 8;
  }
  img.updatePixels(); // ESSENTIAL to do this last!
  return img;
}


PImage redChannel(PImage srcImg) {
  srcImg.loadPixels();
  PImage img = createImage(srcImg.width, srcImg.height, RGB);
  img.loadPixels(); // ESSENTIAL to do this first!
  for (int t = 0; t < img.pixels.length; t++) {
    int redValue = redValue(srcImg.pixels[t]);
    img.pixels[t] = redValue << 16;
  }
  img.updatePixels(); // ESSENTIAL to do this last!
  return img;
}


PImage grayScale(PImage srcImg) {
  srcImg.loadPixels();
  PImage img = createImage(srcImg.width, srcImg.height, RGB);
  img.loadPixels(); // ESSENTIAL to do this first!
  for (int t = 0; t < img.pixels.length; t++) {
    int grayValue = grayValue(srcImg.pixels[t]);
    img.pixels[t] = colorRGB(grayValue,grayValue,grayValue);
  }
  img.updatePixels(); // ESSENTIAL to do this last!
  return img;
}


// invert color by subtracting each RGB component from 255
PImage negate(PImage srcImg) {
  return null;
}

// flip horizontally about a vertical axis
PImage horizontalFlip(PImage srcImg) {
  return null;
}


// flip vertically about a horizontal axis
PImage verticalFlip(PImage srcImg) {
  return null;
}


// rotate counter-clockwise
PImage rotateCCW(PImage srcImg) {
  return null;
}


// crop to selection
PImage crop(PImage srcImg) {
  return null;
}


// n by n  image with uniform noise
PImage uniformNoise(int n) {
  return null;
}

// noisify srcImg by replacing each pixel
// with a value that is randomly +/- sqrt(pixel value)/2
// clip values to stay in the 0-255 range
PImage noisify(PImage srcImg) {
  return null;
}


// Each pixel (picture element) is a color, which
// represents an RGB triple, plus an alpha (transparency)
// The components are packed into a 32 bit pattern
// The notation aRGB is often used
//  aaaaaaaa rrrrrrrr gggggggg bbbbbbbb

// << shifts a bit pattern left 
// >> shifts a signed bit pattern right 
// >>> shifts an unsigned bit pattern right 
// & is a bit-wise logical AND - note x&1 = x, x&0 = 0
// | is a bit-wise logical OR - note x|0 = x, x|1 = 1
// ^ is a bit-wise logical XOR (eXclusive OR)
// A B A&B A|B A^B
// 0 0  0   0   0
// 0 1  0   1   1
// 1 0  0   1   1
// 1 1  1   1   0


// hexadecimal patterns are simple ways of expressing binary pattern
// hex binary dec
// 0   0000   0
// 1   0001
// ...
// 9   1001   9
// a   1010   10
// ...
// f   1111   15


//extract the blue channel of the color c
int blueValue(int c) {
  //return c%256; // naive
  // use a bit mask
  return c&0x000000ff;
}


//extract the green channel of the color c
int greenValue(int c) {
  // use a bit mask and then bit shift the pattern right 8 bits
  return (c&0x0000ff00)>>8;
}

//extract the red channel of the color c
int redValue(int c) {
  // use a bit mask and then bit shift the pattern right 8 bits
  return (c&0x00ff0000)>>16;
}


// comvert a pixel value to a grayscale
// https://en.wikipedia.org/wiki/Grayscale
int grayValue(int c) {
  int y = (int) (0.2126*redValue(c) + 0.7152*greenValue(c) + 0.0722*blueValue(c));
  return y;
}


// combine red, green, and blue channels
int colorRGB(int r, int g, int b) {
  return (r&0x000000ff)<<16 | (g&0x000000ff)<<8 | (b&0x000000ff);
}

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

Have Fun!


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