使用代码将任何 2D 图像变成可 3D 打印的雕塑 [英] Turn any 2D image into 3D printable sculpture with code

查看:38
本文介绍了使用代码将任何 2D 图像变成可 3D 打印的雕塑的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试仅使用代码将 2D 图像转换为 3D 可打印雕塑.首先我想知道是否可以只用脚本来完成?我已经知道 Python 和 C,如果我能使用其中之一来做我想做的事,当然会很棒.

I'm trying to convert a 2D image into a 3D printable sculpture using just code. First I would like to know if it can be done with just a script? I already know Python and C and would be great of course if I could use one of these to do what I want.

这里有两个链接供您理解我所说的将任何 2D 图像转换为 3D 可打印雕塑"(但这些是使用软件):

Here are two links for you to see what I mean by saying "Turn any 2D image into 3D printable sculpture" (but these are using software):

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

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

更具体地说,我想插入一个图像,然后等待获得 3D 雕塑的结果.

To be more specific I want to insert an image and just wait to get the result which will be a 3D sculpture.

推荐答案

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

was curious a bit so I encoded a small example of illumination surface encoding

  • 对于输入图像的每个像素height = (color_intensity)*scale

这是我测试的输入图像(谷歌搜索中第一幅漂亮的油画):

This is input image I tested with (first nice Oil painting in Google search):

这是结果(点云3D预览)

左侧是动画 gif,因此如果动画已停止,请重新加载/刷新页面以查看动画,或者下载 gif 并以更简洁的方式打开以进行 gif 预览...右侧是彩色点云预览(静态图片)

On the left is animated gif so reload/refresh page to see the animation if it is already stopped or download the gif and open in something more decend then brownser for gif preview... On the right is colored point cloud preview (static image)

这是用于计算的 C++ 代码:

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];
    }

这里是 OpenGL 预览代码(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

[注释]

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

I am using own picture class so here some members:

  • xs,ys 图像的像素大小
  • p[y][x].dd 是 (x,y) 位置的像素,为 32 位整数类型
  • p[y][x].db[4] 是按色带 (r,g,b,a) 的像素访问
  • 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)

我还使用自定义 OpenGl scr 和 Texture Classes:

Also I am using custom OpenGl scr and Texture Clases:

  • xs,ys 缓冲区大小(以像素为单位)
  • Texture::txr 是 32 位像素指针(图像被分配为线性一维数组)
  • 高度图用于存储整数值
  • 法线贴图用于存储浮点法向量分量
  • 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

剩下要做的就是:

  1. 根据您的喜好过滤点云
  2. 三角测量/导出到您的打印机支持的网格

还有其他方法可以将光照编码到表面:

  1. 你可以做一些类似菲涅耳透镜表面

  • 因此将网格划分为段
  • 并偏移每个,使其从相同的参考平面(z偏移)开始

需要更少的体积/材料

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

First half of animation is normal height encoding then it is switched to Fresnel surface encoding/packing for comparison

将光照编码为粗糙度图而不是高度图

encode illumination not as height map but as roughness map instead

  • 每个像素都会被映射成小的子高度图
  • 平坦的表面具有高照度/颜色强度
  • 粗糙的表面是黑色的
  • 中间是灰色阴影

这也可以从角度看到,并且可以相对较薄,因此需要很少的材料(比以前的项目少得多)

This will be visible also from angles and can be relatively thin so need very little material for this (much less then previous bullet)

真实高度图(真实 3D 网格表示)

Real height map (real 3D mesh representation)

您需要标准化颜色、阴影和照明伪像非常棘手,因此只剩下正常的阴影(因为表面来自单一材料、颜色、光泽度、粗糙度...),然后才提取高度图.为此,您需要许多东西,例如分割、自适应阈值处理、过滤等等……最后添加空的内部并添加支撑墙,以便在打印时/打印后将网格保持在一起.

It is very tricky you need to normalize colors, shadows and illumination artifacts so only normal shading is left (as the surface is from single material,color,shininess,roughness ...) and only then extract the height map. For that you need many things like segmentation, adaptive tresholding, filtering and much more ... At last add the empty inside and add support walls so the mesh holds together while/after printing.

这篇关于使用代码将任何 2D 图像变成可 3D 打印的雕塑的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆