We closed this forum 18 June 2010. It has served us well since 2005 as the ALPHA forum did before it from 2002 to 2005. New discussions are ongoing at the new URL http://forum.processing.org. You'll need to sign up and get a new user account. We're sorry about that inconvenience, but we think it's better in the long run. The content on this forum will remain online.
Page Index Toggle Pages: 1
help with simple video effect (Read 620 times)
help with simple video effect
Dec 10th, 2008, 1:26am
 
Hey,

I am trying to create a simple video effect as follows,

capture frame and recreate image with a series of black dots

wait for 2.5 seconds and capture another frame and recreate with dots

display first frame

morph the first image into the second over 2.5 seconds

this is what I have

import processing.video.*;

// Size of each circle in the grid
int circleSize = 5;
// Number of columns and rows
int cols, rows;
// Variable for capture device
Capture video;


void setup() {
 size(640, 480, P3D);
 frameRate(50);
 cols = width / cellSize;
 rows = height / cellSize;
 colorMode(RGB, 255, 255, 255, 100);
 video = new Capture(this, width, height, 12);
 smooth();
}


void draw() {
 
 float[] snap01 = new float[cols*rows];
 float[] snap02 = new float[cols*rows];
 color c = color(0, 0, 0, 75);
 background(255,255,255);
 if (video.available()) {
   video.read();
   video.loadPixels();
   
   //capture first frame and write circle size data to array
   for (int i = 0; i < cols; i++) {
     for (int j = 0; j < rows; j++) {
       int x = i*cellSize;
       int y = j*cellSize;
       int loc =  x + y*video.width;
       float r = red(video.pixels[loc]);
       float g = green(video.pixels[loc]);
       float b = blue(video.pixels[loc]);
       snap01[i+cols*j] = 0.3*r + 0.59*g + 0.11*b;
     }
   }
   
   //wait for 2.5 seconds
   delay(2500);
   
   //write circle size data from second frame to array
       for (int i = 0; i < cols; i++) {
     for (int j = 0; j < rows; j++) {
       int x = i*cellSize;
       int y = j*cellSize;
       int loc =  x + y*video.width;
       float r = red(video.pixels[loc]);
       float g = green(video.pixels[loc]);
       float b = blue(video.pixels[loc]);
       snap02[i+cols*j] = 0.3*r + 0.59*g + 0.11*b;
     }
   }
   
   //take 2.5 seconds to morph between the two frames
      for (int k = 0; k < 126; k++){
   
 for (int i = 0; i < cols; i++) {
     for (int j = 0; j < rows; j++) {
       int x = i*cellSize;
       int y = j*cellSize;      
       float interp = snap01[i+cols*j] + ((snap02[i+cols*j]-snap01[i+cols*j])*k/125);
       ellipseMode(CENTER);
       fill(c);
       noStroke();
       ellipse(x+cellSize/2, y+cellSize/2, cellSize*(255-interp)/255, cellSize*(255-interp)/255);
 
     }
 }
 
 }

// write data of second frame into first and loop
 snap01 = snap02;
 }
 
}

It is a pretty long way off, I am finding the timing slightly confusing. I have written the two sets of data into arrays and simply need to interpolate them in a loop. Any help would be gratefully received.

Many thanks,

GB.
Re: help with simple video effect
Reply #1 - Dec 10th, 2008, 5:01am
 
not so sure if i understand what you want to do. however, having had a quick look at the code (and a failed attempt to run it - what is cellSize?) here a few comments:

*looks like you are confusing yourself. it helps to get a bit of paper and write down exactly what it is you want to do

*snap01 and 02 are no different since you are not updating the video in between setting those arrays. this would require an extra call of video.read();  but you should not do it that way. instead:

-use global rather than local variables (snap should be global). by global i mean declared outside of draw or setup so both setup and draw can see the variable.

-think of update and draw separately. of course there is no update function but inside draw separate the code so you know which one does the drawing  and which one updates the data

-define a list of circle coordinates (your data), so your draw section will simply draw the list. i.e. something like

float[] xlist, ylist;

...set and update xlist and ylist

then draw is just:

for(int i = 0; i < numOfPoints; i++)
{
 ellipse(xlist[i],ylist[i],radius,radius);  
}

-your update code does a bit more: it updates the coordinates of the circles depending on a timing variable rather than a delay. so introduce something like

if(elapsedTime > interval)
{
UpdateSnap();
elapsedTime = 0;
}

best to write this as a separate function for clarity and maintainability i.e.

void UpdateSnap( float[] snap)
{
..all the code here
}

-you probably want to perform the interpolation at every draw call. this is the only bit of code that directly changes the list of circle coordinates which you end up drawing

good luck
Re: help with simple video effect
Reply #2 - Dec 10th, 2008, 10:53am
 
Hey drmo,

Thanks a million for the reply but I am still a bit confused. The code below should hopefully help to explain what I am trying to do, even though it still has the delay in it.

import processing.video.*;

// set circle size
int circleSize = 10;
// set variables
int cols, rows;
// set variable for capture device
Capture video;


void setup() {
 size(640, 480, P3D);
 frameRate(30);
 cols = width / circleSize;
 rows = height / circleSize;
 colorMode(RGB, 255, 255, 255, 100);
 video = new Capture(this, width, height, 12);
 smooth();
 background(0);
}


void draw() {
 
 float[] snap01 = new float[cols*rows];
  color c = color(0, 0, 0, 75);
 background(255,255,255);
 if (video.available()) {
   video.read();
   video.loadPixels();
   
//write circle size data to array
   for (int i = 0; i < cols; i++) {
     for (int j = 0; j < rows; j++) {
       int x = i*circleSize;
       int y = j*circleSize;
       int loc =  x + y*video.width;
       float r = red(video.pixels[loc]);
       float g = green(video.pixels[loc]);
       float b = blue(video.pixels[loc]);
       snap01[i+cols*j] = 0.3*r + 0.59*g + 0.11*b;
     }
   }
//draw circles    
 for (int i = 0; i < cols; i++) {
     for (int j = 0; j < rows; j++) {
       int x = i*circleSize;
       int y = j*circleSize;      
       ellipseMode(CENTER);
       fill(c);
       noStroke();
       ellipse(x+circleSize/2, y+circleSize/2, circleSize*(255-snap01[i+cols*j] )/255, circleSize*(255-snap01[i+cols*j])/255);
 
     }
 }
 
 }
 delay(5000);
}

That should run. You should see a frame displayed every 5 seconds. Now I would like each displayed frame to morph into the next, so the circles increase or decrease in size hence the interpolation.

If the snap[] is global how would I set it's size? The rows and cols are set inside setup and are required to set the dimensions of the array. Is there a Redim or something like that I can use?

I hope that is a bit clearer. Thanks again for your help.

GB.
Re: help with simple video effect
Reply #3 - Dec 10th, 2008, 10:57am
 
I just wanted to add that I don't expect this to run in realtime. In order to calculate the interpolations it will need to have a kind of buffer of 5 seconds, or whatever the interval between the captured images is.

Thanks.
Re: help with simple video effect
Reply #4 - Dec 10th, 2008, 6:37pm
 
this should do the trick:

import processing.video.*;

// set circle size
int circleSize = 10;
// set variables
int cols, rows;
// set variable for capture device
Capture video;

float timeMS=0;        //stores the time in milliseconds at which the last frame was updated
float interval = 2500; //update interval in milliseconds i.e. 2.5 seconds

float[] snap01;        //stores colour of last frame update
float[] snapDisplay;   //stores colour of interpolate be

color col  = color(0, 0, 0, 75); //make this global as well so it's easy to change

void setup()
{

 size(640, 480, P3D);

 frameRate(30);

 cols = width / circleSize;
 rows = height / circleSize;

 //you can allocated global variables inside any function, but you only want to do this once
 //so allocate them here  
 snap01         = new float[cols*rows];
 snapDisplay    = new float[cols*rows];

 colorMode(RGB, 255, 255, 255, 100);
 video = new Capture(this, width, height, 12);
 smooth();
}



void draw()
{  
   
 
 //---------- UPDATE -------------
 
 if(millis()-timeMS > interval)
 {
   //we dont need to read video evertime we do a draw but only once
   //everytime we want to update, i.e. every 2.5 seconds (or whatever interval is)
   
   if(video.available())
   {
   
     video.read();
   
     //this now calls a function keeping draw smaller and more readable
     UpdateSnap(video);
   
     timeMS = millis(); //reset time variable  
   }
   
 }
 
 Interpolate();
 
 //---------- DRAW --------------
 
 background(255);
 
 DrawCircles();
 
 //delay(5000);
//avoid delays - this basically stops the program for 2.5 //sec so you can't do anything else (like interpolating!)
}


void Interpolate()
{
 float blendSpeed = 0.05;
 for(int i = 0; i  < snap01.length; i++)
 {
   snapDisplay[i] = (1.0-blendSpeed) * snapDisplay[i]  + blendSpeed * snap01[i];
 }
}

void DrawCircles()
{
     
 for (int i = 0; i < cols; i++)
 {
    for (int j = 0; j < rows; j++)
    {
        int x = i*circleSize;
        int y = j*circleSize;  
       
        ellipseMode(CENTER);
        fill(col);
        noStroke();
       
        //ellipse(x+circleSize/2, y+circleSize/2, circleSize*(255-snap01[i+cols*j] )/255, circleSize*(255-snap01[i+cols*j])/255);
        ellipse(x+circleSize/2, y+circleSize/2, circleSize*(255-snapDisplay[i+cols*j] )/255, circleSize*(255-snapDisplay[i+cols*j])/255);
    }
 }
 
}

void UpdateSnap(PImage img)
{
  //since 'video' is also an image (i.e. the Video class derives from PImage - so it can do all the things PImage does and more)
  //we can just treat it as that here since we don't need to call any of the video specific functions
   
   img.loadPixels();
   
   for (int i = 0; i < cols; i++)
   {
      for (int j = 0; j < rows; j++)
      {
        int x = i*circleSize;
        int y = j*circleSize;
       
        int loc =  x + y*img.width;  
 
        float r = red(img.pixels[loc]);
        float g = green(img.pixels[loc]);
        float b = blue(img.pixels[loc]);
       
        snap01[i+cols*j] = 0.3*r + 0.59*g + 0.11*b;
      }
   }
   
   img.updatePixels(); //the inverse of load pixels - i think you forgot this, but it doesn't seem to be required unless the image is a display
}
Re: help with simple video effect
Reply #5 - Dec 10th, 2008, 7:44pm
 
That's perfect, thanks so much!

GB
Page Index Toggle Pages: 1