xxxxxxxxxx
245
/* Lab 3: Image Processing
* Gillian Smith
* CS 1004 @ WPI
* Last Updated: 02-02-23
*/
//controls whether the image is being displayed, initialized so that it shows on load
var SHOW_IMAGE = true;
//control veriables for filters
var DITHER = false;
var IMPRESSIONIST = false;
var EDGES = false;
var GLITCH = false;
//variable for whether we should just clear the screen
var CLEAR_SCREEN = false;
//store the image!
var santacruz;
function preload() {
santacruz = loadImage("natural-bridges.png");
}
function setup() {
//manually set the canvas size to be the same as the image dimensions
createCanvas(650, 429);
//make a 1-to-1 correspondence between pixel in image and on screen
pixelDensity(1);
//initial drawing settings
background(255);
noStroke();
}
function draw() {
//clear screen just sets the background color to white
if (CLEAR_SCREEN == true) {
background(255);
CLEAR_SCREEN = false;
}
//"impressionist" places differently angled lines as
//"brush strokes" that share a color with the underlying image
else if (IMPRESSIONIST == true) {
background(255); //set background color to white
santacruz.loadPixels(); //update pixels in the image's pixels list
//iterate over every 5 pixels in the image width and height
for (var x = 0; x < width; x += 5) {
for (var y = 0; y < height; y += 5) {
//santacruz.pixels is a 1-dimensional list with length width*height
//convert to 1D from 2D with 4 * (x + width*y)
//colAtPixel is the color at the x,y coordinate
var ind = 4 * (x + width * y);
var rp = santacruz.pixels[ind];
var gp = santacruz.pixels[ind + 1];
var bp = santacruz.pixels[ind + 2];
//draw a thick line with random direction that's the same color
//as the underlying pixel
stroke(rp, gp, bp);
noFill();
strokeWeight(6);
if (random(1) > 0.5) {
//randomly choose between \ and /
line(x - 5, y - 5, x + 5, y + 5);
} else {
line(x - 5, y + 5, x + 5, y - 5);
}
}
}
IMPRESSIONIST = false;
}
//"dither" applies four-step dithering to the image,
// based on the brightness of the pixel value
else if (DITHER == true) {
santacruz.loadPixels(); //update pixels in the image's pixels list
background(255); //set background to white
noStroke(); //turn off outlining
//when dithering, we convert a color image to completely black+white
// and use texture to replace brightness; thus, we need to
// iterate over every 2 pixels because the texture we're replacing
// the image's pixels with is 2x2 pixels
for (var x = 0; x < width; x += 2) {
for (var y = 0; y < height; y += 2) {
var ind = 4 * (x + width * y);
var rp = santacruz.pixels[ind];
var gp = santacruz.pixels[ind + 1];
var bp = santacruz.pixels[ind + 2];
var colAtPixel = color(rp, gp, bp);
//brightness(color) returns a value equivalent
// to the brightness of the color, by default on [0,255]
// storing in a variable named 'l' for "luminance"
var l = brightness(colAtPixel);
if (l > 75) {
//upper quadrant of brightness, just draw a single
// dark grey rectangle
fill(50);
rect(x, y, 1, 1);
} else if (l > 50) {
//second quadrant of brightness, draw two rectangles
// on diagonal with each other
fill(50);
rect(x, y, 1, 1);
rect(x + 1, y + 1, 1, 1);
} else if (l > 25) {
//third quadrant, draw three dark grey rectangles in the 2x2 space
fill(50);
rect(x, y, 1, 1);
rect(x + 1, y + 1, 1, 1);
rect(x + 1, y, 1, 1);
} else {
//fourth quadrant, fill the whole 2x2 space
fill(50);
rect(x, y, 2, 2);
}
}
}
DITHER = false;
}
//this detects edges by convolving the original image with a 3x3 kernel
//tutorial/explainer on convolution here: https://setosa.io/ev/image-kernels/
else if (EDGES == true) {
santacruz.loadPixels();
background(255);
noStroke();
//the kernel is a 3x3 matrix, represented here as a list of lists
//this kernel is a rudimentary edge detector/outliner
kernel = [
[-1, -1, -1],
[-1, 8, -1],
[-1, -1, -1],
];
//because convolving an image with a kernel requires passing the kernel
//fully across the image (with the center on every pixel)
//we need to start at pixel 1 in row/col, and end before the last row/col,
//otherwise the kernel will run off the edge of the image
for (var x = 1; x < width - 1; x++) {
for (var y = 1; y < height - 1; y++) {
sum = 0; //build a sum of the brightness values modified by the kernel
for (var i = 0; i < kernel.length; i++) {
for (var j = 0; j < kernel[i].length; j++) {
//don't freak out by the long scary line, let's break this apart
// x + width*y is the CENTER pixel at the kernel
// we need to look at all the pixels that the kernel overlaps
// i,j counts through the indices in the kernel
// i-1, j-1 will always be the offset from the center of
// the kernel, ranging on [-1, 0, 1]
// so x + (i-1) is the current x value in the image plus
// the offset needed for which pixel to look at on
// this step of convolution
// so we need to take the running sum, and add the kernel-
// modified brightness value to it
var curr_x = x + (i - 1);
var curr_y = y + (j - 1);
var ind = 4 * (curr_x + width * curr_y);
var rp = santacruz.pixels[ind];
var gp = santacruz.pixels[ind + 1];
var bp = santacruz.pixels[ind + 2];
var l = brightness(color(rp, gp, bp));
sum = sum + kernel[i][j] * l;
}
}
fill(map(sum, 0, 100, 0, 255)); //converting to greyscale from color,
//so fill with the brightness
// converted from (0,100) -> (0,255)
rect(x, y, 1, 1); //draw a tiny rectangle
}
}
EDGES = false;
}
// GLITCH is artistic expression time! inspired by glitch art,
// let's convert the image into something highly stylized
// traditionally, glitch art involves *actual* error, typically
// induced by either hardware or image encoding mistakes
// I'm faking it here to get a similar aesthetic
// get some inspiration here: https://www.joelatimer.com/glitch-art-101-mostly-everything-you-need-to-know-about-glitch-art/
else if (GLITCH == true) {
santacruz.loadPixels();
background(255);
noStroke();
for (var x = 0; x < width; x++) {
for (var y = 0; y < height; y++) {
var modX = x + int(random(-5, 5));
var modY = y + int(random(-5, 5));
if (modX < 0 || modX >= width) {
modX = x;
}
if (modY < 0 || modY >= height) {
modY = y;
}
var ind = 4 * (modX + width * modY);
var rp = santacruz.pixels[ind];
var gp = santacruz.pixels[ind + 1];
var bp = santacruz.pixels[ind + 2];
fill(gp, rp, bp, 5);
rect(x, y, random(2, 50), random(2, 50));
}
}
GLITCH = false;
}
//finally, we have the option to just show the image as-is
else if (SHOW_IMAGE == true) {
image(santacruz, 0, 0);
SHOW_IMAGE = false;
}
}
//this should look familiar from lab 2 -- using the keyPressed() function
// to set which filter to show based on which key is pressed
// note that this time we're *not* toggling the value, but setting it to true
// the filter code in draw() turns it off after it executes once
function keyPressed() {
if (key == '1') {
IMPRESSIONIST = true;
}
if (key == '2') {
DITHER = true;
}
if (key == '3') {
EDGES = true;
}
if (key == '4') {
GLITCH = true;
}
if (key == '5') {
SHOW_IMAGE = true;
}
if (key == 'c') {
CLEAR_SCREEN = true;
}
}