Fastness logo - art programming projects
Programming: Faces (& Bitmaps) for Eggbot
20th November  2011

On the 5th December I shall be taking Eggbot to our local Christmas craft fair, I've made a few Christmassey designs but I really wanted to be able to take a picture and draw people's faces on Christmas decorations 'live' on the day.

I've found a way to do it with Processing and a webcam...

Eggbot bitmaps on a bauble

The tool chain is Processing exporting to PDF, followed by Inkscape.

Another bauble...

The code produces the vertical strips, an array of these is needed to make the finished image.

The baubles above are ~70mm diameter, matt silver and they work really well (they're  £2.99 for 6 in Ikea)

I'm taking the bitmapped input from a webcam in the example but it would easily be adapted to work from an image input.  The webcam is driven with the excellent GSVideo library.

The code runs fast enough to be able to see the webcam image on screen quite clearly on my PC, your mileage may vary, nothing gets written out until you press 'e' to export to a PDF.  I drag the PDF into Inkscape to import it into the 3200x800 pixel page that Inkscape needs and re-size as needed.  The finished image looks like this:

bitmap for eggbot

Brightness values in the image are translated into widths of strips so that there is more white where the image is bright (narrow strip) and more fill where the image is dark.

Each face takes about 4 minutes, so I won't be able to do that many if they're popular...

The code for the Strip class is below the main text and zipped here.

If you want to have a go, please feel free to use the included code and let me know how you get on...

====

Source code is available here
class Strip {
  float theLength, theWidth, theSeparation;  
//basic dimensions, length,
//width and desired separation between pixels

  float minWidth, theThick;  
//minimum width & thickness (mainly used for 3D models),
  int thePixels;  
//number of pixels (down normally) that this strip represents
  float[] theBrightness;  
//array of brightness values, & yes I know this should be int[]

  float[] t,l;   //storage arrays
  boolean invert;  
//invert = true assumes light background, dark strips

  
  //switch for 2D/3D writing
  boolean twoD = false;
  
  Strip(float theLength, float theWidth,
float
theSeparation, float[] theBrightness, float minWidth) {
    twoD = true; // this is the 2D version of the constructor
    this.theLength = theLength;
    this.theWidth = theWidth;
    this.theSeparation = theSeparation;
    this.theBrightness = theBrightness;
    this.minWidth = minWidth;
    thePixels = theBrightness.length;
    
    t = new float[thePixels];
    l = new float[2*thePixels];
    
    float maxB = max(theBrightness);
    float minB = min(theBrightness);
    
    //setup the widths of the strip for each pixel
    for (int i=0;i=thePixels;i++) {
      t[i] = map(theBrightness[i],0,255,theWidth,minWidth);
    }
    
    float pixLen = theLength/thePixels;
    float cumlLen = pixLen/2;
    float landLen = pixLen - 2*theSeparation;
    
    //setup the positions along the strip for each pixel
    for (int i=0;i=thePixels;i++) {
      l[2*i] = cumlLen - landLen/2;
      l[2*i+1] = cumlLen + landLen/2;
      cumlLen += pixLen;
    }
    
  }
  
  //this is the 3D version of the constructor
  Strip(float theLength, float theWidth, float theSeparation,
float
[] theBrightness, float minWidth,
float
theThick, boolean invert) {
    this.theLength = theLength;
    this.theWidth = theWidth;
    this.theSeparation = theSeparation;
    this.theBrightness = theBrightness;
    this.minWidth = minWidth;
    this.theThick = theThick;
    this.invert = invert;
    thePixels = theBrightness.length;
    
    t = new float[thePixels];
    l = new float[2*thePixels];
    
    float maxB = max(theBrightness);
    float minB = min(theBrightness);
    
    float[] newBrightness = theBrightness;
    
    //println(theBrightness);
    for (int i=0;i=thePixels;i++) {
      if (!invert) {
        newBrightness[i] = map(theBrightness[i],minB,maxB,maxB,minB);
      }
      t[i] = map(newBrightness[i],0,255,theWidth,minWidth);
    }
    //println(t);
    float pixLen = theLength/thePixels;
    float cumlLen = pixLen/2;
    float landLen = pixLen - 2*theSeparation;
    for (int i=0;i=thePixels;i++) {
      l[2*i] = cumlLen - landLen/2;
      l[2*i+1] = cumlLen + landLen/2;
      cumlLen += pixLen;
    }
    
  }
  
  void drawStrip() {
    
    //NB: TWO versions of the draw code for 2D and 3D
    
    //draw Strip from 0,0,0 to 0,-theLength,0
    /*
  ->   =- min width
    *-*     =- pixel start
    |   \   =- half separation
    |----*
    |    |
    |    |
    |    |
    |    |
    |    |
    |    |
    |    |
    |----*
    |   /   =- half separation
    |  /    =- half separation
    |-*
    | |
    | |
    | |
    | |
    | |
    | |
    | |
    |-*
    
    This is the pattern for the strip
    */
    
    //3D
    if (twoD = false) {
      //NB: this code will produce MASSIVE normal direction problems
      // if you use it for 3D printing, if you want to fix it feel
      // free, otherwise use Blender or Meshlab to fix them later
      
      //top surface (along y direction), zigzag across in x direction
      beginShape(QUAD_STRIP);
      vertex(0,0,0);
      vertex(minWidth,0,0);
      for (int i=0;i=thePixels;i++) {
        vertex(0,l[2*i],0);
        vertex(t[i],l[2*i],0);
        vertex(0,l[2*i+1],0);
        vertex(t[i],l[2*i+1],0);
      }
      vertex(0,theLength,0);
      vertex(minWidth,theLength,0);
      endShape();
      
      //bottom surface
      beginShape(QUAD_STRIP);
      vertex(0,0,theThick);
      vertex(minWidth,0,theThick);
      for (int i=0;i=thePixels;i++) {
        vertex(0,l[2*i],theThick);
        vertex(t[i],l[2*i],theThick);
        vertex(0,l[2*i+1],theThick);
        vertex(t[i],l[2*i+1],theThick);
      }
      vertex(0,theLength,theThick);
      vertex(minWidth,theLength,theThick);
      endShape();
      
      //"crennelated" surface
      beginShape(QUAD_STRIP);
      vertex(minWidth,0,0);
      vertex(minWidth,0,theThick);
      for (int i=0;i=thePixels;i++) {
        vertex(t[i],l[2*i],0);
        vertex(t[i],l[2*i],theThick);
        vertex(t[i],l[2*i+1],0);
        vertex(t[i],l[2*i+1],theThick);
      }
      vertex(minWidth,theLength,0);
      vertex(minWidth,theLength,theThick);
      endShape();
      
      //back surface
      beginShape(QUAD_STRIP);
      vertex(0,0,0);
      vertex(0,0,theThick);
      for (int i=0;i=thePixels;i++) {
        vertex(0,l[2*i],0);
        vertex(0,l[2*i],theThick);
        vertex(0,l[2*i+1],0);
        vertex(0,l[2*i+1],theThick);
      }
      vertex(0,theLength,0);
      vertex(0,theLength,theThick);
      endShape();
      
      //ends
      beginShape(QUAD_STRIP);
      vertex(0,0,0);
      vertex(minWidth,0,0);
      vertex(0,0,theThick);
      vertex(minWidth,0,theThick);
      endShape();
      
      beginShape(QUAD_STRIP);
      vertex(0,theLength,0);
      vertex(minWidth,theLength,0);
      vertex(0,theLength,theThick);
      vertex(minWidth,theLength,theThick);
      endShape();
      
    } else {
      
      //2D
      
      //draw the outline
      beginShape();
      vertex(0,0);
      vertex(minWidth,0);
      for (int i=0;i=thePixels;i++) {
        vertex(t[i],l[2*i]);
        vertex(t[i],l[2*i+1]);
      }
      vertex(0,theLength);
      vertex(minWidth,theLength);
      endShape(CLOSE);
      
      //draw the fill
      beginShape();
      vertex(0,0);
      vertex(minWidth,0);
      for (int i=0;i=thePixels;i++) {
        vertex(t[i]/4,l[2*i]);
        vertex(t[i],l[2*i+1]);
      }
      vertex(0,theLength);
      vertex(minWidth,theLength);
      endShape(CLOSE);
      
    }
  }
  
}



fastness - Iain Banks Graphics
Fastness - Iain Banks Graphics
All of the content from my Iain M Banks website, now shifted to be a section in this one

fastness - Links & Resources:
Processing:
An open source programming tool aimed at artists, engineers and designers.  Simple, light and Java-based with a wealth of libraries and a strong user community

Shapeways:
3D printing for the masses - plastics and metal to your design or team up with a desigenr to personalise a design with a 'co-creator'.  Visit my Shapeways shop for some things I've designed.

Meshlab:
MeshLab is an open source, portable, and extensible system for the processing and editing of unstructured 3D triangular meshes

Blender:
Blender is the free open source 3D content creation suite, available for all major operating systems under the GNU General Public License

Gimp:
GIMP is the GNU Image Manipulation Program. It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages

Inkscape:
An Open Source vector graphics editor, with capabilities similar to Illustrator, CorelDraw, or Xara X, using the W3C standard Scalable Vector Graphics (SVG) file format

Ponoko:
Retail laser cutting outlet with centres in New Zealand, USA, Germany, Italy and the UK (if not more by now)

Eclipse:
Java development environment