/** * ASCII Video * by Ben Fry. * * * Text characters have been used to represent images since the earliest computers. * This sketch is a simple homage that re-interprets live video as ASCII text. * See the keyPressed function for more options, like changing the font size. */ import processing.video.*; Capture video; boolean cheatScreen; // All ASCII characters, sorted according to their visual density String letterOrder = " .`-_':,;^=+/\"|)\\<>)iv%xclrs{*}I?!][1taeo7zjLu" + "nT#JCwfy325Fp6mqSghVd4EgXPGZbYkOA&8U$@KHDBWNMR0Q"; char[] letters; float[] bright; char[] chars; PFont font; float fontSize = 1.5; void setup() { size(640, 480); // This the default video input, see the GettingStartedCapture // example if it creates an error video = new Capture(this, 160, 120); // Start capturing the images from the camera video.start(); int count = video.width * video.height; //println(count); font = loadFont("UniversLTStd-Light-48.vlw"); // for the 256 levels of brightness, distribute the letters across // the an array of 256 elements to use for the lookup letters = new char[256]; for (int i = 0; i < 256; i++) { int index = int(map(i, 0, 256, 0, letterOrder.length())); letters[i] = letterOrder.charAt(index); } // current characters for each position in the video chars = new char[count]; // current brightness for each point bright = new float[count]; for (int i = 0; i < count; i++) { // set each brightness at the midpoint to start bright[i] = 128; } } void captureEvent(Capture c) { c.read(); } void draw() { background(0); pushMatrix(); float hgap = width / float(video.width); float vgap = height / float(video.height); scale(max(hgap, vgap) * fontSize); textFont(font, fontSize); int index = 0; video.loadPixels(); for (int y = 1; y < video.height; y++) { // Move down for next line translate(0, 1.0 / fontSize); pushMatrix(); for (int x = 0; x < video.width; x++) { int pixelColor = video.pixels[index]; // Faster method of calculating r, g, b than red(), green(), blue() int r = (pixelColor >> 16) & 0xff; int g = (pixelColor >> 8) & 0xff; int b = pixelColor & 0xff; // Another option would be to properly calculate brightness as luminance: // luminance = 0.3*red + 0.59*green + 0.11*blue // Or you could instead red + green + blue, and make the the values[] array // 256*3 elements long instead of just 256. int pixelBright = max(r, g, b); // The 0.1 value is used to damp the changes so that letters flicker less float diff = pixelBright - bright[index]; bright[index] += diff * 0.1; fill(pixelColor); int num = int(bright[index]); text(letters[num], 0, 0); // Move to the next pixel index++; // Move over for next character translate(1.0 / fontSize, 0); } popMatrix(); } popMatrix(); if (cheatScreen) { //image(video, 0, height - video.height); // set() is faster than image() when drawing untransformed images set(0, height - video.height, video); } } /** * Handle key presses: * 'c' toggles the cheat screen that shows the original image in the corner * 'g' grabs an image and saves the frame to a tiff image * 'f' and 'F' increase and decrease the font size */ void keyPressed() { switch (key) { case 'g': saveFrame(); break; case 'c': cheatScreen = !cheatScreen; break; case 'f': fontSize *= 1.1; break; case 'F': fontSize *= 0.9; break; } }