Moirés with Processing

38
MOIRÉS with Processing

description

Magazine about the idea and code behind the Moiré Drawer.

Transcript of Moirés with Processing

Page 1: Moirés with Processing

MOIRÉS

MOIRÉS

with Processing

Page 2: Moirés with Processing

2011—Vier Professoren für Gestaltung wählen mein Designkonzept für eine Konferenz über interdisziplinäre Kreativität.

Zwei verschiedene Arten von Linien repräsentieren zwei unterschiedliche Arbeitsfelder, Herangehensweisen oder Denkensarten.

Werden sie interdisziplinär kombiniert kann Neues entstehen. Eine Innovation oder im Fall der Linien, ein Moiré.

0

Page 3: Moirés with Processing

1

Page 4: Moirés with Processing
Page 5: Moirés with Processing
Page 6: Moirés with Processing

4

//click to start drawing, move the mouse, click again to stop drawing//repeat to create moiré patterns

//hit backspace to clear the screen, hit „s“ to save as .png

import controlP5.*;

boolean drawing = false;int Line_Length = 250;boolean Flip_Gradient = false, Flip_Rainbow = false;float Line_Thickness = 5.0;int Color_Mode = 1;float Line_Angle = 0.0;int Line_Resolution = 25;int Line_Amplitude = 15;float distorsionFactor = 5;float centerX, centerY;float grad_Y, grad_Y2;float[] x = new float[Line_Resolution];float[] y = new float[Line_Resolution];int x1;

ControlP5 controlP5;ColorPicker cp_solid, cp_grad1, cp_grad2, cp_rgrad1, cp_rgrad2;

void initializeform(){ centerX = mouseX; centerY = mouseY; float radius = Line_Length*4; float angle = Line_Angle; float x1 = cos(angle) * radius; float y1 = sin(angle) * radius; float x2 = cos(angle-PI) * radius; float y2 = sin(angle-PI) * radius; for(int i=0; i<Line_Resolution; i++) { x[i] = lerp(x1, x2, i/(float)Line_Resolution) + random(-Line_Amplitude,Line_Amplitude); y[i] = lerp(y1, y2, i/(float)Line_Resolution) + random(-Line_Amplitude,Line_Amplitude);

Page 7: Moirés with Processing

5

//click to start drawing, move the mouse, click again to stop drawing//repeat to create moiré patterns

//hit backspace to clear the screen, hit „s“ to save as .png

import controlP5.*;

boolean drawing = false;int Line_Length = 250;boolean Flip_Gradient = false, Flip_Rainbow = false;float Line_Thickness = 5.0;int Color_Mode = 1;float Line_Angle = 0.0;int Line_Resolution = 25;int Line_Amplitude = 15;float distorsionFactor = 5;float centerX, centerY;float grad_Y, grad_Y2;float[] x = new float[Line_Resolution];float[] y = new float[Line_Resolution];int x1;

ControlP5 controlP5;ColorPicker cp_solid, cp_grad1, cp_grad2, cp_rgrad1, cp_rgrad2;

void initializeform(){ centerX = mouseX; centerY = mouseY; float radius = Line_Length*4; float angle = Line_Angle; float x1 = cos(angle) * radius; float y1 = sin(angle) * radius; float x2 = cos(angle-PI) * radius; float y2 = sin(angle-PI) * radius; for(int i=0; i<Line_Resolution; i++) { x[i] = lerp(x1, x2, i/(float)Line_Resolution) + random(-Line_Amplitude,Line_Amplitude); y[i] = lerp(y1, y2, i/(float)Line_Resolution) + random(-Line_Amplitude,Line_Amplitude);

P ro c e s s i n g – P ro g ra m m , J u l i 2 0 11

Ein Klick und horizontale Linien er-scheinen an der Mausposition. Bei zweitem Klicken hört es auf zu zeichnen. In der controlP5 Benutzeroberfläche ändert man folgende Eigenschaften der Linien:

Farbe/Farbverlauf, Transparenz, Län-ge, Stärke, Amplitude, Winkel.

S i m p l e M o i r é Z e i c h n e r

Page 8: Moirés with Processing

6

}}void setup(){ size(screenWidth, screenHeight); x1=screenWidth-200; int xlen=100; smooth(); background(#ffffff); controlP5 = new ControlP5(this); controlP5.window().setPositionOfTabs(x1,0); controlP5.tab(„default“).activateEvent(true); controlP5.tab(„default“).setLabel(„Solid“); controlP5.tab(„Gradient“).activateEvent(true); controlP5.tab(„Rainbow_Gradient“).activateEvent(true); controlP5.tab(„default“).setId(2); controlP5.tab(„default“).setPosition(screenWidth-200,0); controlP5.tab(„Gradient“).setId(3); controlP5.tab(„Rainbow_Gradient“).setId(4); cp_solid = controlP5.addColorPicker(„Solid_Color_Picker“,x1, 50, xlen, 0); cp_solid.setArrayValue(new float[] {255,0,0,255}); cp_grad1 = controlP5.addColorPicker(„Gradient_Color_Picker_1“, x1, 50, xlen, 0); cp_grad1.setArrayValue(new float[] {0,255,0,255}); cp_grad1.moveTo(„Gradient“); cp_grad2 = controlP5.addColorPicker(„Gradient_Color_Picker_2“, x1, 120, xlen, 0); cp_grad2.setArrayValue(new float[] {255,0,0,255}); cp_grad2.moveTo(„Gradient“); cp_rgrad1 = controlP5.addColorPicker(„Rainbow_Gradient_Color_Picker_1“, x1, 50, xlen, 0); cp_rgrad1.setArrayValue(new float[] {255,0,0,255}); cp_rgrad1.moveTo(„Rainbow_Gradient“); cp_rgrad2 = controlP5.addColorPicker(„Rainbow_Gradient_Color_Picker_2“, x1, 120, xlen, 0); cp_rgrad2.setArrayValue(new float[] {255,0,255,255}); cp_rgrad2.moveTo(„Rainbow_Gradient“); controlP5.addToggle(„Flip_Rainbow“,false,x1,190,25,25).moveTo(„ Rainbow_Gradient“); controlP5.addToggle(„Flip_Gradient“,false,x1,190,25,25).moveTo(„Gradient“); controlP5.addSlider(„Line_Length“,0,500,250.0,x1,300,xlen,25).moveTo („global“);

Page 9: Moirés with Processing

7

}}void setup(){ size(screenWidth, screenHeight); x1=screenWidth-200; int xlen=100; smooth(); background(#ffffff); controlP5 = new ControlP5(this); controlP5.window().setPositionOfTabs(x1,0); controlP5.tab(„default“).activateEvent(true); controlP5.tab(„default“).setLabel(„Solid“); controlP5.tab(„Gradient“).activateEvent(true); controlP5.tab(„Rainbow_Gradient“).activateEvent(true); controlP5.tab(„default“).setId(2); controlP5.tab(„default“).setPosition(screenWidth-200,0); controlP5.tab(„Gradient“).setId(3); controlP5.tab(„Rainbow_Gradient“).setId(4); cp_solid = controlP5.addColorPicker(„Solid_Color_Picker“,x1, 50, xlen, 0); cp_solid.setArrayValue(new float[] {255,0,0,255}); cp_grad1 = controlP5.addColorPicker(„Gradient_Color_Picker_1“, x1, 50, xlen, 0); cp_grad1.setArrayValue(new float[] {0,255,0,255}); cp_grad1.moveTo(„Gradient“); cp_grad2 = controlP5.addColorPicker(„Gradient_Color_Picker_2“, x1, 120, xlen, 0); cp_grad2.setArrayValue(new float[] {255,0,0,255}); cp_grad2.moveTo(„Gradient“); cp_rgrad1 = controlP5.addColorPicker(„Rainbow_Gradient_Color_Picker_1“, x1, 50, xlen, 0); cp_rgrad1.setArrayValue(new float[] {255,0,0,255}); cp_rgrad1.moveTo(„Rainbow_Gradient“); cp_rgrad2 = controlP5.addColorPicker(„Rainbow_Gradient_Color_Picker_2“, x1, 120, xlen, 0); cp_rgrad2.setArrayValue(new float[] {255,0,255,255}); cp_rgrad2.moveTo(„Rainbow_Gradient“); controlP5.addToggle(„Flip_Rainbow“,false,x1,190,25,25).moveTo(„ Rainbow_Gradient“); controlP5.addToggle(„Flip_Gradient“,false,x1,190,25,25).moveTo(„Gradient“); controlP5.addSlider(„Line_Length“,0,500,250.0,x1,300,xlen,25).moveTo („global“);

Page 10: Moirés with Processing

8

controlP5.addSlider(„Line_Thickness“,0.0,10.0,5.0,x1,336,xlen,25).moveTo(„global“); Controller myslider = controlP5.addSlider(„Line_Amplitude“, 0, 30, 15, x1, 372, xlen, 25); myslider.moveTo(„global“); myslider.setId(1); controlP5.addSlider(„Line_Resolution“,0,25,25,x1,408,xlen,25).moveTo(„global“); Numberbox mynumberbox = controlP5.addNumberbox( „Line_Angle“, 0.0, x1, 444, xlen, 25 ); mynumberbox.moveTo(„global“); mynumberbox.setMultiplier(0.01); controlP5.setColorLabel(0x000000); controlP5.setColorBackground(127); controlP5.setColorForeground(0); controlP5.setColorActive(200);}

void controlEvent(ControlEvent theEvent) { switch(theEvent.id()) { case(1): initializeform(); break; case(2): Color_Mode = 1; //Solid break; case(3): Color_Mode = 2; //Gradient break; case(4): Color_Mode = 3; //Rainbow_Gradient break; }}

void draw(){ strokeWeight(Line_Thickness); // floating towards mouse position if (mouseX != 0 || mouseY != 0) { centerX += (mouseX-centerX) * 0.1; centerY += (mouseY-centerY) * 0.1; } noFill();

Page 11: Moirés with Processing

9

controlP5.addSlider(„Line_Thickness“,0.0,10.0,5.0,x1,336,xlen,25).moveTo(„global“); Controller myslider = controlP5.addSlider(„Line_Amplitude“, 0, 30, 15, x1, 372, xlen, 25); myslider.moveTo(„global“); myslider.setId(1); controlP5.addSlider(„Line_Resolution“,0,25,25,x1,408,xlen,25).moveTo(„global“); Numberbox mynumberbox = controlP5.addNumberbox( „Line_Angle“, 0.0, x1, 444, xlen, 25 ); mynumberbox.moveTo(„global“); mynumberbox.setMultiplier(0.01); controlP5.setColorLabel(0x000000); controlP5.setColorBackground(127); controlP5.setColorForeground(0); controlP5.setColorActive(200);}

void controlEvent(ControlEvent theEvent) { switch(theEvent.id()) { case(1): initializeform(); break; case(2): Color_Mode = 1; //Solid break; case(3): Color_Mode = 2; //Gradient break; case(4): Color_Mode = 3; //Rainbow_Gradient break; }}

void draw(){ strokeWeight(Line_Thickness); // floating towards mouse position if (mouseX != 0 || mouseY != 0) { centerX += (mouseX-centerX) * 0.1; centerY += (mouseY-centerY) * 0.1; } noFill();

Page 12: Moirés with Processing

10

grad_Y = map(mouseY, 0, height, 0.0, 1.0);

switch(Color_Mode) { case(1): //Solid stroke(cp_solid.getColorValue()); break; case(2): //Gradient colorMode(RGB); if (Flip_Gradient = = false) stroke(lerpColor(color(cp_grad1.getColorValue()), color(cp_grad2.getColorValue()), grad_Y)); else stroke(lerpColor(color(cp_grad2.getColorValue()), color(cp_grad1.getColorValue()), grad_Y)); break; case(3): //Rainbow_Gradient colorMode(HSB, 100); if (Flip_Rainbow = = false) stroke(lerpColor(color(cp_rgrad1.getColorValue()), color(cp_rgrad2.getColorValue()), grad_Y)); else stroke(lerpColor(color(cp_rgrad2.getColorValue()), color(cp_rgrad1.getColorValue()), grad_Y)); break; } if (drawing = = true) { beginShape(); // start controlpoint curveVertex(x[0]+centerX, y[0]+centerY);

// only these points are drawn for (int i=0; i<Line_Resolution; i++){ curveVertex(x[i]+centerX, y[i]+centerY); }

// end controlpoint curveVertex(x[Line_Resolution-1]+centerX, y[Line_Resolution-1] +centerY); endShape(); }}

Page 13: Moirés with Processing

11

grad_Y = map(mouseY, 0, height, 0.0, 1.0);

switch(Color_Mode) { case(1): //Solid stroke(cp_solid.getColorValue()); break; case(2): //Gradient colorMode(RGB); if (Flip_Gradient = = false) stroke(lerpColor(color(cp_grad1.getColorValue()), color(cp_grad2.getColorValue()), grad_Y)); else stroke(lerpColor(color(cp_grad2.getColorValue()), color(cp_grad1.getColorValue()), grad_Y)); break; case(3): //Rainbow_Gradient colorMode(HSB, 100); if (Flip_Rainbow = = false) stroke(lerpColor(color(cp_rgrad1.getColorValue()), color(cp_rgrad2.getColorValue()), grad_Y)); else stroke(lerpColor(color(cp_rgrad2.getColorValue()), color(cp_rgrad1.getColorValue()), grad_Y)); break; } if (drawing = = true) { beginShape(); // start controlpoint curveVertex(x[0]+centerX, y[0]+centerY);

// only these points are drawn for (int i=0; i<Line_Resolution; i++){ curveVertex(x[i]+centerX, y[i]+centerY); }

// end controlpoint curveVertex(x[Line_Resolution-1]+centerX, y[Line_Resolution-1] +centerY); endShape(); }}

Page 14: Moirés with Processing

12

void mousePressed() { if(mouseX<x1&&mouseY>200){ drawing = !drawing; if (drawing = = true) initializeform(); }}

void keyReleased() { if (key = = ‚s‘ || key = = ‚S‘) saveFrame(timestamp()+“_##.png“); if (key = = DELETE || key = = BACKSPACE) { background(#ffffff); }}

String timestamp() {Calendar now = Calendar.getInstance();return String.format(„%1$ty%1$tm%1$td_%1$tH%1$tM%1$tS“, now);}

Page 15: Moirés with Processing

void mousePressed() { if(mouseX<x1&&mouseY>200){ drawing = !drawing; if (drawing = = true) initializeform(); }}

void keyReleased() { if (key = = ‚s‘ || key = = ‚S‘) saveFrame(timestamp()+“_##.png“); if (key = = DELETE || key = = BACKSPACE) { background(#ffffff); }}

String timestamp() {Calendar now = Calendar.getInstance();return String.format(„%1$ty%1$tm%1$td_%1$tH%1$tM%1$tS“, now);}

Page 16: Moirés with Processing

14

KINECT MOI RÉZEICHNER

Page 17: Moirés with Processing

15

KINECT MOI RÉZEICHNER

Page 18: Moirés with Processing

0

2

4

Page 19: Moirés with Processing

1

3

5

Page 20: Moirés with Processing

0

2

4

Page 21: Moirés with Processing

1

3

5

Page 22: Moirés with Processing

20

P ro c e s s i n g – P ro g ra m m , K i n e c t A u g u s t – S e p t e m b e r 2 0 11

Elastische Linien werden Bewe-gungen entsprechend hinzugefügt und beschleunigt.

Ich benutze die Bibliotheken »die-wald_CV_kit« für Kinect und »toxiclibs« für die elastischen Linien.

Subtrahiere die aktuelle Kontur eines Körpers von seiner letzten Kontur. Die Dif-ferenz ergibt die Geschwindigkeit der neuen Linien. Befindet sich an dieser Position der x Achse schon eine elastische Linie? Wenn ja, ist die jetzige Körperkontur an dieser x–Stelle oberhalb der elastischen Linie? Wenn ja, lösch die Linie und erstelle eine neue an aktueller Position. Lass Linien verschwinden wenn sie ein be-stimmtes »Alter« erreichen. Füge sie hinzu nur in einem festgelegten Raster.

K i n e c t M o i r é Z e i c h n e r

Page 23: Moirés with Processing

21

import processing.opengl.*;import diewald_CV_kit.libraryinfo.*;import diewald_CV_kit.utility.*;import diewald_CV_kit.blobdetection.*;import dLibs.freenect.*;import dLibs.freenect.constants.*;import dLibs.freenect.interfaces.*;

PFont font;ConvexHullDiwi convex_hull;

// kinectKinect kinect_; KinectFrameVideo kinect_video_; KinectFrameDepth kinect_depth_; KinectTilt kinect_tilt_;

// get width/height --> actually its always 640 x 480int size_x = VIDEO_FORMAT._RGB_.getWidth(); int size_y = VIDEO_FORMAT._RGB_.getHeight(); PImage video_frame_, depth_frame_; // images

// blob detection BlobDetector blob_detector;BoundingBox detection_area;int detection_resolution = 4;boolean draw_blobs_boundingsbox = false;boolean draw_filled_blobs = false;

// strings (lines)import toxi.physics2d.constraints.*;import toxi.physics2d.behaviors.*;import toxi.physics2d.*;import toxi.geom.*;import toxi.math.*;

int NUM_STRINGS = 200;int STEP = 4;int STRING_RES = 5;int STRING_LENGTH = 133;

Page 24: Moirés with Processing

22

int ANGLE = 91;float MASS = 10.0;float STRENGTH = 2.0; int TOUCHINGDISTANCE = 25;int MAX_AGE=100;int STRKWEIGHT=3;

//velocity vector of moving object in front of camera Vec2D delta;float particleSize = 5;VerletParticle2D selectedP;

ArrayList<ParticleString2DAging> strings = new ArrayList<ParticleString2DAging>();

VerletPhysics2D phys;Vec2D mousePos = new Vec2D(mouseX,mouseY);

ArrayList<ArrayList<Pixel>> last_pixels_list = new ArrayList< ArrayList<Pixel>>();ArrayList<Pixel> last_pixels = new ArrayList<Pixel>();ArrayList<Pixel> current_pixels = new ArrayList<Pixel>();

ArrayList<BoundingBox> bb_list = new ArrayList<BoundingBox>();BoundingBox last_bb = new BoundingBox();BoundingBox curr_bb = new BoundingBox();

public void setup() { size(screenWidth, screenHeight, OPENGL); phys = new VerletPhysics2D(); // KINECT STUFF - initialization kinect_ = new Kinect(0); //create a main kinect instance with index 0 kinect_video_ = new KinectFrameVideo(VIDEO_FORMAT._RGB_ ); // create a video instance, RGB kinect_depth_ = new KinectFrameDepth(DEPTH_FORMAT._11BIT_); // create a depth instance kinect_tilt_ = new KinectTilt(); // create a Tilt instance kinect_video_.setFrameRate(30); kinect_depth_.setFrameRate(30); kinect_video_.connect(kinect_); kinect_depth_.connect(kinect_); kinect_tilt_ .connect(kinect_); // connect Tilt to Kinect kinect_tilt_.setTiltDegrees(10); // set tilt degrees // create a PImage for video/depth video_frame_ = createImage(VIDEO_FORMAT._RGB_ .getWidth(), VIDEO_FORMAT._RGB_.getHeight(), RGB); depth_frame_ = createImage(DEPTH_FORMAT._11BIT_.getWidth(), DEPTH_FORMAT._11BIT_.getHeight(), RGB);

Page 25: Moirés with Processing

23

int ANGLE = 91;float MASS = 10.0;float STRENGTH = 2.0; int TOUCHINGDISTANCE = 25;int MAX_AGE=100;int STRKWEIGHT=3;

//velocity vector of moving object in front of camera Vec2D delta;float particleSize = 5;VerletParticle2D selectedP;

ArrayList<ParticleString2DAging> strings = new ArrayList<ParticleString2DAging>();

VerletPhysics2D phys;Vec2D mousePos = new Vec2D(mouseX,mouseY);

ArrayList<ArrayList<Pixel>> last_pixels_list = new ArrayList< ArrayList<Pixel>>();ArrayList<Pixel> last_pixels = new ArrayList<Pixel>();ArrayList<Pixel> current_pixels = new ArrayList<Pixel>();

ArrayList<BoundingBox> bb_list = new ArrayList<BoundingBox>();BoundingBox last_bb = new BoundingBox();BoundingBox curr_bb = new BoundingBox();

public void setup() { size(screenWidth, screenHeight, OPENGL); phys = new VerletPhysics2D(); // KINECT STUFF - initialization kinect_ = new Kinect(0); //create a main kinect instance with index 0 kinect_video_ = new KinectFrameVideo(VIDEO_FORMAT._RGB_ ); // create a video instance, RGB kinect_depth_ = new KinectFrameDepth(DEPTH_FORMAT._11BIT_); // create a depth instance kinect_tilt_ = new KinectTilt(); // create a Tilt instance kinect_video_.setFrameRate(30); kinect_depth_.setFrameRate(30); kinect_video_.connect(kinect_); kinect_depth_.connect(kinect_); kinect_tilt_ .connect(kinect_); // connect Tilt to Kinect kinect_tilt_.setTiltDegrees(10); // set tilt degrees // create a PImage for video/depth video_frame_ = createImage(VIDEO_FORMAT._RGB_ .getWidth(), VIDEO_FORMAT._RGB_.getHeight(), RGB); depth_frame_ = createImage(DEPTH_FORMAT._11BIT_.getWidth(), DEPTH_FORMAT._11BIT_.getHeight(), RGB);

Page 26: Moirés with Processing

24

// BLOB DETECTION STUFF - initialization blob_detector = new BlobDetector(size_x, size_y); blob_detector.setResolution(detection_resolution); blob_detector.computeContours(true); blob_detector.computeBlobPixels(!true); blob_detector.setMinMaxPixels(10*10, size_x*size_y); blob_detector.setBLOBable( new BLOBable_Kinect_2D(this).setKinectDepth(kinect_depth_)); detection_area = new BoundingBox(0, 0, size_x, size_y); blob_detector.setDetectingArea(detection_area); frameRate(200);}

public void draw() { strokeWeight(STRKWEIGHT); scale(3.0); background(255); stroke(0); phys.update(); //vertical static lines for(int i=0; i<1000; i+=STEP){ line(i,0,i,height); } //draw moving lines for(VerletSpring2D s: phys.springs){ line(s.a.x,s.a.y,s.b.x,s.b.y); } noFill(); rect( detection_area.xMin(), detection_area.yMin(), detection_area.xSize()-1, detection_area.ySize()-1 ); // set resolution - improves speed a lot blob_detector.setResolution(detection_resolution); blob_detector.update(); ArrayList<Blob> blob_list = blob_detector.getBlobs(); for (int blob_idx = 0; blob_idx < blob_list.size(); blob_idx++ ) { Blob blob = blob_list.get(blob_idx); ArrayList<Contour> contour_list = blob.getContours(); for ( int contour_idx = 0; contour_idx < contour_list.size(); contour_idx++ ) { Contour contour = contour_list.get(contour_idx); BoundingBox bb = contour.getBoundingBox(); // draw the outer contours if ( contour_idx = = 0) { //Save last and current BoundingBox to compare them to see if body has moved.

Page 27: Moirés with Processing

25

// BLOB DETECTION STUFF - initialization blob_detector = new BlobDetector(size_x, size_y); blob_detector.setResolution(detection_resolution); blob_detector.computeContours(true); blob_detector.computeBlobPixels(!true); blob_detector.setMinMaxPixels(10*10, size_x*size_y); blob_detector.setBLOBable( new BLOBable_Kinect_2D(this).setKinectDepth(kinect_depth_)); detection_area = new BoundingBox(0, 0, size_x, size_y); blob_detector.setDetectingArea(detection_area); frameRate(200);}

public void draw() { strokeWeight(STRKWEIGHT); scale(3.0); background(255); stroke(0); phys.update(); //vertical static lines for(int i=0; i<1000; i+=STEP){ line(i,0,i,height); } //draw moving lines for(VerletSpring2D s: phys.springs){ line(s.a.x,s.a.y,s.b.x,s.b.y); } noFill(); rect( detection_area.xMin(), detection_area.yMin(), detection_area.xSize()-1, detection_area.ySize()-1 ); // set resolution - improves speed a lot blob_detector.setResolution(detection_resolution); blob_detector.update(); ArrayList<Blob> blob_list = blob_detector.getBlobs(); for (int blob_idx = 0; blob_idx < blob_list.size(); blob_idx++ ) { Blob blob = blob_list.get(blob_idx); ArrayList<Contour> contour_list = blob.getContours(); for ( int contour_idx = 0; contour_idx < contour_list.size(); contour_idx++ ) { Contour contour = contour_list.get(contour_idx); BoundingBox bb = contour.getBoundingBox(); // draw the outer contours if ( contour_idx = = 0) { //Save last and current BoundingBox to compare them to see if body has moved.

Page 28: Moirés with Processing

26

bb_list.add(contour.getBoundingBox()); if (bb_list.size()= =2){ last_bb = bb_list.get(0); curr_bb = bb_list.get(1); bb_list.clear(); } //Save last and current Contours to substract them to accelerate added lines. last_pixels_list.add(contour.getPixels()); if (last_pixels_list.size()= =2){ last_pixels = last_pixels_list.get(0); current_pixels = last_pixels_list.get(1); last_pixels_list.clear(); } drawContour(contour.getPixels(),color(0), color(0, 150),draw_filled_blobs, 3); ConvexHullDiwi convex_hull = new ConvexHullDiwi(); // calculate the convex hull, based on the contour-list convex_hull.update(contour.getPixels()); drawParticleStrings(convex_hull, color(255)); if(last_pixels!=null && last_bb!=null){ if(BoundingBoxMoves(curr_bb, last_bb)){ //make sure "ArrayList<Pixel> current_pixels" has same size as "ArrayList<Pixel> last_pixels" to prepare for subtraction current_pixels = equalize_size(current_pixels, last_pixels); //does the contour of "ArrayList<Pixel> current_pixels" touch the particles of "ArrayList<ParticleString2DAging> ParticleStrings"? ContourTouchesParticle(current_pixels, strings); } } } } } if (strings.size()>0){ for(int ix = 0; ix < strings.size(); ix++){ ParticleString2DAging s = strings.get(ix); //increase the ParticleString's age s.update(); if(!(s.isAlive())){ //DIE, ParticleString, DIE! s.clear(); //remove it from strings

Page 29: Moirés with Processing

27

bb_list.add(contour.getBoundingBox()); if (bb_list.size()= =2){ last_bb = bb_list.get(0); curr_bb = bb_list.get(1); bb_list.clear(); } //Save last and current Contours to substract them to accelerate added lines. last_pixels_list.add(contour.getPixels()); if (last_pixels_list.size()= =2){ last_pixels = last_pixels_list.get(0); current_pixels = last_pixels_list.get(1); last_pixels_list.clear(); } drawContour(contour.getPixels(),color(0), color(0, 150),draw_filled_blobs, 3); ConvexHullDiwi convex_hull = new ConvexHullDiwi(); // calculate the convex hull, based on the contour-list convex_hull.update(contour.getPixels()); drawParticleStrings(convex_hull, color(255)); if(last_pixels!=null && last_bb!=null){ if(BoundingBoxMoves(curr_bb, last_bb)){ //make sure "ArrayList<Pixel> current_pixels" has same size as "ArrayList<Pixel> last_pixels" to prepare for subtraction current_pixels = equalize_size(current_pixels, last_pixels); //does the contour of "ArrayList<Pixel> current_pixels" touch the particles of "ArrayList<ParticleString2DAging> ParticleStrings"? ContourTouchesParticle(current_pixels, strings); } } } } } if (strings.size()>0){ for(int ix = 0; ix < strings.size(); ix++){ ParticleString2DAging s = strings.get(ix); //increase the ParticleString's age s.update(); if(!(s.isAlive())){ //DIE, ParticleString, DIE! s.clear(); //remove it from strings

Page 30: Moirés with Processing

28

strings.remove(ix); } } }}

public void assignPixels(PImage img, Pixelable kinect_dev) { img.loadPixels(); img.pixels = kinect_dev.getPixels(); //assign pixels of the kinect device to the image img.updatePixels();}

//the proper way to close everythingpublic void dispose() { Kinect.shutDown(); super.dispose();}

class ParticleString2DAging extends ParticleString2D{ int age; int x_co; int y_co; ParticleString2DAging(VerletPhysics2D physics, toxi.geom.Vec2D pos, toxi.geom.Vec2D step, int num, float mass, float strength){ super(physics, pos, step, num, mass, strength); age=0; x_co=(int)pos.x; y_co=(int)pos.y; } void update(){ age++; } boolean isAlive(){ return age < MAX_AGE; }}

Page 31: Moirés with Processing

29

strings.remove(ix); } } }}

public void assignPixels(PImage img, Pixelable kinect_dev) { img.loadPixels(); img.pixels = kinect_dev.getPixels(); //assign pixels of the kinect device to the image img.updatePixels();}

//the proper way to close everythingpublic void dispose() { Kinect.shutDown(); super.dispose();}

class ParticleString2DAging extends ParticleString2D{ int age; int x_co; int y_co; ParticleString2DAging(VerletPhysics2D physics, toxi.geom.Vec2D pos, toxi.geom.Vec2D step, int num, float mass, float strength){ super(physics, pos, step, num, mass, strength); age=0; x_co=(int)pos.x; y_co=(int)pos.y; } void update(){ age++; } boolean isAlive(){ return age < MAX_AGE; }}

Page 32: Moirés with Processing

30

public void drawParticleStrings(ConvexHullDiwi convex_hull, int fill_color) { noFill(); DoubleLinkedList<Pixel> convex_hull_list = convex_hull.get(); convex_hull_list.gotoFirst(); beginShape(); for (int cvh_idx = 0; cvh_idx < convex_hull_list.size()+1; cvh_idx++, convex_hull_list.gotoNext() ) { Pixel p = convex_hull_list.getCurrentNode().get(); Vec2D dir=new Vec2D(STRING_LENGTH,radians(ANGLE)).toCartesian(); //Make x coordinate a number that is x%step= =0, so new added ParticleStrings fit the vertical ones in the background. int mod = p.x_%STEP; int px = p.x_-mod; if(!stringExistent(px)){ ParticleString2DAging string = new ParticleString2DAging( phys, new Vec2D(px,p.y_),dir,STRING_RES,MASS,STRENGTH); string.getHead().lock(); string.getTail().lock(); if (delta!=null){ for(VerletParticle2D par : string.particles){ par.addVelocity(delta); } } strings.add(string); } else{ //if ParticleString at x already exists; check if new position is above, if so delete previous string and create new higher string if(stringHigher(px,p.y_)){ ParticleString2DAging string = new ParticleString2DAging( phys, new Vec2D(px,p.y_),dir,STRING_RES,MASS,STRENGTH); string.getHead().lock(); string.getTail().lock(); if (delta!=null){ for(VerletParticle2D par : string.particles){ par.addVelocity(delta); } } strings.add(string); } } } endShape();}

Page 33: Moirés with Processing

31

public void drawParticleStrings(ConvexHullDiwi convex_hull, int fill_color) { noFill(); DoubleLinkedList<Pixel> convex_hull_list = convex_hull.get(); convex_hull_list.gotoFirst(); beginShape(); for (int cvh_idx = 0; cvh_idx < convex_hull_list.size()+1; cvh_idx++, convex_hull_list.gotoNext() ) { Pixel p = convex_hull_list.getCurrentNode().get(); Vec2D dir=new Vec2D(STRING_LENGTH,radians(ANGLE)).toCartesian(); //Make x coordinate a number that is x%step= =0, so new added ParticleStrings fit the vertical ones in the background. int mod = p.x_%STEP; int px = p.x_-mod; if(!stringExistent(px)){ ParticleString2DAging string = new ParticleString2DAging( phys, new Vec2D(px,p.y_),dir,STRING_RES,MASS,STRENGTH); string.getHead().lock(); string.getTail().lock(); if (delta!=null){ for(VerletParticle2D par : string.particles){ par.addVelocity(delta); } } strings.add(string); } else{ //if ParticleString at x already exists; check if new position is above, if so delete previous string and create new higher string if(stringHigher(px,p.y_)){ ParticleString2DAging string = new ParticleString2DAging( phys, new Vec2D(px,p.y_),dir,STRING_RES,MASS,STRENGTH); string.getHead().lock(); string.getTail().lock(); if (delta!=null){ for(VerletParticle2D par : string.particles){ par.addVelocity(delta); } } strings.add(string); } } } endShape();}

Page 34: Moirés with Processing

32

public void drawContour(ArrayList<Pixel> pixel_list, int stroke_color, int fill_color, boolean fill, float stroke_weight) { stroke(stroke_color); strokeWeight(stroke_weight); beginShape(); for (int idx = 0; idx < pixel_list.size(); idx+=2) { Pixel p = pixel_list.get(idx); vertex(p.x_, p.y_); } endShape();}

boolean BoundingBoxMoves(BoundingBox curr_bb, BoundingBox last_bb){ int numm = curr_bb.xMin() - last_bb.xMin(); println (abs(numm)); if (abs(numm)>7){ return true; } int nums = curr_bb.xSize() - last_bb.xSize(); return (abs(nums)>7);}

ArrayList<Pixel> equalize_size(ArrayList<Pixel> currp_list, ArrayList<Pixel> lastp_list){ if(currp_list.size()>lastp_list.size()){ currp_list.subList(lastp_list.size(),currp_list.size()).clear(); } return currp_list;}

Vec2D ContourDeltaLoc(Pixel current_pixel, Pixel last_pixel){ Vec2D cpvec = new Vec2D(current_pixel.x_,current_pixel.y_); Vec2D lpvec = new Vec2D(last_pixel.x_,last_pixel.y_); cpvec.subSelf(lpvec); return cpvec;}

void ContourTouchesParticle(ArrayList<Pixel> pixel_list, ArrayList<ParticleString2DAging> strings_list){ for(int ix = 0; ix < pixel_list.size(); ix++){ Pixel p = pixel_list.get(ix); mousePos.set(p.x_,p.y_); for(ParticleString2DAging s: strings_list){ for(int i = 1 ; i < STRING_RES ; i++){

Page 35: Moirés with Processing

33

public void drawContour(ArrayList<Pixel> pixel_list, int stroke_color, int fill_color, boolean fill, float stroke_weight) { stroke(stroke_color); strokeWeight(stroke_weight); beginShape(); for (int idx = 0; idx < pixel_list.size(); idx+=2) { Pixel p = pixel_list.get(idx); vertex(p.x_, p.y_); } endShape();}

boolean BoundingBoxMoves(BoundingBox curr_bb, BoundingBox last_bb){ int numm = curr_bb.xMin() - last_bb.xMin(); println (abs(numm)); if (abs(numm)>7){ return true; } int nums = curr_bb.xSize() - last_bb.xSize(); return (abs(nums)>7);}

ArrayList<Pixel> equalize_size(ArrayList<Pixel> currp_list, ArrayList<Pixel> lastp_list){ if(currp_list.size()>lastp_list.size()){ currp_list.subList(lastp_list.size(),currp_list.size()).clear(); } return currp_list;}

Vec2D ContourDeltaLoc(Pixel current_pixel, Pixel last_pixel){ Vec2D cpvec = new Vec2D(current_pixel.x_,current_pixel.y_); Vec2D lpvec = new Vec2D(last_pixel.x_,last_pixel.y_); cpvec.subSelf(lpvec); return cpvec;}

void ContourTouchesParticle(ArrayList<Pixel> pixel_list, ArrayList<ParticleString2DAging> strings_list){ for(int ix = 0; ix < pixel_list.size(); ix++){ Pixel p = pixel_list.get(ix); mousePos.set(p.x_,p.y_); for(ParticleString2DAging s: strings_list){ for(int i = 1 ; i < STRING_RES ; i++){

Page 36: Moirés with Processing

34

VerletParticle2D par = s.particles.get(i); if(mousePos.distanceTo(par) < TOUCHINGDISTANCE) { delta = ContourDeltaLoc(pixel_list.get(ix), last_pixels.get(ix)); } } } }}//check to see if specific y-coordinate is higher at specific x-coordinate if it is, delete lower ParticleStringboolean stringHigher(int px, int py){ boolean higher = false; if (strings.size()>0){ for(int ix = 0; ix < strings.size(); ix++){ ParticleString2DAging s = strings.get(ix); if (s.x_co= =px){ if (s.y_co>py){ //clear string from phys s.clear(); //clear it from strings list strings.remove(ix); higher = true; continue; } } } } return higher; }

boolean stringExistent(int px){ boolean existent = false; if (strings.size()>0){ for(ParticleString2DAging s: strings){ if (s.x_co= =px){ existent = true; continue; } } } return existent; }

Page 37: Moirés with Processing

35

VerletParticle2D par = s.particles.get(i); if(mousePos.distanceTo(par) < TOUCHINGDISTANCE) { delta = ContourDeltaLoc(pixel_list.get(ix), last_pixels.get(ix)); } } } }}//check to see if specific y-coordinate is higher at specific x-coordinate if it is, delete lower ParticleStringboolean stringHigher(int px, int py){ boolean higher = false; if (strings.size()>0){ for(int ix = 0; ix < strings.size(); ix++){ ParticleString2DAging s = strings.get(ix); if (s.x_co= =px){ if (s.y_co>py){ //clear string from phys s.clear(); //clear it from strings list strings.remove(ix); higher = true; continue; } } } } return higher; }

boolean stringExistent(int px){ boolean existent = false; if (strings.size()>0){ for(ParticleString2DAging s: strings){ if (s.x_co= =px){ existent = true; continue; } } } return existent; }

Page 38: Moirés with Processing