This project was SO MUCH FUN. I had way too many ideas for just this week, so after I finish this post I’ll probably go back to making portraits.
At first I had only abstract concepts to work towards. Like gravity was definitely something I wanted to play around with. Unfortunately, I ran into issues with how ridiculously long it took to load the program every time I ran it…. there was no way I was going to be able to make anything that complicated. I was worried that I might not even finish the project! (every time I loaded the image it took on average 7 minutes to load. That’s like 8 an hour).
So, a good portion of my work on this project was figuring out how to make it run faster. After reading around on the reference page, I figured out if I used loadPixels, I could directly access the pixels[] array, and thus get the pixels information way faster. And.. hurray the code runs almost instantly!
I had a couple hours left, so I didn’t have room to be QUITE as ambitious as I wanted to be for this project (I was honestly going to turn in like 5 different codes as variations on a theme). Nonetheless, I think it turned out pretty well. I wanted to get a sort of old video game aesthetic going, so first I coded that up.
I played around with the size of the squares used to create the image, and the contrast between the darker parts (like the hair and lips) and the lighter parts (skin), but ultimately settled on the image above. Next, I (accidentally) made the stroke() color on the square pixels 10 below the fill color. This gave the image a more tile-esque look to it — closer to that old video game vibe I was going for. I decided to play around with that (intentionally this time), and settled on a white stroke. The reason being, is I wanted to print out the image on a huge poster, and have the affect of a bunch of separated squares, instead of a filled canvas.
At this point, I felt like the portrait was pretty good, but I wanted to do something a little bit more. Also, I just wanted to do something with code that is a bit out of my comfort zone… so I implemented objects into the portrait. I made each “tile” start at the bottom of the canvas, and slide upwards at varying speeds until it reached its correct location on the canvas.
I particularly like the effect that occurs around the bottom of the hair, as the dark pixels are sliding under the lighter pixels that have already reached their destination.
Click the in the image below if you want to see the program run again!
//Jonathan Perez
//Section B
//jdperez@andrew.cmu.edu
//Project 9
var img;
var rectSize = 9 //size of square pixels
var margin = 1 //gap between square pixels
function preload() {
img = loadImage("https://i.imgur.com/DjcKS6b.jpg");
}
function myTile(x, y, finalY, dy, color) {
this.x = x
this.y = y
this.finalY = finalY
this.dy = dy
this.color = color
this.draw = function() {
rectMode(CENTER);
stroke(255);
strokeWeight(margin+1) // creates a white border around the tiles for visual emphasis and irregularity
rect(this.x, this.y, rectSize, rectSize);
};
this.move = function() {
if(this.y > this.finalY) {
this.y = this.y - this.dy; //move the tile upwards
}
};
}
var myTile
var allTiles = [];
function setup() {
createCanvas(img.width, img.height);
background(200);
pixelDensity(1); //scales pixelDensity to image
image(img, 0, 0)
loadPixels(); //loads pixel array
for(y = 0; y < img.height; y += rectSize+margin) { //scans through one row at a time from top to bottom
for(x = 0; x < img.width; x += rectSize+margin) { //scans through all of the pixels in the row
var d = pixelDensity();
var off = (y * width + x) * d * 4; //location of the R value of x and y coordinate in pixel array
var bright = pixels[off];
if(bright < 30) { //checks current pixels brightness against current brightest pixel
allTiles.push(new myTile(x, height+(rectSize/2), y, random(2,4), 0));
} else if(bright < 40 & bright >= 30) {
allTiles.push(new myTile(x, height+(rectSize/2), y, random(2,4), 20));
} else if(bright < 60 & bright >= 40) {
allTiles.push(new myTile(x, height+(rectSize/2), y, random(2,4), 40));
} else if(bright < 70 & bright >= 60) {
allTiles.push(new myTile(x, height+(rectSize/2), y, random(2,4), 60));
} else if(bright < 80 & bright >= 70) {
allTiles.push(new myTile(x, height+(rectSize/2), y, random(2,4), 70));
} else if(bright < 90 & bright >= 80) {
allTiles.push(new myTile(x, height+(rectSize/2), y, random(2,4), 130));
} else if(bright < 100 & bright >= 90) {
allTiles.push(new myTile(x, height+(rectSize/2), y, random(2,4), 140));
} else if(bright < 110 & bright >= 100) {
allTiles.push(new myTile(x, height+(rectSize/2), y, random(2,4), 140));
} else if(bright < 120 & bright >= 110) {
allTiles.push(new myTile(x, height+(rectSize/2), y, random(2,4), 150));
} else if(bright < 130 & bright >= 120) {
allTiles.push(new myTile(x, height+(rectSize/2), y, random(2,4), 160));
} else if(bright < 140 & bright >= 110) { //switch from lower bound to upper bound
allTiles.push(new myTile(x, height+(rectSize/2), y, random(2,4), 175));
} else if(bright < 170 & bright >= 140) {
allTiles.push(new myTile(x, height+(rectSize/2), y, random(2,4), 210));
} else if(bright < 200 & bright >= 170) {
allTiles.push(new myTile(x, height+(rectSize/2), y, random(2,4), 220));
} else if(bright < 220 & bright >= 200) {
allTiles.push(new myTile(x, height+(rectSize/2), y, random(2,4), 230));
} else if(bright < 240 & bright >= 220) {
allTiles.push(new myTile(x, height+(rectSize/2), y, random(2,4), 250));
} else if(bright < 260 & bright >= 240) {
allTiles.push(new myTile(x, height+(rectSize/2), y, random(2,4), 255));
}
}
}
print(img.width, img.height)
}
function draw() {
scale(.65);
background(255);
for(i = 0; i < allTiles.length; i++) {
fill(allTiles[i].color);
allTiles[i].draw();
allTiles[i].move();
}
}
function mouseClicked() {
for(i = 0; i < allTiles.length; i++) {
allTiles[i].y = height + rectSize/2
}
}