用代码将任何2D图像变成可打印的3D雕塑

8 人关注

我想用代码把一张二维图像转换成一个可打印的三维雕塑。首先我想知道是否可以只用一个脚本来完成?我已经知道Python和C语言,如果能用其中的一种来做我想做的事,那当然好。

这里有两个链接,让你看看我说的 "把任何二维图像变成可打印的三维雕塑 "是什么意思(但这些是使用软件)。

https://www.youtube.com/watch?v=ngZwibfaysc

https://www.youtube.com/watch?v=-fe2zxcKSic

更具体地说,我想插入一个图像,然后等待得到的结果将是一个三维雕塑。

2 个评论
RN_
你必须要有一个近似的高度图;我想你可以用gimp-cli来做这个,所以不需要写一个python脚本。
1.更具体一点,你想要真实的模型还是只想要照明编码的表面(以及哪种形式...)。2.你将使用什么样的图像作为输入(通用的在CV/DIP中是不可行的/实用的/可靠的)。
python
c
image
image-processing
3d
Oluderi
Oluderi
发布于 2015-07-09
1 个回答
Spektre
Spektre
发布于 2015-07-10
已采纳
0 人赞同

我有点好奇,所以我编码了一个照明面编码的小例子

  • for each pixel of input image height = (color_intensity)*scale
  • 这是我测试的输入图像 (谷歌搜索中的第一幅漂亮的油画) :

    This is the result (point cloud 3D preview)

    左边是GIF动画,如果动画已经停止,请重新加载/刷新页面以查看动画,或者下载GIF并在更高级的东西中打开,然后用brownser进行GIF预览...。右边是彩色点云预览(静态图像)。

    This is the C++ code for computing this:

    OpenGLtexture zed,nx,ny,nz; // height map,normal maps (just 2D images)
    picture pic;                // source image
    int x,y,a;
    // resize textures to source image size
    zed.resize(pic.xs,pic.ys); 
     nx.resize(pic.xs,pic.ys); float *pnx=(float*) nx.txr;
     ny.resize(pic.xs,pic.ys); float *pny=(float*) ny.txr;
     nz.resize(pic.xs,pic.ys); float *pnz=(float*) nz.txr;
    // prepare tmp image for height map extraction
    picture pic0;
    pic0=pic;       // copy
    pic0.rgb2i();   // grayscale
    // this computes the point cloud (this is the only important stuff from this code)
    // as you can see there are just 3 lines of code important from all of this
    for (a=0,y=0;y<pic.ys;y++)
     for (x=0;x<pic.xs;x++,a++)
      zed.txr[a]=pic0.p[y][x].dd>>3; // height = intensity/(2^3)
    // compute normals (for OpenGL rendering only)
    double n[3],p0[3],px[3],py[3];
    int zedx,zedy,picx,picy;
    for (a=zed.xs,zedy=-(pic.ys>>1),picy=1;picy<pic.ys;picy++,zedy++)
     for (a++,    zedx=-(pic.xs>>1),picx=1;picx<pic.xs;picx++,zedx++,a++)
        vector_ld(p0,zedx-1,zedy  ,-zed.txr[a       -1]); // 3 neighboring points
        vector_ld(py,zedx  ,zedy-1,-zed.txr[a+zed.xs  ]);
        vector_ld(px,zedx  ,zedy  ,-zed.txr[a         ]);
        vector_sub(px,p0,px); // 2 vectors (latices of quad/triangle)
        vector_sub(py,p0,py);
        vector_mul(n,px,py); // cross product
        vector_one(n,n); // unit vector normalization
        pnx[a]=n[0]; // store vector components to textures
        pny[a]=n[1];
        pnz[a]=n[2];
    

    Here OpenGL preview code (C++):

    scr.cls(); // clear buffers
    scr.set_perspective(); // set camera matrix
    glMatrixMode(GL_MODELVIEW); // set object matrix
    rep.use_rep();
    glLoadMatrixd(rep.rep);
    // directional (normal shading)
    float lightAmbient  [4]={0.20,0.20,0.20,1.00};      
    float lightDiffuse  [4]={1.00,1.00,1.00,1.00};      
    float lightDirection[4]={0.00,0.00,+1.0,0.00};      
    glLightfv(GL_LIGHT1,GL_AMBIENT ,lightAmbient );
    glLightfv(GL_LIGHT1,GL_DIFFUSE ,lightDiffuse );
    glLightfv(GL_LIGHT1,GL_POSITION,lightDirection);
    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHTING);
    glDisable(GL_TEXTURE_2D);
    glEnable(GL_COLOR_MATERIAL);
    // render point cloud
    int zedx,zedy,picx,picy,a;
    glColor3f(0.7,0.7,0.7);
    float *pnx=(float*)nx.txr;
    float *pny=(float*)ny.txr;
    float *pnz=(float*)nz.txr;
    glBegin(GL_POINTS);
    for (a=zed.xs,zedy=-(pic.ys>>1),picy=1;picy<pic.ys;picy++,zedy++)
     for (a++,    zedx=-(pic.xs>>1),picx=1;picx<pic.xs;picx++,zedx++,a++)
        //glColor4ubv((BYTE*)&pic.p[picy][picx].dd); // this is coloring with original image colors but it hides the 3D effect
        glNormal3f(pnx[a],pny[a],pnz[a]); // normal for lighting
        glVertex3i(zedx  ,zedy  ,-zed.txr[a]); // this is the point cloud surface point coordinate
    glEnd();
    scr.exe(); // finalize OpenGL calls and swap buffers ...
    scr.rfs();
    

    矩阵是这样设置的。

    // gluProjection parameters
    double f=100;                   //[pixels] focus
    scr.views[0].znear=       f;    //[pixels]
    scr.views[0].zfar =1000.0+f;    //[pixels]
    scr.views[0].zang =  60.0;      //[deg] view projection angle
    scr.init(this); // this compute the Projection matrix and init OpenGL
    // place the painting surface in the middle of frustrum
    rep.reset();
    rep.gpos_set(vector_ld(0.0,0.0,-0.5*(scr.views[0].zfar+scr.views[0].znear)));
    rep.lrotx(180.0*deg); // rotate it to match original image
    

    [notes]

    我正在使用自己的图片类,所以这里有一些成员。

  • xs,ys size of image in pixels
  • p[y][x].dd is pixel at (x,y) position as 32 bit integer type
  • p[y][x].db[4] is pixel access by color bands (r,g,b,a)
  • 我还使用了自定义的OpenGlscr和Texture Clases。

  • xs,ys size of buffer in pixels
  • Texture::txr is 32bit pixel pointer (image is allocated as linear 1D array)
  • height map is used to store int values
  • normal maps is used to store float normal vector components
  • The only thing left to do is:

  • filter the pointcloud to your liking
  • triangulate/export to mesh supported by your printer
  • 还有其他方法可以将光照编码到表面。

  • 你可以做这样的事情菲涅尔透镜表面

  • so divide mesh to segments
  • and offset each so it starts from the same reference plane (z offset)
  • 这需要更少的体积/材料

    动画的前半部分是正常的高度编码,然后切换到菲涅尔表面编码/包装,以进行比较

  • 编码照度不是作为高度图,而是作为粗糙度图而不是

  • each pixel will be mapped into small sub height map
  • flat surface is high illumination/intensity of color
  • rough surface is black
  • and in between are the shades of gray
  •