How can I produce a stl file from a 2d image?

8 views (last 30 days)
Thalles Leite
Thalles Leite on 10 Nov 2015
Edited: DGM on 6 Apr 2025
It's simple.
I have a matrix 2d from a logical image. (For example a black square in the center of a white image)
And I want to give it some height, transforming it in a cube and then export like a stl file.
Is that possible?

Answers (1)

DGM
DGM on 4 Apr 2025
Edited: DGM on 6 Apr 2025
This turned out to be more difficult than I expected. There's probably a better way, but eh. With the exception of the 'merge' option, this runs in R2015b (assuming one of the FEX STL writers (#51200, #20922) was used in place of R2018b stlwrite().
The biggest disappointment is that most everything is hidden in the support functions (attached), so there's not much to see here. It does work though. The origin is treated as being in the SW corner of the image.
unzip supportcode.zip % cleaner than attaching a bunch of files
% some parameters
voxsize = [1 1 1]; % scalar or [x y z]
mergeflag = true; % merge colinear edge segments (requires R2017b)
% a logical image
inpict = imread('tinyblobs.png');
%inpict = false(5); inpict([1:4 6 9 11 14 16:18 25]) = true;
% show it
imagesc(inpict)
colormap(gray)
axis equal tight
% make sure the image is binarized, logical
if ~islogical(inpict)
% use im2bw() or something else prior to R2016a
inpict = imbinarize(inpict); % R2016a+
end
% convert the logical image to FV data
% the 'merge option requires polyshape (R2017b)
[F V boundaries] = bw2tri(inpict,'merge',mergeflag);
% extrude the surface
[F V] = extrude(F,V,boundaries);
% finally, rescale the vertex data as necessary
if isscalar(voxsize)
voxsize = repmat(voxsize,[1 3]);
end
V = bsxfun(@times,V,voxsize); % since we're in 2015
% write to file
% use one of the FEX STL writers if you're a time-traveller
stlwrite(triangulation(F,V),'testfile.stl') % R2018b
% display it using patch()
figure
patch('faces',F,'vertices',V,'facecolor','w','edgecolor','k');
view(3); camlight; view(10,33)
axis equal; grid on
xlabel('X'); ylabel('Y'); zlabel('Z')
That said, this direct extrusion has a fundamental problem. The second test image (commented out) illustrates it:
See it yet? How about now?
It's really easy to generate non-manifold edges this way. Anywhere you have two pixels bridging diagonally across the background, you'll generate non-manifold geometry. This pretty much ruins the prospect of using this extrusion technique in combination with dithered images.
How can we fix it? The easy way is to simply not let the bridges happen. You could use bwmorph(inpict,'diag') to break the background connectivity in these regions, but that would change the image. In the aforementioned case of dithering, it would completely destroy the image. Other options seem like a lot of work, and none of them seem like they wouldn't be objectionable in some circumstance. The least-difficult would be upsampling and dilation, but that would probably be pretty costly.
Do we need to fix it? It depends. It seems most people care less about it than I do, so maybe it's not an issue.
GPToolbox has a similar tool bwmesh() for converting a binary image into a 2D triangulation (which could then be extruded), but it triangulates the polygon connecting the boundary pixel centers instead of representing pixels as squares/rectangles.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!