本帖最后由 mostfun 于 2016-3-24 11:49 编辑
我们办公室里的3D打印机可以被用来创造一些独一无二的黑白影印的一种精确的、半透明的白色材质。这些影印也许从正面看不清晰,但是背光它们就可以呈现出令人震惊的高精度甚至给画面一种精细的维度和纹理。
通过增加这种半透明打印纸某部分的厚度来控制透过光线的数量,进而控制亮度(薄的地方就会亮写,厚的地方就会暗些)。
我改变厚度任意设计出独特的影像灰度像素,好让我精确地再次设计出任意灰度的影像。我打印的照片有我最敬爱的妈妈给我们家的小猫Teddy照的(图4),有Cassini太空船勘探到的土星和它的Titan卫星的(图5、图6),和一张来自Ansel Adams的巨大的(19x16)Mt.Willianson.(图1,2,3)
第一步:编码
所有的这些3D模型都是用Marius Watz的Model library在算法上进行加工产生的。这个图书馆允许3D几何体以STL格式文件存入,而STL文件形式形成的防护是可以被3D打印机打印出来的。
你自己开始用这个编码下载最新版本的ModelBuilder library解压文件,复制文件存入程序的“library”文件夹。如果你要安装ModelBuilder library的旧版本(Unlekkzer library)。你需要删除然后重新启动。
//image to 3d printableheightmap/lithophane//by Amanda Ghassaei //May 2013 //http://www.instructables.com/id/3D-Printed-Photograph/ /* *This program is free software; you can redistribute it and/or modify * itunder 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_here.jpg";//nameof file (with extension - this also works with pngs) //storage for dimensions int widthRes; int heightRes; float widthDim = 5;//width dimension (ininches) float widthScaled; float heightScaled; float zDim = 0.1;//max vertical displacement(in inches) float thickness = 0.02;//base thickness (ininches) boolean invert = true;//if true, then whiteareas 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 forverticies 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 pixeldata 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 intdotPos = name.lastIndexOf("."); if(dotPos > 0) name = name.substring(0, dotPos); geo.writeSTL(this,name+".stl"); exit(); println("Finished");
} 从GitHbb下载最新版本的程序(点击下载压缩包),打开Lighograph 3DPrint的文件夹,复制任意你想要改变的灰度级图片。跟着向导命名你的图片,替换下一行引号中的部分
String name = "your_file_name_here";
我相信gif/jpg/tga和png都不错,但我目前只用了tested.jpg。跟向导,一分钟或两步后它将会告诉你正描述STL文件最后会告诉你已完成。最终的文件将放在目录文件的“NAME_OF_ORIGINAL_FILE.stl”里。你可以用很多像CDA软件和STL阅读器打开。我喜欢用Meshlab浏览(它免费且公开)。我设置图片规格默认为8"宽,以0.02~0.1的厚度为特点,你可以在目录上方调整变量,更改设置
来源:instrctables
作者:amandaghassaei
|