Tuesday, June 11, 2013

3D Printing a Photo

This is not my code, however, this tutorial helps by laying out nice step by step instructions that will help any user be able to accomplish this project.

For a more detailed explanation, please visit: http://www.instructables.com/id/3D-Printed-Photograph/

Now for my personal experience in downloading this software:

For this to work, you will need to download the following:


Now that you have the three of these downloaded, move the modelbuilder folder into the processing library folder. 

Now copy the following code into Processing:

//3D printed photograph
//by Amanda Ghassaei (w bugfix by Pete Blacker)
//May 2013
//http://www.instructables.com/id/3D-Printed-Photograph/

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
*/
//libraries
import processing.opengl.*;
import unlekker.util.*;
import unlekker.modelbuilder.*;
import ec.util.*;


String name = "YOUR_FILE_NAME.jpg";//name of file

//storage for dimensions
int widthRes;
int heightRes;
float widthDim = 8;//width dimension (in inches)
float widthScaled;
float heightScaled;
float zDim = 0.1;//max vertical displacement (in inches)
float thickness = 0.02;//base thickness (in inches)

boolean invert = true;//if true, then white areas are lower than black, if not true white areas are taller

PImage img;//storage for image
float pixeldata[];//storage for pixel array
UVertexList v1,v2,v3,v4;//storage for verticies
UGeometry geo;//storage for stl geometry

void setup(){
  
  img = loadImage(name);//load image
  //get dimensions of image
  widthRes = img.width;
  heightRes =img.height;
  
  size(widthRes,heightRes,P3D);//set dimensions of output
  
  image(img, 0,0);//display image
  loadPixels();//poad pixels into array
  
  pixeldata = new float[widthRes*heightRes];//initialize storage for pixel data
  for(int index=0;index<widthRes*heightRes;index++){
    int getPixelData = pixels[index];//get data from pixels[] array
    pixeldata[index] = getPixelData&255;//convert to greyscale byte (0-255)
  }
  
  
  //initialize storage for stl
  geo = new UGeometry();
  v1 = new UVertexList();
  v2 = new UVertexList();
  v3 = new UVertexList();
  v4 = new UVertexList();
  
  //draw stl
  
  if(invert){
    //draw top
    for(int i=0;i<(heightRes-1);i++){
      v1.reset();
      v2.reset();
      for(int j=0;j<widthRes;j++){
        widthScaled = j/float(widthRes)*widthDim;
        //top layer
        v1.add(widthScaled,i/float(widthRes)*widthDim,(255-pixeldata[widthRes*i+j])*zDim/255+thickness);
        v2.add(widthScaled,(i+1)/float(widthRes)*widthDim,(255-pixeldata[widthRes*(i+1)+j])*zDim/255+thickness);
      }
      geo.quadStrip(v1,v2);
    }
    //draw sides
    v1.reset();
    v2.reset();
    v3.reset();
    v4.reset();
    for(int j=0;j<widthRes;j++){
      widthScaled = j/float(widthRes)*widthDim;
      v1.add(widthScaled,0,(255-pixeldata[j])*zDim/255+thickness);
      v2.add(widthScaled,0,0);
      v3.add(widthScaled,(heightRes-1)/float(widthRes)*widthDim,(255-pixeldata[widthRes*(heightRes-1)+j])*zDim/255+thickness);
      v4.add(widthScaled,(heightRes-1)/float(widthRes)*widthDim,0);
    }
    geo.quadStrip(v2,v1);
    geo.quadStrip(v3,v4);
    //draw sides
    v1.reset();
    v2.reset();
    v3.reset();
    v4.reset();
    for(int i=0;i<heightRes;i++){
      heightScaled = i/float(widthRes)*widthDim;
      v1.add(0,heightScaled,(255-pixeldata[widthRes*i])*zDim/255+thickness);
      v2.add(0,heightScaled,0);
      v3.add((widthRes-1)/float(widthRes)*widthDim,heightScaled,(255-pixeldata[widthRes*(i+1)-1])*zDim/255+thickness);
      v4.add((widthRes-1)/float(widthRes)*widthDim,heightScaled,0);
    }
    geo.quadStrip(v1,v2);
    geo.quadStrip(v4,v3);
  }
  else{
        //draw top
    for(int i=0;i<(heightRes-1);i++){
      v1.reset();
      v2.reset();
      for(int j=0;j<widthRes;j++){
        widthScaled = j/float(widthRes)*widthDim;
        //top layer
        v1.add(widthScaled,i/float(widthRes)*widthDim,(pixeldata[widthRes*i+j])*zDim/255+thickness);
        v2.add(widthScaled,(i+1)/float(widthRes)*widthDim,(pixeldata[widthRes*(i+1)+j])*zDim/255+thickness);
      }
      geo.quadStrip(v1,v2);
    }
    //draw sides
    v1.reset();
    v2.reset();
    v3.reset();
    v4.reset();
    for(int j=0;j<widthRes;j++){
      widthScaled = j/float(widthRes)*widthDim;
      v1.add(widthScaled,0,(pixeldata[j])*zDim/255+thickness);
      v2.add(widthScaled,0,0);
      v3.add(widthScaled,(heightRes-1)/float(widthRes)*widthDim,(pixeldata[widthRes*(heightRes-1)+j])*zDim/255+thickness);
      v4.add(widthScaled,(heightRes-1)/float(widthRes)*widthDim,0);
    }
    geo.quadStrip(v2,v1);
    geo.quadStrip(v3,v4);
    //draw sides
    v1.reset();
    v2.reset();
    v3.reset();
    v4.reset();
    for(int i=0;i<heightRes;i++){
      heightScaled = i/float(widthRes)*widthDim;
      v1.add(0,heightScaled,(pixeldata[widthRes*i])*zDim/255+thickness);
      v2.add(0,heightScaled,0);
      v3.add((widthRes-1)/float(widthRes)*widthDim,heightScaled,(pixeldata[widthRes*(i+1)-1])*zDim/255+thickness);
      v4.add((widthRes-1)/float(widthRes)*widthDim,heightScaled,0);
    }
    geo.quadStrip(v1,v2);
    geo.quadStrip(v4,v3);
  }
    
  
  //draw bottom
  v1.reset();
  v2.reset();
  //add bottom four corners
  v1.add(0,0,0);
  v1.add(0,(heightRes-1)/float(widthRes)*widthDim,0);
  v2.add((widthRes-1)/float(widthRes)*widthDim,0,0);
  v2.add((widthRes-1)/float(widthRes)*widthDim,(heightRes-1)/float(widthRes)*widthDim,0);
  geo.quadStrip(v1,v2);  

  //change extension of file name
  int dotPos = name.lastIndexOf(".");
  if (dotPos > 0)
    name = name.substring(0, dotPos);

  geo.writeSTL(this,name+".stl");

  exit();
  
  println("Finished");

}


Click the arrow pointing down to save the code. (This is a necessary step). 

Now find a jpg you would like to make into a 3D model. Open up the image editing software called Gimp. Import your jpg file and desaturate the image by clicking colors->desaturate. Export the image as a jpg file. After doing this, move the desaturated jpg file that you would like to make 3D into the sketch folder that Processing made when you saved it.



Close Processing and click on the .pde file to open the code in Processing. Towards the top of your code, you will see the words: String name = "YOUR_FILE_NAME.jpg"; Replace 'YOUR_FILE_NAME' with the name of your jpeg and press the play button (run). You may receive an error. If this happens, go to processing->preferences and click 'Increase maximum available memory'. After some failed a few tests, I just changed the maximum size to about 2000MB. Click run again, and after a few moments, you should see a message that it is making your STL and that it is finished.

TADA! You have successfully converted your photo to a 3D image.






This is the result from my 3D print. For better results, scale up the z-axis and make the size of the 3D print altogether larger. (This was only about 73x73 mm, and only about 1mm high)

2 comments:

  1. Keep it up!! You have done the nice job having provided the latest information.Great community

    ReplyDelete
  2. Thank you for sharing informative blog.it is so impressive.
    photo print on aluminum dibond

    ReplyDelete