MOIRÉS 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
1
//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 y[i] = lerp(y1, y2, i/(float)Line_Resolution) + random(-Line_Amplitude
4
Simple Moiré Zeichner P r o c e s s i n g – P r o g r a m m , J u l i 2 0 11 Ein Klick und horizontale Linien erscheinen 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änge, Stärke, Amplitude, Winkel.
e,Line_Amplitude); e,Line_Amplitude);
5
} } 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, cp_solid.setArrayValue(new float[] {255,0,0,255});
cp_grad1 = controlP5.addColorPicker(„Gradient_Color_Picker_1“, x1, 50 cp_grad1.setArrayValue(new float[] {0,255,0,255}); cp_grad1.moveTo(„Gradient“); cp_grad2 = controlP5.addColorPicker(„Gradient_Color_Picker_2“, x1, 12 cp_grad2.setArrayValue(new float[] {255,0,0,255}); cp_grad2.moveTo(„Gradient“);
cp_rgrad1 = controlP5.addColorPicker(„Rainbow_Gradient_Color_Picke cp_rgrad1.setArrayValue(new float[] {255,0,0,255}); cp_rgrad1.moveTo(„Rainbow_Gradient“); cp_rgrad2 = controlP5.addColorPicker(„Rainbow_Gradient_Color_Picke cp_rgrad2.setArrayValue(new float[] {255,0,255,255}); cp_rgrad2.moveTo(„Rainbow_Gradient“);
controlP5.addToggle(„Flip_Rainbow“,false,x1,190,25,25).moveTo(„ Rainb controlP5.addToggle(„Flip_Gradient“,false,x1,190,25,25).moveTo(„Gradi
controlP5.addSlider(„Line_Length“,0,500,250.0,x1,300,xlen,25).moveTo (
6
0);
0, xlen, 0);
20, xlen, 0);
er_1“, x1, 50, xlen, 0);
er_2“, x1, 120, xlen, 0);
bow_Gradient“); ient“);
(„global“);
7
controlP5.addSlider(„Line_Thickness“,0.0,10.0,5.0,x1,336,xlen,25).moveT Controller myslider = controlP5.addSlider(„Line_Amplitude“, 0, 30, 15, x myslider.moveTo(„global“); myslider.setId(1); controlP5.addSlider(„Line_Resolution“,0,25,25,x1,408,xlen,25).moveTo(„ Numberbox mynumberbox = controlP5.addNumberbox( „Line_Angle“, 0 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();
8
To(„global“); x1, 372, xlen, 25);
„global“); 0.0, x1, 444, xlen, 25 );
9
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.get else stroke(lerpColor(color(cp_grad2.getColorValue()), color(cp_grad1.get break;
}
case(3): //Rainbow_Gradient colorMode(HSB, 100); if (Flip_Rainbow = = false) stroke(lerpColor(color(cp_rgrad1.getColorValue()), color(cp_rgrad2.ge else stroke(lerpColor(color(cp_rgrad2.getColorValue()), color(cp_rgrad1.ge 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); }
}
10
}
// end controlpoint curveVertex(x[Line_Resolution-1]+centerX, y[Line_Resolution-1] +cen endShape();
tColorValue()), grad_Y));
tColorValue()), grad_Y));
etColorValue()), grad_Y));
etColorValue()), grad_Y));
nterY);
11
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); }
12
KINECT MOI 14
RÉZEICHNER 15
0
2
4
1
3
5
0
2
4
1
3
5
Kinect Moiré Zeichner Processing–Programm, Kinect August – September 2 0 11 Elastische Linien werden Bewegungen entsprechend hinzugefügt und beschleunigt. Ich benutze die Bibliotheken »diewald_CV_kit« für Kinect und »toxiclibs« für die elastischen Linien. Subtrahiere die aktuelle Kontur eines Körpers von seiner letzten Kontur. Die Differenz 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 bestimmtes »Alter« erreichen. Füge sie hinzu nur in einem festgelegten Raster.
20
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; // kinect Kinect kinect_; KinectFrameVideo kinect_video_; KinectFrameDepth kinect_depth_; KinectTilt kinect_tilt_; // get width/height --> actually its always 640 x 480 int 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;
21
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<ParticleString VerletPhysics2D phys; Vec2D mousePos = new Vec2D(mouseX,mouseY);
ArrayList<ArrayList<Pixel>> last_pixels_list = new ArrayList<â&#x20AC;&#x2020;ArrayList< 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_ ); // c kinect_depth_ = new KinectFrameDepth(DEPTH_FORMAT._11BIT_); // c 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(), VID depth_frame_ = createImage(DEPTH_FORMAT._11BIT_.getWidth(), DEP
22
g2DAging>();
<Pixel>>();
create a video instance, RGB create a depth instance
DEO_FORMAT._RGB_.getHeight(), RGB); PTH_FORMAT._11BIT_.getHeight(), RGB);
23
}
// 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).setKinectD 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 // 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 b
24
Depth(kinect_depth_));
e()-1, detection_area.ySize()-1 );
x++ ) {
body has moved.
25
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 ad 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_b 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 " current_pixels = equalize_size(current_pixels, last_pixels); //does the contour of "ArrayList<Pixel> current_pixels" touch the p 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
26
dded lines.
blobs, 3);
"ArrayList<Pixel> last_pixels" to prepare for subtraction
particles of "ArrayList<ParticleString2DAging> ParticleStrings"?
27
}
}
}
}
strings.remove(ix);
public void assignPixels(PImage img, Pixelable kinect_dev) { img.loadPixels(); img.pixels = kinect_dev.getPixels(); //assign pixels of the kinect devic img.updatePixels(); } //the proper way to close everything public 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, t super(physics, pos, step, num, mass, strength); age=0; x_co=(int)pos.x; y_co=(int)pos.y; } void update(){ age++; }
}
28
boolean isAlive(){ return age < MAX_AGE; }
ce to the image
toxi.geom.Vec2D step, int num, float mass, float strength){
29
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++, con 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=â&#x20AC;&#x2020;=0, so new added Part int mod = p.x_%STEP; int px = p.x_-mod; if(!stringExistent(px)){ ParticleString2DAging string = new ParticleString2DAging( phys, n 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 if(stringHigher(px,p.y_)){ ParticleString2DAging string = new ParticleString2DAging( phys, n string.getHead().lock(); string.getTail().lock(); if (delta!=null){ for(VerletParticle2D par : string.particles){ par.addVelocity(delta); } } strings.add(string); } } } endShape(); }
30
r) {
nvex_hull_list.gotoNext() ) {
n(); ticleStrings fit the vertical ones in the background.
new Vec2D(px,p.y_),dir,STRING_RES,MASS,STRENGTH);
so delete previous string and create new higher string
new Vec2D(px,p.y_),dir,STRING_RES,MASS,STRENGTH);
31
public void drawContour(ArrayList<Pixel> pixel_list, int stroke_color,â&#x20AC;&#x2020;int f 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<Pix 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<Partic 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++){
32
fill_color, boolean fill, float stroke_weight) {
b){
xel> lastp_list){
cleString2DAging> strings_list){
33
}
}
}
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 boolean 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=â&#x20AC;&#x2020;=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=â&#x20AC;&#x2020;=px){ existent = true; continue; } } } return existent; }
34
â&#x20AC;&#x2020;if it is, delete lower ParticleString
35