The starting point for the illustrations of the focus are prototypical museum objects: the Mona Lisa as THE work of art, the Venus of Willendorf as THE historical artifact, herbarium voucher, butterfly and the skeleton of a Triceratops stand for the extensive collections of natural history museums, the light bulb for technical collections, the coin with the image of Hadrian for history museums.

For the visualization, significant points of the object shape were first determined algorithmically by comparing image points based on their color and contrast values. These form-giving points then serve as material for the visual reconstruction of the object according to formalized rules. Variations are created by randomly modifying these rules and each new execution creates a visual instance of the object. In Mark Taylor’s work, a particular variance is found: the image of a coin generates itself from the words of his text. The abstract and inevitably fuzzy glimpses thus generated complement those of the authors into a future that can at best be guessed at.

Generators: Venus of Willendorf

				
					// ––––––––––––––––––––––––––––––––––––––––––––––––––––––––
// Venus of Willendorf
// 
// Andreas Pirchner, 2014
// ––––––––––––––––––––––––––––––––––––––––––––––––––––––––

import processing.pdf.*;
import controlP5.*;

float[][] kernel = {{ -1, -1, -1}, 
                    { -1,  9, -1}, 
                    { -1, -1, -1}};

int nodesUsed = 1000; 
float valRed;
float valBlue;
float valGreen;
int nodeCount = 0; 
int maxConnect = 10;
float currentDistance = 0;
PImage img;
int nodeLoop = 1;


PVector[] nodes = new PVector[1000*1000];
int[] connections = new int[1000*1000];
color[] nodeColors = new color[1000*1000];
boolean [] visible = new boolean[1000*1000];


ControlP5 cp5;
CheckBox RecordPDF;

boolean recording = false;
boolean saveNow = false;
boolean justDrawn = false;
int saveCount = 0;

int dotAmount;
int lineLength;
int transp;
int ellipseRadius;

boolean startDraw = true;

void setup() { 
  size(2000, 2000);
  img = loadImage("venusblack2.jpg"); // Load the original image
  image(img,500,0);
  
  for (int i=0; i< nodes.length; i++) {
      nodes[i] = new PVector(0,0);
  } 
  for(int m=0; m < connections.length; m++){
     connections[m] = 0; 
     nodeColors[m] = color(0,0,0); 
     visible[m] = false;
  }
  
  cp5 = new ControlP5(this);
  cp5.addSlider("dotAmount")
     .setPosition(20,50)
     .setRange(50,45000)
     .setValue(2000)
     .setLabel("Number of Dots")
     .setColorLabel(color(0))
     ;
     
  cp5.addSlider("lineLength")
     .setPosition(20,70)
     .setRange(0,1000)
     .setValue(450)
     .setLabel("Length of lines")
     .setColorLabel(color(0))
     ;
  
  cp5.addSlider("transp")
     .setPosition(20,90)
     .setRange(0,255)
     .setValue(10)
     .setLabel("Transparency")
     .setColorLabel(color(0))
     ;
     
  cp5.addSlider("ellipseRadius")
     .setPosition(20,110)
     .setRange(1,20)
     .setValue(4)
     .setLabel("Ellipse Radius")
     .setColorLabel(color(0))
     ;
     
  cp5.addSlider("dotsRandom")
     .setPosition(20,130)
     .setRange(0,100)
     .setLabel("Random deviation of used Dots")
     .setColorLabel(color(0))
     ;

     
  cp5.addBang("bangSave")
       .setPosition(20, 150)
       .setSize(10, 10)
       .setLabel("Export PDF")
       .setColorLabel(color(0))
       ;
  
  img.loadPixels();
  
  for (int y = 1; y < img.height-1; y++) { // Skip top and bottom edges
    for (int x = 1; x < img.width-1; x++) { // Skip left and right edges
      float sum = 0; // Kernel sum for this pixel
      float sumRed = 0; // Kernel sum for this pixel
      float sumGreen = 0; // Kernel sum for this pixel
      float sumBlue = 0; // Kernel sum for this pixel
      
      for (int ky = -1; ky <= 1; ky++) {
        for (int kx = -1; kx <= 1; kx++) {
          // Calculate the adjacent pixel for this kernel point
          int pos = (y + ky)*img.width + (x + kx);
          // Image is grayscale, red/green/blue are identical
           valRed = red(img.pixels[pos]);
           valGreen = green(img.pixels[pos]);
           valBlue = blue(img.pixels[pos]);
           
          // Multiply adjacent pixels based on the kernel values
          sumRed += kernel[ky+1][kx+1] * valRed;
          sumGreen += kernel[ky+1][kx+1] * valGreen;
          sumBlue += kernel[ky+1][kx+1] * valBlue;
        }
      }
      
      // Kantenpunkte in Array ablegen: x-Position, y-Position, Farbe
      if (sumRed > 400 || sumBlue > 90 || sumGreen > 200 ) {
        
         nodeCount ++;
         nodes[nodeCount].x = x+500;
         nodes[nodeCount].y = y; 
         //if (valRed < 50){ valRed = 50;}
         nodeColors[nodeCount] = color(valRed,valGreen, valBlue,255);      
        
      }
      
    }
  }
  background(255);
}

void draw() {

  if(startDraw == true){
        resetCanvas();
        drawStructure();
        startDraw = false;     
  }
}

void drawStructure() {
  while (nodeLoop < dotAmount){
        int nextPoint = int(random(nodeCount));
        if (visible[nextPoint] != true){
            visible[nextPoint] = true;
            nodeLoop ++;
            strokeWeight(1);
           
            stroke(red(nodeColors[nextPoint]), red(nodeColors[nextPoint])/3, red(nodeColors[nextPoint])*2/3,transp);
            
            line(nodes[nextPoint].x, nodes[nextPoint].y, nodes[nextPoint].x+random(-lineLength,lineLength), nodes[nextPoint].y+random(150,lineLength));
            strokeWeight(0);
            
            fill(red(nodeColors[nextPoint])*2, red(nodeColors[nextPoint])*1, red(nodeColors[nextPoint])*1, 200 );
            
            ellipse(nodes[nextPoint].x+(levyDistribution(0,0.1)*20),nodes[nextPoint].y,random(2,ellipseRadius),random(2,ellipseRadius));
        }
    }
}


void resetCanvas(){
      background(255);
      nodeLoop = 0;
      print(dotAmount);
}


// Function for Record-Bang
void bangSave() {
  resetCanvas();
  beginRecord(PDF, "DAL_dots_"+dotAmount+".pdf");
  drawStructure(); 
  endRecord();
}


// Function for Amount-Slider
void dotAmount(int dA) {
  //background(255);
  dotAmount = dA;
  startDraw = true; 
}

void lineLength(int lL) {
  lineLength = lL;
  startDraw = true; 
}

void transp(int t) {
  transp = t;
  startDraw = true; 
}

void ellipseRadius(int eR) {
  ellipseRadius = eR;
  startDraw = true; 
}




// Function for Lévy-Distibution
float levyDistribution(float Wert1, float Wert2){
               float u = Wert1; // u = Lageparameter
               float c = Wert2; // s = Stauchung
               float x = 0;
               float y = 1;
               float fx = 0;
             while (y > fx) {
               x = random(10);
               y = random(1);
               fx = sqrt(c/(2*PI))*(exp(-c/(2*(x-u)))/pow((x-u), 3/2));
               //fx = 2 * exp(-2*x); Exponential
             }
             //point(x*100+200,500-y*500);
             return x;
        }






				
			

Generators: Rhizome/Lightbulb

				
					// ––––––––––––––––––––––––––––––––––––––––––––––––––––––––
// Rhizome / Lightbulb
// 
// Andreas Pirchner, 2014
// ––––––––––––––––––––––––––––––––––––––––––––––––––––––––

import processing.pdf.*;
import controlP5.*;

float[][] kernel = {{ -1, -1, -1}, 
                    { -1,  9, -1}, 
                    { -1, -1, -1}};

int nodesPossible = 1000*1000; 
float valRed;
float valBlue;
float valGreen;
int nodeCount = 0; 
int maxConnect = 10;
float currentDistance = 0;
PImage img;
//int nodeLoop = 1;
int activePoints = 0;
int startPoint = int(random(nodeCount));
int nextPoint = 0;
float bestDistance = 100;
  

IntList nodesActive = new IntList();
PVector[] nodes = new PVector[nodesPossible];
int[] connections = new int[nodesPossible];
color[] nodeColors = new color[nodesPossible];
int nodeOne = 40;
int nodeTwo;
int newNode;

ControlP5 cp5;
CheckBox RecordPDF;

int dotAmount;
int conDist;
int dotCon;

boolean startDraw = true;

void setup() { 
  size(1000, 1000);
  img = loadImage("bulb.jpg"); // Load the original image
  
  for (int i=0; i< nodes.length; i++) {
      nodes[i] = new PVector(0,0);
      connections[i] = 0; 
     nodeColors[i] = color(0,0,0); 
  } 
  
  cp5 = new ControlP5(this);
  cp5.addSlider("dotAmount")
     .setPosition(20,50)
     .setRange(50,100000)
     .setSize(600,10)
     .setValue(1000)
     .setLabel("Number of Dots")
     .setColorLabel(color(0))
     ;
     
  cp5.addSlider("conDist")
     .setPosition(20,70)
     .setRange(0,500)
     .setSize(600,10)
     .setValue(50)
     .setLabel("Range of Connectivity")
     .setColorLabel(color(0))
     ;
     
  cp5.addSlider("dotCon")
     .setPosition(20,90)
     .setRange(0,30)
     .setSize(600,10)
     .setValue(12)
     .setLabel("Connections per Dot")
     .setColorLabel(color(0))
     ;
    
  cp5.addBang("bangSave")
       .setPosition(20, 110)
       .setSize(10, 10)
       .setLabel("Export PDF")
       .setColorLabel(color(0))
       ;
  
  img.loadPixels();
  
  for (int y = 1; y < img.height-1; y++) { // Skip top and bottom edges
    for (int x = 1; x < img.width-1; x++) { // Skip left and right edges
      float sum = 0; // Kernel sum for this pixel
      float sumRed = 0; // Kernel sum for this pixel
      float sumGreen = 0; // Kernel sum for this pixel
      float sumBlue = 0; // Kernel sum for this pixel
      
      for (int ky = -1; ky <= 1; ky++) {
        for (int kx = -1; kx <= 1; kx++) {
          // Calculate the adjacent pixel for this kernel point
          int pos = (y + ky)*img.width + (x + kx);
          // Image is grayscale, red/green/blue are identical
           valRed = red(img.pixels[pos]);
           valGreen = green(img.pixels[pos]);
           valBlue = blue(img.pixels[pos]);
           
          // Multiply adjacent pixels based on the kernel values
          sumRed += kernel[ky+1][kx+1] * valRed;
          sumGreen += kernel[ky+1][kx+1] * valGreen;
          sumBlue += kernel[ky+1][kx+1] * valBlue;
        }
      }
      
      // Kantenpunkte in Array ablegen: x-Position, y-Position, Farbe
      if (sumRed > 400 || sumBlue > 90 || sumGreen > 200 ) {       
         nodeCount ++;
         nodes[nodeCount].x = x;
         nodes[nodeCount].y = y; 
         nodeColors[nodeCount] = color(valRed,valGreen, valBlue,255);              
      }      
    }
  }
  background(255);
}

void draw() {
  if(startDraw == true){
        resetCanvas();
        drawStructure();
        startDraw = false;     
  }
}

void drawStructure() {
  for (int h=10; h < nodesActive.size(); h++){
            nodeOne = nodesActive.get(h);
            for (int j=h+1; j < nodesActive.size(); j++){
              newNode = nodesActive.get(j);
              
              float abstand = nodes[nodeOne].dist(nodes[newNode]);
              if (abstand < conDist && connections[h] < dotCon && connections[j] < dotCon && nodes[nodeOne].x != 0 && nodes[newNode].x != 0){     
                connections[h] ++;
                connections[j] ++; 
                strokeWeight(1);
                stroke(red(nodeColors[nodeOne])*2, red(nodeColors[nodeOne])*1, red(nodeColors[nodeOne])*1, 100 );
                line(nodes[nodeOne].x, nodes[nodeOne].y, nodes[newNode].x, nodes[newNode].y);
              }
            }         
        }
}

void resetCanvas(){
  background(255);
  // Clear List of Connections between Nodes
      for (int h=0; h< nodesActive.size(); h++){  
        connections[h] = 0;
      }
  // Clear List of active Nodes and populate it again
      nodesActive.clear();
      for (int l=0; l< dotAmount; l++){  
        nodesActive.append(int(random(nodes.length)));
      }
      print(dotAmount);
}

// Function for Record-Bang
void bangSave() {
  resetCanvas();
  beginRecord(PDF, "RHIZOM_dots_"+dotAmount+"_range_"+conDist+"_links_"+dotCon+".pdf");
  drawStructure(); 
  endRecord();
}

// Functions for Sliders
void dotAmount(int dA) {
  //background(255);
  dotAmount = dA;
  startDraw = true; 
}

void conDist(int cD) {
  conDist = cD;
  startDraw = true;
}

void dotCon(int dC) {
  dotCon = dC;
  startDraw = true;
}

// Function for Lévy-Distibution
float levyDistribution(float Wert1, float Wert2){
               float u = Wert1; // u = Lageparameter
               float c = Wert2; // s = Stauchung
               float x = 0;
               float y = 1;
               float fx = 0;
             while (y > fx) {
               x = random(10);
               y = random(1);
               fx = sqrt(c/(2*PI))*(exp(-c/(2*(x-u)))/pow((x-u), 3/2));
               //fx = 2 * exp(-2*x); Exponential
             }
             //point(x*100+200,500-y*500);
             return x;
        }






				
			

Generators: Cells/Herbarium

				
					// ––––––––––––––––––––––––––––––––––––––––––––––––––––––––
// Cells / Herbarium
// 
// Andreas Pirchner, 2014
// ––––––––––––––––––––––––––––––––––––––––––––––––––––––––

import processing.pdf.*;
import controlP5.*;

float[][] kernel = {{ -1, -1, -1}, 
                    { -1,  9, -1}, 
                    { -1, -1, -1}};

int nodesUsed = 1000; 
float valRed;
float valBlue;
float valGreen;
int nodeCount = 0; 
int maxConnect = 10;
float currentDistance = 0;
PImage img;
int nodeLoop = 1;
int activePoints = 0;
int startPoint = int(random(nodeCount));
int nextPoint = 0;
float bestDistance = 100;
  
PVector[] nodes = new PVector[1000*1000];
IntList nodesActive = new IntList();

int[] connections = new int[1000*1000];
int[] distance2current = new int[1000*1000];
color[] nodeColors = new color[1000*1000];
boolean [] visible = new boolean[1000*1000];
boolean [] used = new boolean[1000*1000];
int nodeOne = 40;
int nodeTwo;
int newNode;

ControlP5 cp5;
CheckBox RecordPDF;

boolean recording = false;
boolean saveNow = false;
boolean justDrawn = false;
boolean pointfound = false;
int saveCount = 0;


boolean startDraw = true;

int dotAmount;
int cellSize;
int cellTrans;

ArrayList <Cell> cells = new ArrayList <Cell> ();


void setup() { 
  size(1000, 1000);
  img = loadImage("Herbar3.jpg"); // Load the original image
  
  for (int i=0; i< nodes.length; i++) {
      nodes[i] = new PVector(0,0);
  } 
  for(int m=0; m < connections.length; m++){
     connections[m] = 0; 
     distance2current[m] = 0;
     nodeColors[m] = color(0,0,0); 
     visible[m] = false;
     used[m] = false;
  }
  
  cp5 = new ControlP5(this);
  cp5.addSlider("dotAmount")
     .setPosition(20,50)
     .setRange(50,1000000)
     .setSize(600,10)
     .setValue(500)
     .setLabel("Number of Dots")
     .setColorLabel(color(0))
     ;
     
  cp5.addSlider("cellSize")
     .setPosition(20,70)
     .setRange(0,500)
     .setSize(600,10)
     .setValue(50)
     .setLabel("Cell Size")
     .setColorLabel(color(0))
     ;
     
  cp5.addSlider("cellTrans")
     .setPosition(20,90)
     .setRange(0,255)
     .setSize(600,10)
     .setValue(10)
     .setLabel("Transparency")
     .setColorLabel(color(0))
     ;
    
  cp5.addBang("bangSave")
       .setPosition(20, 110)
       .setSize(10, 10)
       .setLabel("Export PDF")
       .setColorLabel(color(0))
       ;
  
  img.loadPixels();
  
  for (int y = 1; y < img.height-1; y++) { // Skip top and bottom edges
    for (int x = 1; x < img.width-1; x++) { // Skip left and right edges
      float sum = 0; // Kernel sum for this pixel
      float sumRed = 0; // Kernel sum for this pixel
      float sumGreen = 0; // Kernel sum for this pixel
      float sumBlue = 0; // Kernel sum for this pixel
      
      for (int ky = -1; ky <= 1; ky++) {
        for (int kx = -1; kx <= 1; kx++) {
          // Calculate the adjacent pixel for this kernel point
          int pos = (y + ky)*img.width + (x + kx);
          // Image is grayscale, red/green/blue are identical
           valRed = red(img.pixels[pos]);
           valGreen = green(img.pixels[pos]);
           valBlue = blue(img.pixels[pos]);
           
          // Multiply adjacent pixels based on the kernel values
          sumRed += kernel[ky+1][kx+1] * valRed;
          sumGreen += kernel[ky+1][kx+1] * valGreen;
          sumBlue += kernel[ky+1][kx+1] * valBlue;
        }
      }
      
      // Kantenpunkte in Array ablegen: x-Position, y-Position, Farbe
      if (sumRed > 400 || sumBlue > 90 || sumGreen > 200 ) {       
         nodeCount ++;
         nodes[nodeCount].x = x;
         nodes[nodeCount].y = y; 
         nodeColors[nodeCount] = color(valRed,valGreen, valBlue,255);              
      }      
    }
  }
  print(nodeCount);
  background(255);

}

void draw() {
  
  // Start recording PDF
  if (saveNow == true && recording ==true) beginRecord(PDF, "mona"+saveCount+".pdf");
  //image(img, 0, 0); // Displays the image from point (0,0) 
  // Ellipsen nach Daten aus dem Array zeichnen
      if(startDraw == true){
          resetCanvas();
          drawStructure();
          startDraw = false;    
      }
  // Stop recording PDF
  if (saveNow == true && justDrawn == true) {
    saveNow = false;
    recording = false;
    endRecord();
    saveCount ++;
  }
}

void drawStructure() {
      while (activePoints < nodesActive.size()){
                    while (pointfound != true){
                       nextPoint = int(random(0, nodesActive.size()));   
                       if (used[nextPoint] != true){
                           pointfound = true;
                       }
                    }
                    float x = nodes[nodesActive.get(nextPoint)].x;
                    float y = nodes[nodesActive.get(nextPoint)].y;               
                    boolean overlap = false;
                    for (Cell c : cells) {
                      if (dist(x, y, c.x, c.y) <= c.radius - 2) {
                        overlap = true;
                        break;
                      }
                    }
                    if (!overlap) {
                      cells.add(new Cell(x, y, nodeColors[nodesActive.get(nextPoint)])); 
                      used[nextPoint] = true;
                      
                    }      
                    pointfound = false;
                    activePoints ++;               
       }
     
       for (Cell c : cells) {
                //c.update();
                c.drawCell();
       }
       print("done painting");  
}

void resetCanvas(){
    background(100);
    nodeLoop = 1;
    activePoints=0;
    for (int n=0; n< nodeCount; n++){
        visible[n] = false;
    }
    saveNow = true;
    nodesUsed = dotAmount;
    startDraw = true;    
    nodesActive.clear();
    cells.clear();
    for (int l=0; l<nodesUsed; l++){  
      nodesActive.append(int(random(nodes.length)));
    }
    print(nodesActive.size()+",       ");
}

// Function for Record-Bang
void bangSave() {
  resetCanvas();
  beginRecord(PDF, "2CELLS_dots_"+dotAmount+"_range_"+cellSize+"_links_"+cellTrans+".pdf");
  drawStructure(); 
  endRecord();
}


// Function for Amount-Slider
void dotAmount(int dA) {
  dotAmount = dA;
  startDraw = true; 
}

void cellSize(int cS) {
  cellSize = cS;
  startDraw = true;
}

void cellTrans(int cT) {
  cellTrans = cT;
  startDraw = true;
}

// Function for Lévy-Distibution
float levyDistribution(float Wert1, float Wert2){
               float u = Wert1; // u = Lageparameter
               float c = Wert2; // s = Stauchung
               float x = 0;
               float y = 1;
               float fx = 0;
             while (y > fx) {
               x = random(5);
               y = random(1);
               fx = sqrt(c/(2*PI))*(exp(-c/(2*(x-u)))/pow((x-u), 3/2));
               //fx = 2 * exp(-2*x); Exponential
             }
             //point(x*100+200,500-y*500);
             return x;
        }





				
			
				
					// ––––––––––––––––––––––––––––––––––––––––––––––––––––––––
// Cells / Herbarium
// 
// Andreas Pirchner, 2014
// ––––––––––––––––––––––––––––––––––––––––––––––––––––––––

class Cell {
 float x,y;
 float radius;
 boolean overlap;
 color c; 

 Cell(float x, float y, color c) {
   this.x = x;
   this.y = y;
   //radius = random(1,cellSize);
   radius = levyDistribution(0,0.001)*cellSize/10;
   this.c = c;
  }
 
 void drawCell(){
   //stroke(red(nodeColors[nodeOne])*2, red(nodeColors[nodeOne])*1, red(nodeColors[nodeOne])*1, 100 );
     //stroke(red(c)*1, red(c)*1, red(c)*1, 255);
     stroke(255, 255, 255, 255);
     
     strokeWeight(0.4);
     //fill(0,0,0,20);
     point(100, 100);
     fill(255);
     
     ellipse(x,y,radius/2, radius/2);
     noFill();
    
     beginShape();
         
         int mitoCount = int(random(10));
         float startX = x+((radius/4)*random(1));
         float startY = y+((radius/4)*random(1));
         while (mitoCount >= 0){
           vertex(startX, startY);
           drawMitochondrion();
           endShape();
           mitoCount --;
         }
     fill(198,36,114);
     noStroke();
     ellipse(x,y,radius/12, radius/12);
     //stroke(0,0,0,100);
     //line(x-radius/4,y, x+radius/4, y);
 }
 
 void drawMitochondrion(){
    stroke(198, 36, 114, random(50,150));
   bezier(
          x+random(-radius/6, radius/6),y+random(-radius/6, radius/6),
          x+random(-radius/6, radius/6),y+random(-radius/6, radius/6),
          x+random(-radius/6, radius/6),y+random(-radius/6, radius/6),
          x+random(-radius/6, radius/6),y+random(-radius/6, radius/6)
        );
 }

}





				
			

Generators: Random Walks/ Skeletal remains

Generators: Random Grids/Butterfly taxonomy