I went with the threshold method. Ideally, I think it should use background subtraction, but thats for another day.
The rainbow circles give the letters legibility, playfulness, and greater visual weight. I encountered several challenges with this project.
It took me about 4 hours.
I commented the heck out of my mediocre code if anyone is curious.
I have trouble with logic, so that section is likely verbose and roundabout. I’d love some tips.
w/♡,
-Robb
////RobbRain/////Textrain Spinoff, after Camille Utterback
////2013/////www.robb.cc//////////////////
import processing.video.*; ///add the library
Capture video;
int threshold = 122; //brightness value to count as dark
int letterSize = 20; //diameter of circles, real or imaginary that bound the falling shapes
int columnWidth = 20; //how wide you want the columns to be
int columnQty; //dependent on above
int numPix; //dependent, how many pixels are there?
int[] fallingY; //array of all the y values of our objects
String poem = "Trust not he who winces in rain.";
//char[] poem = { o,h, }; // Alternate syntax
void setup() {
size(640, 480, P2D); // Change size to 320 x 240 if too slow at 640 x 480
video = new Capture(this, width, height);
video.start();
colorMode(HSB); //easy rainbows man
noCursor(); //cursors are for sissys
noStroke();//as are strokes
smooth();//doesn't work.
println(poem.length());
numPix = video.width*video.height; //calc the pixel qty
columnQty = width/columnWidth; //calc the column qty
fallingY = new int[columnQty]; //size that array
for (int i = 0; i height||fallingY[i]<0) {//if it falls off the bottom or top, it should go again. no giving up
fallingY[i] = 10;
}
fallingLetter(sampleX, fallingY[i], poem.charAt(i),i); ///draws the thing.
}
if(mousePressed){setup();}////cute.. puts the letters at top if click.
}
}
void fallingLetter(int letterX, int letterY, char letter, int i) {
fill(map(i, 0, columnQty, 0, 255), 255, 255, 100);
ellipse(letterX, letterY, letterSize, letterSize);
fill(0);
text(letter, letterX-letterSize/3, letterY+letterSize/5);
}
int brightnessXY(int xxx, int yyy) { ///this lil guy calc the brightness of a video pixel and returns it as an int.
int videoIndex = constrain(yyy * video.width + xxx, 0, numPix-1); //index = y*videoWidth + x
int briteSpot = int(brightness(video.pixels[videoIndex]));
return briteSpot;
}
void mouseTrack() { //useful for finding the proper threshold.
float briteMouse = brightnessXY(mouseX, mouseY);
if (briteMouse > threshold) {
fill(0);
}
else {
fill(100);
}
rect(mouseX, mouseY, 20, 20);
}