|
Author |
Topic: timestruct (Read 522 times) |
|
swannodette
|
timestruct
« on: Dec 28th, 2003, 11:45pm » |
|
Using footage from my brand new Canon PowerShot SD100 i made a project that samples different points of a video buffer- resulting in a fractured time study. There's lots of possibilities here for creating interesting film/video projects. to see quicktime movies of the results link to: http://www.onager.org/~dnolen/timestruct.html if anybody has any pointers on making this code faster that would be greatly appreciated- there's a lot of pixel copying; Thus the applet is only really good for rendering and not realtime. Also it seems that copying a Bvideo.pixels field to a BImage.pixels field results in just passing a pointer to the video- also it would be nice if there was a method like image(BVideo, 0, 0) that returned a BImage. anyways: //12-25-03 dissecting time by the pixel int FPS = 30; int BUFSIZE = 48; BVideo myvid; BImage[] vidBuffer = new BImage[BUFSIZE]; int counter = 0; void setup() { framerate(30); myvid = loadVideo("momma.mov"); size(320, 240); repeat(myvid); //create a buffer of the first 96 images of the movie //init the buffer since processing doesn't allow for //creating empty BImage objects for(int i = 0; i<BUFSIZE; i++) vidBuffer[i] = loadImage("initframe.jpg"); } void loop() { BImage modframe = loadImage("initframe.jpg"); int frameinc = 0, curframe = 0, cp=0; background(0); if(counter < BUFSIZE) { //load first 48 frames for(int i = 0; i< myvid.width*myvid.height; i++) vidBuffer[counter].pixels[i] = myvid.pixels[i]; } else { //get a frame from buffer modframe = vidBuffer[0]; //modify the modframe //the fun and tricky part for(int r = 0; r<modframe.height; r++) { //split into rows, inelegant I know if(cp<modframe.width*(modframe.height/4)) curframe = 0; else if(cp<modframe.width*2*(modframe.height/4)) curframe = BUFSIZE/4; else if(cp<modframe.width*3*(modframe.height/4)) curframe = 2*BUFSIZE/4; else curframe = 3*BUFSIZE/4; //draw columns for(int n=0; n<6; n++) { for(int m=0; m<modframe.width/6; m++) { cp = r*modframe.width+n*(modframe.width/6)+m; modframe.pixels[cp] = vidBuffer[curframe].pixels[cp]; } curframe+=BUFSIZE/24; } } //display the new frame image(modframe, 0, 0); //move all frames in the video buffer up one //have to copy all the pixel one by one since copying just //the .pixels field actually just passes a reference to the video for(int j = 1; j < BUFSIZE; j++) for(int i = 0; i< myvid.width*myvid.height; i++) vidBuffer[j-1].pixels[i] = vidBuffer[j].pixels[i]; //copy current vidframe into last fram of buffer for(int i = 0; i< myvid.width*myvid.height; i++) vidBuffer[BUFSIZE-1].pixels[i] = myvid.pixels[i]; } //save an image so I can make a .mov of this nonsense saveFrame(); counter++; }
|
« Last Edit: Dec 28th, 2003, 11:46pm by swannodette » |
|
|
|
|
TomC
|
Re: timestruct
« Reply #1 on: Dec 29th, 2003, 1:49am » |
|
Hey, that's neat. Reminds me of a slide puzzle, but that's a sketch for another day Playing around, I reckon you can get a bit of a speed nudge by replacing... Code: for(int i = 0; i< video.pixels.length; i++) vidBuffer[counter].pixels[i] = video.pixels[i]; |
| with Code: vidBuffer[counter] = video.copy(width,height); |
| Also, I think there is an as yet undocumented constructor for BImage which might help you out. Rather than Code: vidBuffer[i] = loadImage("initframe.jpg"); |
| Try Code: vidBuffer[i] = new BImage(width, height); |
| After that, things get a little more complex, but bear with me. Rather than always having the same place in your buffer as the current frame (shuffling your buffer down one frame each time), you can just keep track of which buffer is current, and then add that to the index when accessing the array, modulo buffer length. Erm... I'll try an example. Rather than: Code: // remember 100 frames, // (buffer[0] is most recent, buffer[99] is oldest) BImage[] buffer = new BImage[100]; void setup() { size(320,240); beginVideo(width,height,30); for (int i = 0; i < buffer.length; i++) buffer[i] = new BImage(width,height); } void loop() { // copy each buffer image back one place for (int i = 1; i < buffer.length; i++) buffer[i-1] = buffer[i]; // store current buffer[buffer.length-1] = video.copy(); // display last image(buffer[0],0,0); } |
| Do this: Code: // remember 100 frames BImage[] buffer = new BImage[100]; // remember where the oldest frame is int oldestFrame = 0; void setup() { size(320,240); beginVideo(width,height,30); for (int i = 0; i < buffer.length; i++) buffer[i] = new BImage(width,height); } void loop() { // (now there's no need to move every frame in the buffer...) // store current frame, buffer.length-1 places away from oldestFrame buffer[(oldestFrame+buffer.length-1)%buffer.length] = video.copy(); // display oldestFrame image(buffer[oldestFrame%buffer.length],0,0); oldestFrame++; } |
| I think it should be quicker, but it probably only depends on buffer length now, since we're using the copy method rather than doing it per pixel. I'll post my modified version in a minute.
|
|
|
|
TomC
|
Re: timestruct
« Reply #2 on: Dec 29th, 2003, 2:04am » |
|
OK, this works in just about real-time for me, at 320x240. (The original version did too actually, to be fair. That means that there's no guarantee my optimisations represent anything other than coding preferences. Let me know how you get on.) Code: //12-25-03 dissecting time by the pixel (swannodette) //12-28-03 with luck, some optimisations (TomC) int FPS = 30; int BUFSIZE = 48; BImage[] vidBuffer = new BImage[BUFSIZE]; BImage modframe; int counter = 0; void setup() { size(640,480); framerate(FPS); beginVideo(width,height,FPS); //create a buffer of the first 96 images of the movie //init the buffer since processing doesn't allow for //creating empty BImage objects for(int i = 0; i<vidBuffer.length; i++) vidBuffer[i] = new BImage(width,height); } void loop() { if(counter < vidBuffer.length) { //load first 48 frames vidBuffer[counter] = video.copy(); } else { //get a frame from buffer modframe = vidBuffer[counter%vidBuffer.length]; //modify the modframe //the fun and tricky part int cp = 0, curframe = 0; for(int r = 0; r<modframe.height; r++) { //split into rows, inelegant I know if(cp<modframe.width*(modframe.height/4)) curframe = 0; else if(cp<modframe.width*2*(modframe.height/4)) curframe = vidBuffer.length/4; else if(cp<modframe.width*3*(modframe.height/4)) curframe = 2*vidBuffer.length/4; else curframe = 3*vidBuffer.length/4; //draw columns for(int n=0; n<6; n++) { for(int m=0; m<modframe.width/6; m++) { cp = r*modframe.width+n*(modframe.width/6)+m; modframe.pixels[cp] = vidBuffer[(curframe+counter)%vidBuffer.length].pixels[cp]; } curframe+=vidBuffer.length/24; } } //copy current vidframe into last fram of buffer vidBuffer[(counter-1)%vidBuffer.length] = video.copy(width,height); //display the new frame image(modframe, 0, 0); } //save an image so I can make a .mov of this nonsense //saveFrame(); counter++; } |
| On update: Just realised there's no need for modFrame, since you can write directly to pixels. And you always save the currentFrame into the buffer, so there's no need to have that bit of code twice. Also, width*height is the same as pixels.length. It's quite short now, neatly showcasing your algorithm. Code: //12-25-03 dissecting time by the pixel (swannodette) //12-28-03 with luck, some optimisations (TomC) int FPS = 30; int BUFSIZE = 48; BImage[] vidBuffer = new BImage[BUFSIZE]; int counter = 0; void setup() { size(640,480); framerate(FPS); beginVideo(width,height,FPS); } void loop() { if(counter > vidBuffer.length) { //the fun and tricky part int cp = 0, curframe = 0; for(int r = 0; r < height; r++) { //split into rows, inelegant I know if(cp < pixels.length/4) curframe = 0; else if(cp < pixels.length/2) curframe = vidBuffer.length/4; else if(cp < pixels.length*3/4) curframe = 2*vidBuffer.length/4; else curframe = 3*vidBuffer.length/4; //draw columns for(int n=0; n<6; n++) { for(int m=0; m<width/6; m++) { cp = r*width+n*(width/6)+m; pixels[cp] = vidBuffer[(curframe+counter)%vidBuffer.length].pixels[cp]; } curframe+=vidBuffer.length/24; } } } //copy current vidframe into last fram of buffer vidBuffer[(counter+vidBuffer.length-1)%vidBuffer.length] = video.copy(); //save an image so I can make a .mov of this nonsense //saveFrame(); counter++; } |
|
|
« Last Edit: Dec 29th, 2003, 2:15am by TomC » |
|
|
|
|
swannodette
|
Re: timestruct
« Reply #3 on: Dec 29th, 2003, 11:09pm » |
|
Thanks for the insights. I actually like your optimization, it makes the code more readable and it's great to know there's a constructor for BImage. I'm running on a 400Mhz Powerbook so anything to speed things up helps.
|
|
|
|
|