Bee Here, Bee Gone

(I know. Cheesy, cheesy title.)

My original idea for this assignment had to do with brightness and ghosts. I wanted to use my laptop’s camera to obtain the video’s brightness and set a brightness threshold. If the room wasn’t dark (above the threshold), text would appear to tell the user they should turn off the lights. Once the brightness was sufficiently low, the background would change (using background substraction) to an image of a ghost. Hopefully, I thought, it would cause jump scares but not heart attacks.

I started coding this but realized that I don’t like how dirty the background subtraction turns out when the video is dark, given that the user’s face is also affected. Thus, I changed the idea to a little ghost that would appear and follow the user.

Somewhere along the way, it occured to me that the ghost should be chasing something specific, and my plan changed completely. I imagined the user taking sweets from a candy bowl and a fly appearing on screen to chase the candy from the user’s hand. I googled “fly gif” and found a nice bee. Classic Google. So I decided to make a bee that chases flower pollen.

I made sure that the following happen in the program:

– The bee follows a green LED covered in pollen. The LED can only be covered in pollen after it’s “dipped” into a flower garden. To do this, I obtained the area in the video that corresponds to being inside the garden; if the LED (which the code tracks by color and brightness) is positioned within this area, an image of pollen (a teeny tiny mountain of pollen) appears over the LED and an animation of a bee flutters above it.

– The bee moves closer to the pollen if the LED remains steady (meaning, if the x-coordinate doesn’t vary too much between video frames). Otherwise, it hovers a bit higher. I think this makes the bee’s movements a bit more realistic.

– If one of the code’s global variables is changed (the boolean named “attraction” is changed to false), then the pollen disappears. This is useful if the video captures a bigger object (or a background) that is green, for it changes the interaction. Instead of having the bee follow the little green light, the user can shoo the bee away while it hovers over the green backdrop.

The following video shows how each version of the program can be used (“Bee Here” followed by “Bee Gone”):

(Music: “Seven Days A Week,” Austin Roberts)

And this is the Processing code. I took Aaron’s color tracking example and made some tweaks:

import processing.video.*;
Capture video;
PImage flower, pollen;
PImage bee0, bee1, bee2, bee3, bee4, bee5, bee6, bee7;
color trackColor;
int locX, locY, prevX;
boolean start;
int counter;
boolean attraction = true; //can be changed to false

void setup() {
 size(640, 480);
 video = new Capture(this, 640, 480, 30);
 flower = loadImage("flower.png");
 pollen = loadImage("pollen.png");
 bee0 = loadImage("bee0.png");
 bee1 = loadImage("bee1.png");
 bee2 = loadImage("bee2.png");
 bee3 = loadImage("bee3.png");
 bee4 = loadImage("bee4.png");
 bee5 = loadImage("bee5.png");
 bee6 = loadImage("bee6.png");
 bee7 = loadImage("bee7.png");
 video.start();
 start = false;
 trackColor = color(0, 255, 0);
 counter = 0;
}

void draw() {
 if (video.available()) {
 video.read();
 }
 video.loadPixels();
 float dist=500;
 for (int y=0; y<height; y++) {
 for (int x=0; x<width; x++) {
 int loc = (video.width-x-1)+(y*width);
 color pix=video.pixels[loc];
 float r1=red(pix);
 float g1=green(pix);
 float b1=blue(pix);
 float r2=red(trackColor);
 float g2=green(trackColor);
 float b2=blue(trackColor);
 float diff=dist(r1,g1,b1,r2,g2,b2);
 
 if (diff<dist){
 dist=diff;
 prevX = locX;
 locX=x;
 locY=y;
 }
 }
 }
 video.updatePixels();
 pushMatrix();
 translate(width,0);
 scale(-1,1);
 image(video,0,0);
 popMatrix();
 fill(trackColor);
 if((locX <= 25 && locY >= 370) || 
 (locX >= 25 && locX <= 135 && locY >= 320)||
 (locX >= 135 && locX <= 195 && locY >= 370) ||
 (locX >= 195 && locX <= 220 && locY >= 400) ||
 (locX >= 220 && locX <= 290 && locY >= 370) ||
 (locX >= 290 && locX <= 320 && locY >= 400) ||
 (locX >= 320 && locX <= 430 && locY >= 370) ||
 (locX >= 430 && locX <= 530 && locY >= 400) ||
 (locX >= 530 && locY >= 320)){
 start = true;
 };
 imageMode(CENTER);
 if(attraction == true){
 if(start == true){
 counter++;
 image(pollen, locX, locY);
 }
 }
 else{
 counter++;
 }
 if(counter > 20){
 int randomX = int(random(-10, 10));
 int randomY;
 if(prevX + 5 >= locX && prevX - 5 <= locX){
 randomY = int(random(30, 50));
 }
 else{
 randomY = int(random(80, 100));
 };
 if(counter%8 == 0){
 image(bee7, locX - randomX, locY - randomY);
 }
 else if(counter%7 == 0){
 image(bee6, locX - randomX, locY - randomY);
 }
 else if(counter%6 == 0){
 image(bee5, locX - randomX, locY - randomY);
 }
 else if(counter%5 == 0){
 image(bee4, locX - randomX, locY - randomY);
 }
 else if(counter%4 == 0){
 image(bee3, locX - randomX, locY - randomY);
 }
 else if(counter%3 == 0){
 image(bee2, locX - randomX, locY - randomY);
 }
 else if(counter%2 == 0){
 image(bee1, locX - randomX, locY - randomY);
 }
 else{
 image(bee0, locX - randomX, locY - randomY);
 }
 };
 imageMode(CORNER);
 scale(0.5);
 image(flower, -100, 600);
}

void mousePressed(){
 int loc = (video.width-mouseX-1)+(mouseY*width);
 color tracked = video.pixels[loc];
 float bright = brightness(tracked);
 if(bright > 200){
 trackColor = tracked;
 };
}