Category Archives: text-rain

Robb

25 Jan 2013

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

GitHub Link

////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);
}

Project 1: TextRain

screenshot

Here is my reimplementation of TextRain. I am offering more of a proof of concept solution, so I could really keep things simple. The implementation process is the following: reading a text file with famous quotes on every line, at start initializing an ArrayList of all the letters from every loaded text line, positioned regarding their order in the sentence. Then on every frame I get a live video feed from my webcam and going through all “flying” letters, I check if they collide with these areas of the image that are darker then my “collisionThreshold”, if they collide, I keep the letter still, if not the letter continues down the road.

Code: https://github.com/kamend/IACD_TextRain

import processing.video.*;

// objects
class Letter {
  PVector vel;
  PVector pos; 
  char ch;
  color col;
};

// global vars
int videoWidth = 640;
int videoHeight = 480;
Capture cap; // video capture device

ArrayList(Letter) LetterList = new ArrayList(Letter)(); // the list that will hold the particles

float letterXOffset = 10; // how far we should draw the individual letters
float letterYOffset = 400; // how far every sentence should be
float collisionThreshold = 30; // haw dark the areas of collision must be
PFont font;

void setup() {
  size(640, 480);

  // initalizes video capture
  cap = new Capture(this, videoWidth, videoHeight);
  cap.start();

  // read text and launch "particles"
  launchSentences();

  // setup display font
  font = createFont("Helvetica Bold", 16, true);
  textFont(font, 16);
}

void launchSentences() {

  // read sentences from a file
  String lines[] = loadStrings("text.txt");

  for (int lineNum = 0;lineNum < lines.length;lineNum++) {
    String sentence = lines[lineNum];
    int setanceLength = sentence.length();
    for (int i=0;i height) {
      l.pos.y -= height+letterYOffset;
    }
  }
}

boolean isColliding(PVector pos) {
  float radius = 10.0;
  if (pos.y > radius && pos.y < = videoHeight-radius && pos.x >=0 && pos.x < videoWidth) {
    PVector pixelPos = pos.get();
    pixelPos.add(0.0, radius, 0.0);
    int pixelIndex = floor(pixelPos.x) + floor(pixelPos.y)*videoWidth;
    color pixelColor = cap.pixels[pixelIndex];

    if (brightness(pixelColor) < collisionThreshold)
      return true;
  }
  return false;
}

void draw() {
  update();

  background(0);
  image(cap, 0, 0); 

  for (int i=0;i= 0.0) {
      fill(l.col, 255 - abs(map(l.pos.y, 0, height, -200, 200)));
      text(l.ch, l.pos.x, l.pos.y);
    }
  }
}