Clear Filters
Clear Filters

Generate 3D model from a 2D image

159 views (last 30 days)
Haoqing Yang
Haoqing Yang on 7 Apr 2024
Edited: Haoqing Yang on 19 May 2024 at 22:32
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?

Sign in to comment.

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
% 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';
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.
Haoqing Yang
Haoqing Yang on 8 Apr 2024
Edited: Haoqing Yang on 8 Apr 2024
Okay I fixed the problem, now it works well.
I appreciate so much for your help!
You made my day!!!!
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.

Sign in to comment.

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
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
Warning: Some input points are not referenced by the triangulation.
% display it again
hs = trisurf(TR);
hs.EdgeColor = 'none';
hs.FaceColor = [1 1 1]*0.8;
% write it to a 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.

Sign in to comment.


Find more on Display Image 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!