Thursday

Forever popping bubbles!

I found this amazing effect (plus code) online from:
http://andybest.net/2009/02/processing-opencv-tutorial-2-bubbles/

Here is the creators video of the sketch:


Processing OpenCV Tutorial Video #2- Bubbles! from Andy Best on Vimeo.

I downloaded the code and started experimenting immediately.

Here is my first experiment. A simple one; delete the scoreboard at the top of the screen:






(Sorry about the festive nostalgia soundtrack!)

and here comes the original code:

import hypermedia.video.*;          //  Imports the OpenCV library

OpenCV opencv;                      //  Creates a new OpenCV object
PImage movementImg;                 //  Creates a new PImage to hold the movement image
int poppedBubbles;                  //  Creates a variable to hold the total number of popped bubbles
ArrayList bubbles;                  //  Creates an ArrayList to hold the Bubble objects
PImage bubblePNG;                   //  Creates a PImage that will hold the image of the bubble
PFont font;                         //  Creates a new font object

void setup()
{
  size ( 640, 480 );                      //  Window size of 640 x 480
  opencv = new OpenCV( this );            //  Initialises the OpenCV library
  opencv.capture( 640, 480 );             //  Sets the capture size to 640 x 480
  movementImg = new PImage( 640, 480 );   //  Initialises the PImage that holds the movement image
 
  poppedBubbles = 0;                    
 
  bubbles = new ArrayList();              //  Initialises the ArrayList
 
  bubblePNG = loadImage("bubble.png");    //  Load the bubble image into memory
  font = loadFont("Serif-48.vlw");        //  Load the font file into memory
 textFont(font, 32);                      

}

void draw()
{
  bubbles.add(new Bubble( (int)random( 0, width - 40), -bubblePNG.height, bubblePNG.width, bubblePNG.height));   //  Adds a new bubble to the array with a random x position
 
  opencv.read();                              //  Captures a frame from the camera   
  opencv.flip(OpenCV.FLIP_HORIZONTAL);        //  Flips the image horizontally
  image( opencv.image(), 0, 0 );              //  Draws the camera image to the screen
  opencv.absDiff();                           //  Creates a difference image
   
  opencv.convert(OpenCV.GRAY);                //  Converts to greyscale
  opencv.blur(OpenCV.BLUR, 3);                //  Blur to remove camera noise
  opencv.threshold(20);                       //  Thresholds to convert to black and white
  movementImg = opencv.image();               //  Puts the OpenCV buffer into an image object
 // background(51);
 
  for ( int i = 0; i < bubbles.size(); i++ ){    //  For every bubble in the bubbles array
    Bubble _bubble = (Bubble) bubbles.get(i);    //  Copies the current bubble into a temporary object
   
    if(_bubble.update() == 1){                  //  If the bubble's update function returns '1'
      bubbles.remove(i);                        //  then remove the bubble from the array
      _bubble = null;                           //  and make the temporary bubble object null
      i--;                                      //  since we've removed a bubble from the array, we need to subtract 1 from i, or we'll skip the next bubble
   
  }else{                                        //  If the bubble's update function doesn't return '1'
      bubbles.set(i, _bubble);                  //  Copys the updated temporary bubble object back into the array
      _bubble = null;                           //  Makes the temporary bubble object null.
    }
  }
 
  opencv.remember(OpenCV.SOURCE, OpenCV.FLIP_HORIZONTAL);    //  Remembers the camera image so we can generate a difference image next frame. Since we've
                                                             //  flipped the image earlier, we need to flip it here too.
//  text("Bubbles popped: " + poppedBubbles, 20, 40);          //  Displays some text showing how many bubbles have been popped
 
}

class Bubble
{
 
  int bubbleX, bubbleY, bubbleWidth, bubbleHeight;    //  Some variables to hold information about the bubble
 
  Bubble ( int bX, int bY, int bW, int bH )           //  The class constructor- sets the values when a new bubble object is made
  {
    bubbleX = bX;
    bubbleY = bY;
    bubbleWidth = bW;
    bubbleHeight = bH;
  }
 
  int update()      //   The Bubble update function
  {
    int movementAmount;          //  Create and set a variable to hold the amount of white pixels detected in the area where the bubble is
    movementAmount = 0;
   
    for( int y = bubbleY; y < (bubbleY + (bubbleHeight-1)); y++ ){    //  For loop that cycles through all of the pixels in the area the bubble occupies
      for( int x = bubbleX; x < (bubbleX + (bubbleWidth-1)); x++ ){
       
        if ( x < width && x > 0 && y < height && y > 0 ){             //  If the current pixel is within the screen bondaries
          if (brightness(movementImg.pixels[x + (y * width)]) > 127)  //  and if the brightness is above 127 (in this case, if it is white)
          {
            movementAmount++;                                         //  Add 1 to the movementAmount variable.
          }
        }
      }
    }
   
    if (movementAmount > 5)               //  If more than 5 pixels of movement are detected in the bubble area
    {
      poppedBubbles++;                    //  Add 1 to the variable that holds the number of popped bubbles
      return 1;                           //  Return 1 so that the bubble object is destroyed
  
   }else{                                 //  If less than 5 pixels of movement are detected,
      bubbleY += 10;                      //  increase the y position of the bubble so that it falls down
     
      if (bubbleY > height)               //  If the bubble has dropped off of the bottom of the screen
      {  return 1; }                      //  Return '1' so that the bubble object is destroyed
     
      image(bubblePNG, bubbleX, bubbleY);    //  Draws the bubble to the screen
      return 0;                              //  Returns '0' so that the bubble isn't destroyed
    }
   
  }
 
}

Now time to adapt a little.
First little experiment: change the image to another bubble.png:

 

And now some Nike Trainers!:



finally, I went back to the bubbles and found a simple tip to blackout the background, so you cannot see my image, but the code still works in the same way:
(Extract of the code is displayed below):

opencvOpenCV.GRAY);                //  Converts to greyscale
  opencv.blur(OpenCV.BLUR, 3);                //  Blur to remove camera noise
  opencv.threshold(20);                       //  Thresholds to convert to black and white
  movementImg = opencv.image();               //  Puts the OpenCV buffer into an image object
  background(51);

The last line: background (51) is what blakcs out the background. Clever, eh? Here's the result:



So, now I am going to on and experiment from there with this effect. But first I need to research a bit more into the Nike branding- feel I want to get across.

0 comments:

Post a Comment