Save Matlab Simulink Model as PDF with tight bounding box - matlab

Given a Simulink block diagram (model), I would like to produce a 'Screenshot' to be used later in a LaTeX document. I want this screenshot to be PDF (vector graphic, -> pdflatex) with a tight bounding box, by that I mean no unneccessary white space around the diagram.
I have searched the net, searched stackexchange, searched the matlab doc. But no success so far. Some notes:
For figures, there are solutions to this question. I have a Simulink block diagram, it's different (see below).
I am aware of solutions using additional software like pdfcrop.
PDF seems to be the only driver that really produces vector graphics (R2013b on Win7 here). The EPS and PS output seems to have bitmaps inside. You zoom, you see it.
What I have tried:
1.
The default behaviour of print
modelName = 'vdp'; % example system
load_system(modelName); % load in background
% print to file as pdf and as jpeg
print(['-s',modelName],'-dpdf','pdfOutput1')
print(['-s',modelName],'-djpeg','jpegOutput1')
The JPEG looks good, tight bounding box. The PDF is centered on a page that looks like A4 or usletter. Not what I want.
2.
There are several parameters for printing block diagrams. See the Simulink reference page http://www.mathworks.com/help/simulink/slref/model-parameters.html. Let's extract some:
modelName = 'vdp'; % example system
load_system(modelName); % load in background
PaperPositionMode = get_param(modelName,'PaperPositionMode');
PaperUnits = get_param(modelName,'PaperUnits');
PaperPosition = get_param(modelName,'PaperPosition');
PaperSize = get_param(modelName,'PaperSize');
According to the documentation, PaperPosition contains a four element vector [left, bottom, width, height]. The last two elements specify the bounding box, the first two specify the distance of the lower left corner of the bounding box from the lower left corner of the paper.
Now when I print the PDF output and measure using a ruler, I find the values of both the bounding box and the position of its lower left corner are totally wrong (Yes, I have measured in PaperUnits). That's a real bummer. I could have calculated the margins to trim off the paper to be used later in \includegraphics[clip=true,trim=...]{pdfpage}.
3.
Of course what I initially wanted is a PDF that is already cropped. There is a solution for figures, it goes like this: You move the bounding box to the lower left corner of the paper and than change the paper size to the size of the bounding box.
oldPaperPosition = get_param(modelName,'PaperPosition');
set_param(modelName,'PaperPositionMode','manual');
set_param(modelName,'PaperPosition',[0 0 oldPaperPosition(3:4)]);
set_param(modelName,'PaperSize',oldPaperPosition(3:4));
For simulink models, there are two problems with this. PaperSize is a read-only parameter for models. And changing the PaperPosition has no effect at all on the output.
I'm running out of ideas, really.
EDIT ----------------------------------
Allright, to keep you updated: I talked to the Matlab support about this.
In R2013b, there are bugs causing wrong behaviour of PaperPositionMode and the bounding box from PaperPostion to be wrong.
There is no known way to extract the scale factor from print.
They suggested to go this way: Simulink --(print)--> SVG --(Inkscape)--> PDF. It works really good this way. The (correct) bounding box is an attribute of the svg node and the scale factor when exporting to SVG is always the same. Furthermore, Inkscape produces an already cropped PDF. So this approach solves all my problems, just you need Inkscape.

You can try export_fig to export your figures. WYSIWYG! This function is especially suited to exporting figures for use in publications and presentations, because of the high quality and portability of media produced.

Why you don't like to use pdfcrop?
My code works perfectly, and everything is inside Matlab:
function prints(name)
%%Prints Print current simulink model screen and save as eps and pdf
print('-s', '-depsc','-tiff', name)
print('-s', '-dpdf','-tiff', name)
dos(['pdfcrop ' name '.pdf ' name '.pdf &']);
end
You just have to invoke pdfcrop using "dos" command, and it's works fine!

on 2021a you have exportgraphics.
beatiful pdf images.
figure(3);
plot(Time.Data,wSOHO_KpKi.Data,'-',Time.Data,Demanded_Speed.Data,'--');
grid;
xlh = xlabel('$\mathrm{t\left [ s \right ]}$','interpreter','latex',"FontSize",15);
ylh = ylabel('$\mathrm{\omega _{m}\left [ rads/s \right ]}$','interpreter','latex',"FontSize",15);
xlh.Position(2) = xlh.Position(2) - abs(xlh.Position(2) * 0.05);
ylh.Position(1) = ylh.Position(1) - abs(ylh.Position(1) * 0.01);
exportgraphics(figure(3),'Grafico de Escalon Inicial velocidad estimada por algoritmo SOHO-KpKi.pdf');

Related

How to open a txt file of IR temperatures as an image in matlab or other analysis software

I am using a therm-app camera to take infra-red photos of bats. I would like to draw around parts of the bat and find the hottest, coldest and average temperature and do further analysis.
The software that comes with the camera doesn't let me draw polygons so I would like to load the image in another program such as MATLAB or maybe imageJ (also happy to use Python or other if that would work).
The camera creates 4 files total:
I have a .jpg file, however when I open this in MATLAB it just appears as an image and I think it is just opening as a normal image, not sure how to accurately get the temperatures from this. I used the following to open it:
im=imread('C:\18. Bats\20190321_064039.jpg');
imshow(im);
I also have three other files, two are metadata (e.g. show date-time emissivity settings etc.) and one is a text file.
The text file appears to show the temperature of every pixel in the image.
e.g. (for a photo that had a minimum temperature of 15deg and max of 20deg it would be a text file with a minimum value of 1500 and maximum value of 2000)
1516 1530 1530 1540 1600 1600 1600 1600 1536 1536 ........
This file looks very useful, just wondering if there is some way I can open this as an image, probably in a program like MATLAB, which I think has image analysis so that I could draw around certain parts of the image (e.g. the wing of the bat) and find the average, max, min etc.
Has anyone had experience with this type of thing, can I just assign colours to numbers somehow? Or maybe other people have done it already and there is a much easier way. I will keep searching on the internet also and try to find out.
Alternatively maybe I need to open the .jpg image, draw around different parts, write a program to find out which pixels I drew around, find these in the txt file and then do averaging etc? Or somehow link the values in the text file to the .jpg file.
Sorry if this is the wrong place to ask, I can't find an image processing site on stack exchange.
All help is really appreciated, I will continue searching on the internet in the meantime.
the following worked in the end, it was much much easier than I thought it would be. Now a big fan of MATLAB, I thought it could take days to do this.
Just pasting here in case it is useful to someone else. I'm sure there is a more elegant way to write the code, however this is the first time I've used MATLAB in 20 years :p Use at your own risk, I haven't double checked I'm getting the correct results yet (though will do before I use it for anything important).
edit, since writing this I've found that the output .txt file of temperatures is actually sensor temperatures which need to be corrected for emissivity and background temperature to obtain the target temperatures. (One way to do this is to use the software which comes free with the camera to create new output .csv files of temperatures and use those instead).
Thanks to bla who put me on the right track with dlmread.
M=dlmread('C:\18. Bats\20190321_064039\20190321_064039_temps.txt') % read in the text file as a matrix (call it M)
% note that file seems to be a list of temperature values for each pixel
% e.g. 1934 1935 1935 1960 2000 2199...
M = rot90( M , 1 ) % rotate M anti-clockwise by 1*90 (All the pictures were saved sideways for some reason so rotate for easier viewing)
a = min(M(:)); % find the minimum temperature in the image
b = max(M(:)); % find the maximum temperature in the image
imresize(M,1.64); % resize the image to fit the computer screen prior to showing it on the screen
imshow(M,[a b]); % show image on the screen and fit the colours so that white is the value with the highest temperature in the image (b) and black is the lowest (a).
h = drawpolygon('FaceAlpha',0); % Let the user draw a polygon around the region of interest (ROI)
%(this stops code until polygon is drawn)
maskOfROI = h.createMask(); % For each pixel in the image assign a binary number, pixels inside the polygon (ROI) area are given 1 outside are 0
selectedValues = M(maskOfROI); % Now get the image values for all pixels where the mask value is '1' (i.e. all pixels within the polygon) and call this selectedValues.
averageTemperature = mean(selectedValues); % Get the mean of selectedValues (i.e. mean of the temperatures inside the polygon area)
maxTemperature = max(selectedValues); % Get the max of selectedValues
minTemperature = min(selectedValues); % Get the min of selectedValues

Interpolation between two images with different pixelsize

For my application, I want to interpolate between two images(CT to PET).
Therefore I map between them like that:
[X,Y,Z] = ndgrid(linspace(1,size(imagedata_ct,1),size_pet(1)),...
linspace(1,size(imagedata_ct,2),size_pet(2)),...
linspace(1,size(imagedata_ct,3),size_pet(3)));
new_imageData_CT=interp3(imagedata_ct,X,Y,Z,'nearest',-1024);
The size of my new image new_imageData_CT is similar to PET image. The problem is that data of my new image is not correct scaled. So it is compressed. I think the reason for that is that the pixelsize between the two images is different and not involved to the interpolation. So for example :
CT image size : 512x512x1027
CT voxel size[mm] : 1.5x1.5x0.6
PET image size : 192x126x128
PET voxel size[mm] : 2.6x2.6x3.12
So how could I take care about the voxel size regarding to the interpolation?
You need to perform a matching in the patient coordinate system, but there is more to consider than just the resolution and the voxel size. You need to synchronize the positions (and maybe the orientations also, but this is unlikely) of the two volumes.
You may find this thread helpful to find out which DICOM Tags describe the volume and how to calculate transformation matrices to use for transforming between the patient (x, y, z in millimeters) and volume (x, y, z in column, row, slice number).
You have to make sure that the volume positions are comparable as the positions of the slices in the CT and PET do not necsesarily refer to the same origin. The easy way to do this is to compare the DICOM attribute Frame Of Reference UID (0020,0052) of the CT and PET slices. For all slices that share the same Frame Of Reference UID, the position of the slice in the DICOM header refers to the same origin.
If the datasets do not contain this tag, it is going to be much more difficult, unless you just put it as an assumption. There are methods to deduce the matching slices of two different volumes from the contents of the pixel data referred to as "registration" but this is a science of its own. See the link from Hugues Fontenelle.
BTW: In your example, you are not going to find a matching voxel in both volumes for each position as the volumes have different size. E.g. for the x-direction:
CT: 512 * 1.5 = 768 millimeters
PET: 192 * 2.6 = 499 millimeters
I'll let to someone else answering the question, but I think that you're asking the wrong one. I lack context of course, but at first glance Matlab isn't the right tool for the job.
Have a look at ITK (C++ library with python wrappers), and the "Multi-modal 3D image registration" article.
Try 3DSlicer (it has a GUI for the previous tool)
Try FreeSurfer (similar, focused on brain scans)
After you've done that registration step, you could export the resulting images (now of identical size and spacing), and continue with your interpolation in Matlab if you wish (or with the same tools).
There is a toolbox in slicer called PETCTFUSION which aligns the PET scan to the CT image.
you can install it in slicer new version.
In the module's Display panel shown below, options to select a colorizing scheme for the PET dataset are provided:
Grey will provide white to black colorization, with black indicating the highest count values.
Heat will provide a warm color scale, with Dark red lowest, and white the highest count values.
Spectrum will provide a warm color scale that goes cooler (dark blue) on the low-count end to white at the highest.
This panel also provides a means to adjust the window and level of both PET and CT volumes.
I normally use the resampleinplace tool after the registration. you can find it in the package: registration and then, resample image.
Look at the screensht here:
If you would like to know more about the PETCTFUSION, there is a link below:
https://www.slicer.org/wiki/Modules:PETCTFusion-Documentation-3.6
Since slicer is compatible with python, you can use the python interactor to run your own code too.
And let me know if you face any problem

Same default figure position and size independent of screen resolution on different computers

I work with MATLAB on the right half of the screen, so I want figures to open on the left half of the screen. However, the figure height should be about the size of a default figure, so not the height of the screen. Also, I use MATLAB on different computers with variable screen sizes (pixels), so figure dimensions should depend on the screen size, but produce identical figures on screen. The figure dimensions and position are therefore dependent on the screen resolution, but the code generating the dimensions and position should be independent on it.
I've accomplished this with the code in my answer below, which I thought I'd share for anyone who finds this useful for their own setup.
The default MATLAB current folder can be set in MATLAB's preferences. I've set this to the network folder on all my MATLAB computers, this can also be a cloud folder of a cloud service, e.g. Dropbox. Then I put a file startup.m in that folder containing the following code.
ss = get(0,'screensize');
b = 7; % border around figures is 7 pixels wide
%TODO different for various operating systems and possibly configurations.
p = 0; % extra padding pixels from left edge of screen
if ispc
win = feature('getos');
i = (1:2) + regexp(win,'Windows ','end');
switch win(i)
case '10'
b = 0;
p = 2;
otherwise
% other cases will be added in the future
end
end
fwp = ss(3)/2-2*b-p; % figure width in pixels
b = b+p;
n = 5;
set(0,'defaultfigureposition',[b ss(4)/n, fwp, ss(4)*(1-2/n)])
clear
Now, every time I start MATLAB, it runs this script and it moves the default figures I create to the left half of the screen with a nice size (the axes are just a little wider than they are tall).
The figure's units are normalised, but they can be set to pixels or whatever measure you like as well. I hope someone will find this a useful script for their setup.
EDIT: I've update the script to keep the default figure units: pixels. This is necessary, because apps such as the curve fitting tool (cftool) or the Classification Learner (classificationLearner) and probably others are bugged with normalised figure units. Their (dialog) windows either don't show up (they are positioned outside your screen area) or are too small or too large.
EDIT 2: I've updated the script for compatibility with Windows 10. The figure windows now have a border of 1 pixel, instead of 7. Also, the figures are padded a bit to the right, because Windows 10 puts them too far to the left. Windows 10 is detected automatically.
TO DO: support additional operating systems (with detection), e.g. Mac, Linux. If you have such a system, please report the following in a comment:
Open MATLAB and copy paste the resulting string from the feature getos command here.
Position the figure against (not on or over) the left edge of the screen and against (not on or over) the right half of the screen and report the figure's position and outerposition here.

How to determine a projected (if 3D) aspect ratio (if set) of a figure in Matlab to specify a proper paper size?

I saw many Q&A here about squeezing space out of Matlab figures. However I want to squeeze space resulted from a possibly fixed aspect, i.e. to choose proper paper size for figure printing when aspect is fixed.
Quite often I work with DEM/map/image thus I use axis image. Now if I want to produce a high resolution image I do something like
set(gcf,'PaperUnits','inches','PaperPosition',[0 0 4 3])
print('-dpng','-r300','somefile.png')
as described in Matlab KB.
The problem here is to determine a proper aspect such that I can specify proper paper size that would leave no white/background stripes on either sides.
Apparently if I have a map (let's say 1000x2000 cells) with aspect ratio of 0.5, and I'm printing it on 4"x3" paper, I'll get background stripes on the sides. This is quite annoying as I'd prefer 1.5"x3" paper + axes & labels or so. Right now I have to manually adjust paper size.
This is inconvenient as I'd like a universal solution. For instance I may print a plot into file that I expect to occupy 4"x3" as well that has no fixed aspect. Or I may want to print a 3D figure. I'm aware of daspect and pbaspect, but how can I know how it is currently drawn?
Perhaps I can derive current 2D aspect from get(gca,'Position') and then scale it to my maximum allowed desired size (e.g., 4"x3") while respecting whether DataAspectRatioMode (?) property is set to manual. Is it the way to proceed or is there a better way?
I am not exactly sure if I understand your problem exactly, but I have used the following commands to create pdf images that are sized exactly to the size of the figure. I have used this for both 2D and 3D figures. The "handle" variable is simply your figure handle.
set(handle,'Units','inches');
set(handle,'PaperUnits','Inches','PaperPositionMode','auto');
P = get(handle,'Position');
set(handle,'PaperSize', [P(3),P(4)]);

Getting rid of interpolation/aliasing in EPS export of matlab?

I have a 2D color-map plot created with imagesc and want to export it as a .eps file using
print -depsc.
The problem is that the "original" image data is from a rather small matrix (131 x 131). When I view the image in the matlab figure window, I can see all the individual pixels if I zoom a bit closer.
When I export to eps, however, there seems to be some interpolation or anti-aliasing going on, in that neighboring pixels get blurred/blended into each other. I don't get the problem if I export a high-resolution tiff, but that format is not an option (as demanded by a publisher).
How can I obtain an eps that preserves the pixely structure of my image without applying interpolation or anti-aliasing?
The blurring actually depends on the rendering software your viewer application or printer uses. To get good results all the time, make each pixel in your image an 8x8 block of pixels of the same color. The blurring then only affects the pixels at the edge of each block. 8x8 blocks are best as they compress without nasty artifacts using DCT compression (sometimes used in eps files).
Old question, but highly ranked in Google, so here is my answer:
Open the .eps-file with a text editor, search for "Interpolate" and change the following "true" to "false". Repeat that step for all Interpolate-statements.
It might also depend on the viewer you're using, but probably just because some viewers ignore the "Interpolate"s...
Had the same problem using plot2svg in Matlab and exporting from Inkscape to eps.