This makes the second time this week i've been researching something just for the hell of it and suddenly find a use for it a day later, altho I guess the rounding algorithm stuff did have an actual purpose. Oddly enough, the project i want to use it for was waiting for me to figure out some version of this little snippet. Originally I was thinking i was going to have to do it as a full on hand-tracking/skeletal tracking thing, but if I can figure out some smoothing, I think this'll work pretty nicely on its own. We're putting together a mini-installation at work, details of which I'll not spoil for you here, but should be fun...
I started wondering about frame differencing after repeated visits to testwebcam.com (yes, it's SFW). Simple effect, but it looks really cool. Also a great way to approximate motion on a webcam stream. The initial implementation didn't take me too long, now I just have to implement some optical flow or maybe even just a cheap trailing-3 tap, who knows? Of course, you're welcome to solve that problem yourself if you wanna copy-paste this into your own copy of processing and hit Ctrl-R...seriously, your copy of p5 looks a little lonely and unloved, you should do something with it...I did some tests with lerping and vector/distancing, but i think i'm going to need a real filter...
This is totally not a photoshop, run the sketch if you don't believe me...
//PREPARE YOURSELF FOR THE COMING OF 2.0 //GET GSVIDEOOOOkay it's actually not going to be //that big of a transition. import codeanticode.gsvideo.*; PImage lastFrame; GSCapture vStream; int diff; int thresh = 32; ArrayList<PVector> dVals = new ArrayList(); PVector p_m; PVector lastP; void setup() { p_m = new PVector(0,0); lastP = new PVector(0,0); size(640, 480, P2D); frameRate(30); lastFrame = createImage(width,height,RGB); vStream = new GSCapture(this, width, height); vStream.start(); background(0); } void draw() { diff = 0; loadPixels(); dVals.clear(); if(vStream.available()) { vStream.read(); vStream.loadPixels(); lastFrame.loadPixels(); for (int x=0;x<width;x++) { for (int y=0;y<height;y++) { int i = y*width+x; color c = vStream.pixels[i]; color l = lastFrame.pixels[i]; int c_r = int(red(c)); int c_g = int(green(c)); int c_b = int(blue(c)); int l_r = int(red(l)); int l_g = int(green(l)); int l_b = int(blue(l)); int d_r = max(0,(c_r-l_r)-thresh); int d_g = max(0,(c_g-l_g)-thresh); int d_b = max(0,(c_b-l_b)-thresh); int d_s = d_r+d_g+d_b; diff += d_s; if(d_s>0) { dVals.add(new PVector(x,y)); } pixels[i] = vStream.pixels[i]; lastFrame.pixels[i] = c; } } } updatePixels(); if(diff>0) { p_m = avgArrayList(dVals); fill(255,255,255); ellipse(p_m.x,p_m.y,40,40); } lastP = p_m; } PVector avgArrayList(ArrayList<PVector> arr) { float sumx=0; float sumy=0; for(int i=0;i<arr.size();i++) { PVector c = (PVector)arr.get(i); sumx+=c.x; sumy+=c.y; } return new PVector(sumx/arr.size(),sumy/arr.size()); } void keyPressed() { if(key=='q') { thresh+=1; if(thresh>128) thresh=128; } if(key=='a') { thresh-=1; if(thresh<8) thresh=8; } } void stop() { vStream.stop(); vStream.dispose(); }
No comments:
Post a Comment