Generate 3D model from a 2D image
92 views (last 30 days)
Show older comments
Hi friends,
I would like to generate a 3D model from a 2D image but I don't have any clue.
From some good instruction, I have successfully generated a binary image with my defined masks. Here the reason why I want a binary image is that the 3D printer only accepts binary slices. I would like to just extrude my pixels into a 3D model (all numbers 1 need to be given the same height, but 0 don't need a height or a neglectable height), and slice them with my printer software. Here is the first section to generate a good binary image. I know there is some other ways we can use to reconstruct a 3D model from a 2D image, but I just want do it in matlab.
1 Comment
DGM
on 7 Apr 2024
Edited: DGM
on 7 Apr 2024
Is there a particular reason you're using this dither pattern? There are existing tools for ordered and error-diffusion dithering.
Is there a reason that you're doing dithering at all? At least for a FDM process, this is going to create something that may be a challenge for many printers due to the absurd number of retractions (~30k retractions per layer).
You'd also need to be combining the extruded image with some other solid geometry, otherwise you'd just end up with a bunch of disconnected plastic bits on the build plate. So obviously there's more to this than just extruding the binarized image.
If you're going to slice the generated model anyway, I don't see why it needs to be binarized or dithered. What is the actual goal? Lithophanes?
Answers (2)
DGM
on 8 Apr 2024
Moved: DGM
on 8 Apr 2024
I've always found that one of the biggest troubles with resin processes is getting decent reproduction of small islands/holes. Small islands tend to break off and end up welding to the print elsewhere, and small holes are always undersized. If the goal were to just produce a lithophane, I'd convert the image into a 3D surface (a height map), and then let the slicer do its job instead of trying to do the slicer's job for it.
If you want to do it with dithering, well here's one attempt, but I'll warn you that it has problems.
% read and strip color
inpict = imread('MonaLisaSquare.jpeg');
inpict = im2gray(inpict);
xyscale = 0.102; % mm/px
zscale = 0.2; % mm
maxwidth = 300; % pixels
% resize
inpict = imresize(inpict,min(maxwidth./size(inpict,1:2)));
% binarize
%binarized = imbinarize(medfilt2(inpict,[1 1]*5)); % something simple
binarized = dither(inpict); % dithered
imshow(binarized,'border','tight')
% generate position data
szo = size(binarized,1:2);
x = xyscale/2:xyscale:xyscale*(szo(2)-0.5);
y = xyscale/2:xyscale:xyscale*(szo(1)-0.5);
z = zscale/4:zscale/2:zscale*0.75; % model is 1 voxel thick
% expand and reorient
out = repmat(flipud(binarized).',[1 1 2]);
% write as voxelized STL
outputname = 'mona.stl';
CONVERT_voxels_to_stl(outputname,out,x,y,z,'binary')
This uses this tool from the FEX
The problem here is that two pixels which are only diagonally connected will form a non-manifold edge. You can expect the STL file to be relatively large (a few tens of MB), and you can expect it to have thousands of defects. Whether or not your slicer will put up with that, I don't know.
9 Comments
DGM
on 8 Apr 2024
Oh. What was the problem? Somehow the image got collapsed to 1px?
I'm still trying to get MATLAB Online to even work for me. It's pretty broken in my browser now.
DGM
on 8 Apr 2024
While I'm waiting for MATLAB to load, I'm going to throw this out there.
This is just a height map. For a lithophane, you'd just invert the image with imcomplement() so that the brightest areas are thinnest.
% read and strip color
inpict = imread('peppers.png');
inpict = im2gray(inpict);
% invert if making a lithophane
inpict = imcomplement(inpict);
% resize if you want to change the mesh resolution
inpict = imresize(inpict,0.5);
% make sure the image is full-scale and floating point
outpict = mat2gray(inpict);
% object scale parameters (mm)
% this does not do any resampling
reliefheight = 10; % the variation in thickness
basethickness = 2; % the minimum thickness
xwidth = 150; % y-width is calculated to preserve aspect ratio
% construct coordinate arrays
szi = size(outpict);
szo = xwidth*[szi(1)/szi(2) 1];
x = linspace(0,szo(2),szi(2));
y = linspace(szo(1),0,szi(1)); % shift origin to SW corner
[X Y] = meshgrid(x,y);
Z = im2double(outpict)*reliefheight + basethickness; % scale z
% display the surface
figure
hs = surf(X,Y,Z); hold on
hs.EdgeColor = 'none';
hs.FaceColor = [1 1 1]*0.8;
followerlight(hs); % attached
% construct a closed surface
% surf2solid() outputs face/vertex lists, but the native stlwrite()
% only accepts triangulation objects, so convert it
[F V] = surf2solid(X,Y,Z,'elevation',0); % SEE FEX #42876
TR = triangulation(F,V); % complains, but i'm going to ignore that
% display it again
figure
hs = trisurf(TR);
hs.EdgeColor = 'none';
hs.FaceColor = [1 1 1]*0.8;
followerlight(hs);
% write it to a STL
stlwrite(TR,'monarelief.stl')
The slicer does all the work of binarizing the layers.
1 Comment
DGM
on 8 Apr 2024
Is that using this example or the other one? That looks like your original 3x3 custom dither pattern.
See Also
Categories
Find more on Basic Display in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!