You are now following this question
- You will see updates in your followed content feed.
- You may receive emails, depending on your communication preferences.
How can I convert a svg file to matrix or image in Matlab?
25 views (last 30 days)
Show older comments
I have a .svg file containing the slicing of a model. How can I import and read the slices in Matlab? They are binary slices and I need to loop over each of them to obtain the corresponding matrix. I'd rather not use Exchange functions, but that is not mandatory.
3 Comments
DGM
on 3 Nov 2022
What exactly is in the file? Are you trying to rasterize vector content in an SVG file, or are you trying to extract embedded raster content from the file? For certain types of vector content, you can use loadsvg() and methods similar to those described here may work to rasterize path objects.
For embedded raster data, I don't know off the top of my head, but even if existing SVG tools don't support it, it can't be too hard to extract directly.
Simone Cotta Ramusino
on 3 Nov 2022
I want to extract the content (93 binary slices) from the SVG file.
Accepted Answer
DGM
on 4 Nov 2022
If you have raster images embedded in an SVG file, you may be able to extract them something like this:
% filename of svg file
fname = 'multiobject.svg.fakeextension.txt';
% extract image extensions and data from file
% ignore all other objects in the file
str = fileread(fname);
blockinfo = regexp(str,'data:image/(.*?);base64,([^"]*)','tokens');
for k = 1:numel(blockinfo)
% get the info for this image
thisext = blockinfo{k}{1};
thisdata = blockinfo{k}{2};
% decode the image file
thisdata = matlab.net.base64decode(thisdata);
% write the file using the original format extension
fname = sprintf('myextractedfile_%04d.%s',k,thisext);
fid = fopen(fname,'w');
fwrite(fid,thisdata,'uint8');
fclose(fid);
end
Now all the files can simply be read from disk.
A = imread('myextractedfile_0001.png');
imshow(A)

Without knowing what exactly is in the file, I can't know for sure if that's what you need.
13 Comments
Simone Cotta Ramusino
on 4 Nov 2022
It is not possible to attach here the .svg file directly. I leave here a sample screenshot: in my file (it is a Slic3r output) I have 93 slices like this, all stacked in a single .svg
Your code over here did not work, unfortunately.
Thanks for your support
DGM
on 4 Nov 2022
Edited: DGM
on 4 Nov 2022
A screenshot of the shape doesn't tell me anything about what's actually in the file. While I gave a suggestion for reading embedded raster images, I have my doubts that the objects in the file are embedded raster images at all. I don't know why a slicer would render output as raster data in an SVG container. I would expect the output to be vector. If that's the case, then the above code won't work. Since I don't know what errors occured, I have nothing else to go on.
It's possible that they are raster images, but my shallow familiarity with the format conventions may mean that the text processing won't work on SVG files generated by applications other than the one that I used. That might be an easy thing to fix, but I'd hate to just keep guessing.
EDIT: I said I'd hate to keep guessing, but here's a guess:
blockinfo = regexp(str,'data:image/(.*?);\s*base64,\s*([^"]*)','tokens');
If it turns out that the objects are vector data, it may be a minor challenge to get it converted within MATLAB. There may be other options. I don't know yet.
If you can use your existing methods to generate a simplified version of the file or a version of the file using non-confidential information, then you could upload that. It really doesn't need more than one or two slices. The editor won't let you attach a .svg file directly, but you can either zip it or do what I did above and just put a fake extension on it.
DGM
on 4 Nov 2022
Edited: DGM
on 4 Nov 2022
It's not a bother. It goes both ways. We have to accept that neither of us know each other's contexts quite perfectly until we begin to communicate.
That said. The layers are vector objects. I haven't worked with trying to import filled polygon objects, so I'll have to see what I can do. I'm not sure if the existing SVG tools support that. The turnaround time on that might be quite some time. I might have to come back to this after work.
EDIT: the existing SVG tools don't work on filled polygon objects. I'll have to see what I can do, but options may be limited.
Simone Cotta Ramusino
on 4 Nov 2022
I see. Thank you for your efforts. The ouput comes from the software Slic3r, and, as far as I could see, it should produce vector objects, as you said.
Your code does not actually produce an error, simply the blockinfo cell stays empty.
Alternatively, we could solve the problem upstream: is there a way to get a volume in Matlab (i.e. a 3D matrix) starting from an stl file? Because that's my goal. I have the stl and I can read it in Matlab and get faces and vertices (or a triangulation structure), but from these I need to create the "slices" of the geometry, that is a series of matrix. I have tried with fill() to get some kind of 2D screen of the part, as if it was viewed from above, but it does not convince me

I get this, and from this I can move on to get a matrix representing it; but it would not work if the geometry varied along the z-axis.
That is the reason I looked for a slicing software, if we can avoid this and do everything it in Matlab, it would be great
DGM
on 4 Nov 2022
Edited: DGM
on 4 Nov 2022
There may be a way to handle STL files. I know it's come up before, and I think there are some STL-related contributions on the File Exchange, though I'm not really familiar with the topic.
That said, it looks like you're kind of halfway there already anyway. It seems your issue is simply that you have the coordinate information, but you just need to convert that to 3D raster data. If your desired output is a controllable raster image, it's often best to avoid trying to use graphing tools as part of the workflow. Otherwise, you're dealing with issues of inconsistent scale and all sorts of requisite interpolation and the consequences thereof.
Out of curiosity, is the final array to be binarized (two voxel states), or is any sort of antialiasing desired? Binarized representations are probably more appropriate for technical purposes, and for the purposes of getting this to work, it's going to be way easier.
Simone Cotta Ramusino
on 4 Nov 2022
I have just found the function VOXELISE on Exchange, that could be right for me, but I cannot clearly see how to use it. Did you ever use it?
Yes, obtaining binary matrix/volume would be perfect; antialiasing could be a problem.
Simone Cotta Ramusino
on 4 Nov 2022
I think I have solved using VOXELISE function; in this way, .svg should not be needed anymore.
I will let you know.
Thanks again for your suggestions.
DGM
on 5 Nov 2022
Edited: DGM
on 5 Nov 2022
Ah, well.
For what it's worth, this is what I came up with.
% filename of svg file
fname = 'Type_IV.svg';
% image scaling
scale = 20; % px/mm (i'm assuming these units are mm)
% extract image extensions and data from file
% ignore all other objects in the file
str = fileread(fname);
% get page geometry
% example: <svg width="114.999998" height="19"
pagesize = regexp(str,'<svg width="(\d+\.?\d*)" height="(\d+\.?\d*)"','tokens');
pagesize = fliplr(str2double(pagesize{1})); % [y x]
% get z-height for each polygon
% i'm currently assuming that these are in sequential order
% example: <g id="layer0" slic3r:z="1.35e-008">
zpos = regexp(str,'<g id="layer\d+" slic3r:z="(\d+\.?\d*[eE+-]*\d*)">','tokens');
zpos = str2double(vertcat(zpos{:}));
nframes = numel(zpos);
% get point list for each polygon
% example: <polygon slic3r:type="contour" points="..."
pointdata = regexp(str,'<polygon slic3r:type="contour" points="([^"]*)"','tokens');
for c = 1:nframes
thisblock = pointdata{c}{:};
thisblock = strrep(thisblock,',',' ');
thisblock = str2num(thisblock); %#ok<ST2NM>
pointdata{c} = reshape(thisblock,2,[]).'; % [x y]
end
% build image stack using ROI tools
% this is strictly 1 page per slice, so z-geometry is currently ignored!
outpict = false([ceil(scale*pagesize) nframes]);
imshow(outpict(:,:,1))
ROI = images.roi.Polygon(gca);
for c = 1:nframes
ROI.Position = scale*pointdata{c};
outpict(:,:,c) = createMask(ROI);
end
% assuming that z-steps are uniform, loft z by rescaling
% this won't really help in this case, since the part is so thin
% if z shares the same resolution as x and y, it reduces to a single page
%thick = scale*range(zpos);
%outpict = logical(imresize3(single(outpict),[ceil(scale*pagesize) thick],'nearest'));
volshow(outpict)

The above will generate a binary volumetric image. As given, the z-resolution isn't respected; it's just one page per layer (thicker than in reality). In this case, that makes the effective resolution [20 20 1/(2.7E-08)] px/mm (assuming x,y,and z are all in mm), given that the z-step is 2.7E-08.
The commented code will do lofting, but I'm thinking that it may best to represent these things with a z-scale that's independent of the x,y scale.
Simone Cotta Ramusino
on 5 Nov 2022
This definitely works, indeed I'm accepting this as answer!
But I must admit I cannot understand every part of your code, there are functions I am not familiar with (e.g. how did you use regexp? And how do you get svg properties?). If you could add some comments, without obligation obviously, I will appreciate it more.
About the resolution: I don't think I need lofting; I know both the final overall dimensions and the voxel dimensions I want for the 'outpict' volume:
volume size=[224, 2717, 93] pixels
or, alternatively,
voxel dimensions=[0.08 0.04 0.027] mm
How can I impose these?
DGM
on 6 Nov 2022
You should be able to open an SVG file with a text editor to see what's in it. As you can see, sometimes different software writes things in ways that a naive parser (like the one I wrote) won't expect. Note the fact that slic3r uses its own tags.
Like I said, my parsing attempt is pretty naive. it's strictly based on the file at hand and my recollection of other files -- as opposed to an in-depth understanding of the format specification and best practices for robust decoding. My use of regex to match things so literally makes this example inapplicable for files generated by other software.
I expanded the expressions a bit here. I'm not great with regex, but it's a start.
% filename of svg file
fname = 'Type_IV.svg';
% output image size
outsize = [224 2717]; % [y x]
% read the entire file
str = fileread(fname);
% get page geometry
% example: <svg width="114.999998" height="19"
% portions in () are the tokens to extract
% (\d+\.?\d*)
% \d+ one or more of any numeric digit
% \.? zero or one literal . character
% \d* zero or more of any digit
pagesize = regexp(str,'<svg width="(\d+\.?\d*)" height="(\d+\.?\d*)"','tokens');
pagesize = fliplr(str2double(pagesize{1})); % [y x]
scale = outsize./pagesize; % calculate scale from output size
% get z-height for each polygon
% i'm currently assuming that these are in sequential order
% example: <g id="layer0" slic3r:z="1.35e-008">
% (\d+\.?\d*[eE+-]*\d*)
% \d+ one or more of any digit
% \.? zero or one literal . character
% \d* zero or more of any digit
% [eE+-]* zero or more of the characters within the brackets
% \d* zero or more of any digit
zpos = regexp(str,'<g id="layer\d+" slic3r:z="(\d+\.?\d*[eE+-]*\d*)">','tokens');
zpos = str2double(vertcat(zpos{:}));
nframes = numel(zpos);
% get point list for each polygon
% example: <polygon slic3r:type="contour" points="..."
% ([^"]*)
% [^"]* zero or more characters which are not "
pointdata = regexp(str,'<polygon slic3r:type="contour" points="([^"]*)"','tokens');
for c = 1:nframes
thisblock = pointdata{c}{:};
thisblock = strrep(thisblock,',',' ');
thisblock = str2num(thisblock); %#ok<ST2NM>
pointdata{c} = reshape(thisblock,2,[]).'; % [x y]
end
% build image stack using ROI tools
% this is strictly 1 page per slice, so z-geometry is currently ignored!
outpict = false([ceil(scale.*pagesize) nframes]);
imshow(outpict(:,:,1)) % displaying one page to set the axes geometry
ROI = images.roi.Polygon(gca); % create a polygon ROI object in the current axes
for c = 1:nframes
ROI.Position = fliplr(scale).*pointdata{c}; % set the vertex list of the polygon
outpict(:,:,c) = createMask(ROI); % convert the polygon to a 2D binary image
end
I rearranged the use of the scale parameter. In this case, you specify the output geometry instead of the scale. The result should be 224x2717x93.
Simone Cotta Ramusino
on 6 Nov 2022
So, if I get this right, you "simply" created a syntax that materially recognizes and reads the tokens of this .svg file; and even if it could not be multipurpose, should it always work for these kind of .svg files created with slic3r?
Then you define the page geometry and you "plot" the needed shape over it. I will always have a loss of information, like an aliasing-effect, right? This is due to the attempt to define cruved lines with pixels, I assume..even if I try:
ROI=image.roi.FreeHand(gca);
nothing changes.
Finally, the last real doubt: why did you define the scale array? I mean, at line 42, couldn't one write this:
outpict = false([ceil(outsize) nframes]);
and, in the following loop:
for c = 1:nframes
ROI.Position = fliplr(outsize./pagesize).*pointdata{c}; % set the vertex list of the polygon
outpict(:,:,c) = createMask(ROI); % convert the polygon to a 2D binary image
end
The outsize array is not fixed and I always know how to fill it, so scale looks unnecessary..or am I misinterpreting something?
DGM
on 6 Nov 2022
Yeah, I basically looked at the file and assumed that other files generated by the same software would have the same formatting. Unless slic3r happens to add something other than polygon objects to some files, I tentatively assume that it should work. That's an approximation based on a single observation.
Swapping images.roi.Polygon() with images.roi.Freehand() doesn't really change anything, since their position properties are compatibly-oriented. The only real difference between the two is in how they're created when doing so interactively (with the mouse). Since they're being used programmatically, they behave the same.
Yes, I suppose you could rewrite it that way as well. I just saw potential value in knowing the factors which map between part geometry and image geometry. That, and it's a bit of a holdover from the prior code. You're free to adapt it however you feel suits your needs.
Simone Cotta Ramusino
on 6 Nov 2022
Ok, anyway I could adapt it if the svg file changed, fixing the regex syntax I think.
I got it, indeed nothing changes, the "aliasing" is still there, but I think it is inescapable.
Yes, in the end I think I will leave it untouched, so I can use the scaling factor, if necessary.
Thank you very much, you were crystal clear and helped me a lot. I am sorry I was not very precise at first.
Thanks again
More Answers (0)
See Also
Categories
Find more on Graphics Object Identification 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!An Error Occurred
Unable to complete the action because of changes made to the page. Reload the page to see its updated state.
Select a Web Site
Choose a web site to get translated content where available and see local events and offers. Based on your location, we recommend that you select: .
You can also select a web site from the following list:
How to Get Best Site Performance
Select the China site (in Chinese or English) for best site performance. Other MathWorks country sites are not optimized for visits from your location.
Americas
- América Latina (Español)
- Canada (English)
- United States (English)
Europe
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom (English)
Asia Pacific
- Australia (English)
- India (English)
- New Zealand (English)
- 中国
- 日本Japanese (日本語)
- 한국Korean (한국어)