Saving image of specific area of GUI in matlab - matlab

I have devloped a GUI which browses mat files and draw plots in matlab now I want to save these plots as images using a save button in my GUI
I did the coding of save callback function as
[file,path]=uiputfile({'*.bmp','BMP'},'Save Image As');
f=getframe(handles.axes);
[x,map]=frame2im(f);
imwrite(x,fullfile(path, file),'bmp');
But this code gives me just the graph without its axis labelled.
Someone suggested me to use explore_fig but i am unable to use it for my purpose
If I want to save specific area of my GUI as an image what code should I use
Thanks

As you have noticed, using getframe it grabs solely the contents of the axes and no more. In order to get the axes labeled, you can take advantage of the TightInset property of the axes to find the bounding rectangle of the axes. The TightInset is the margin that is added to the axes Position to make room for labels.
Also, you can take advantage of the second input to getframe which specifies the rect (in pixels) to grab. You can compute this using hgconvertunits (undocumented).
% Position INCLUDING labels/ticks
position = get(hax, 'Position');
inset = get(hax, 'TightInset');
outerpos = [position(1:2) - inset(1:2), position(3:4) + inset(3:4)];
% Ensure that the units are PIXELS
rect = hgconvertunits(hfig, outerpos, get(hax1, 'Units'), 'pixels', hfig);
% Grab only the specified rectangle from the figure
im = getframe(hfig, rect);
If we do this on some sample data
% Load Sample Data
load mri
img = squeeze(D(:,:,12));
% Display axes in middle of figure
hfig = figure();
hax = axes('Position', [0.2 0.2 0.5 0.5]);
imagesc(img);
xlabel('columns');
ylabel('rows');
axis image;
The original looks like this
And the result of getframe with a rect is

Related

Prevent Color Bar from Resizing Image in MATLAB

I am trying to add color bars to an image in MATLAB without losing the original resolution of the figure.
This link explains how to deal with the fact that adding a color bar resizes the original image. But the solution makes the original loose information by enlarging using interpolation (the set method used in the 6th line from the bottom). It is crucial to my application that this does not happen (Trying to observe Moire effects on sub-sampling)
The code I am using is appended below
%% Load images using relative paths
path1 = '../data/circles_concentric.png';
path2 = '../data/barbaraSmall.png';
img1 = imread(path1, 'png');
img2 = imread(path2, 'png');
%Shrinking factor
d1 = 2;
d2 = 3;
img1_shrunk1 = myShrinkImageByFactorD(img1, d1);
imshow(img1_shrunk1);
colorbar(gca);
img1_shrunk2 = myShrinkImageByFactorD(img1, d2);
figure, imshow(img1_shrunk2);
colorbar(gca);
I have dealt with this problem by simply putting the colorbar in a separate axis.
%Import image and colormap
[img,map]=imread('image.tif');
%Create figure and show the image on ax1
fig=figure;
ax1=axes(fig);
imshow(img,map,'Parent',ax1);
%Create ax2 and make it invisible
ax2=axes(fig,...
'Position',[ax1.Position(1)+ax1.Position(3),ax1.Position(2),0.2,0.7]);
axis off
set(ax2,'color','none');
%Apply colormap to ax2 and, colorbar and adjust CLim
colormap(map);
colorbar(ax2,'Position',...
[ax1.Position(1)+ax1.Position(3)+0.03,0.1,0.05,0.7],...
'AxisLocation','in');
ax2.CLim=[minValue,maxValue];

How to have an image in background of plot in matlab

I have a plot from a network of lines in 3D space and I have one image from the object as well. Now I want to put the image file in the background of my plot as a fixed background and then the network should be plotted on that background. By the way, since the Network is in 3D space I can rotate it easily and it is important for me rotate the network on the my combined plot as well.
this is my code that I have written but it shows my plot separately! if I put imshow inside the figure then image will be ploted on the top of my network and I can see only one point of my network. Here is the link of Network and the background image from background
Here is my code: the first line plot the image and the rest of the code plot my network of lines:
Img1 = imshow('STP1.png');
figure('name','Distance');
hold on;
labels = cellstr( num2str([1:SIFT_Length]') );
text(SIFT_3D(:,1), SIFT_3D(:,2),SIFT_3D(:,3),labels,'FontWeight','bold','FontSize', 12,...
'VerticalAlignment','bottom','HorizontalAlignment','right')
title('Distances Network with colorized lines based on Uncertainty','FontWeight','bold');
hold on
for k = 1:Num_Line_SIFTS
plot3([SIFT_3D(Line_among_2_Sifts(k,1),1),SIFT_3D(Line_among_2_Sifts(k,2),1)],...
[SIFT_3D(Line_among_2_Sifts(k,1),2),SIFT_3D(Line_among_2_Sifts(k,2),2)],...
[SIFT_3D(Line_among_2_Sifts(k,1),3),SIFT_3D(Line_among_2_Sifts(k,2),3)],...
'o-','Color',[RGB_0_1(k,1) RGB_0_1(k,2) RGB_0_1(k,3)],'MarkerFaceColor',[RGB_0_1(k,1) RGB_0_1(k,2) RGB_0_1(k,3)],'MarkerEdgeColor',...
'k', 'LineWidth',2)
end
hold off;
Please help me how can I solve this issue.
What about this:
clear
clc
close all
%// Read image
Im=flipud(imread('STP1_low.png'));
%// Dummy surface to plot.
Z = peaks(25);
%// Prepare image position
shift = 20;
xIm=zeros(size(Z))-shift;
hold on
surface(xIm,Im,'FaceColor','texturemap','EdgeColor','none','CDataMapping','direct')
surface(Z,'FaceAlpha',0.8,'LineStyle','none','FaceColor','interp');
axis on
view(-35,45)
box on
rotate3d on
Output:
You can rotate it and the image stays as the background.
I'm not sure I understood your need, nevertheless ...
figure('name','Distance','unit','normalized');
a=axes('position',[0 0 1 1])
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% UPDATED CODE STARTS HERE
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Disable zoom
h=zoom;
setAllowAxesZoom(h,a,false);
% Disable rotation
h = rotate3d;
setAllowAxesRotate(h,a,false)
%
%%%%%%%%%%%%%%%%%%%%%%%%%%
% UPDATED CODE ENDS HERE
%%%%%%%%%%%%%%%%%%%%%%%%%%
%
hold on
imshow('Jupiter_New_Horizons.jpg','parent',a)
t=0:.01:2*pi;
z=sin(t).*cos(t)
a1=axes('position',[0.3 0.3 .5 .5])
plot3(cos(t),sin(t),z,'r','linewidth',3)
grid on
set(gca,'color','none')
This script generates the following graph:
Hope this helps.

Include axes labels when saving plot from MATLAB GUI

I have written the following code to try and retrieve ONLY the axes and its plot from my MATLAB GUI.
F = getframe(gca);
figure();
image(F.cdata);
saveas(gcf,'PlotPic','png');
close(gcf);
I noticed, however, that this method does not include ANY of my axis labels or title. Is there any way which I can get the getframe function to include the axis labels and title?
I tried the following code but it did exactly the same
pl = plot(x,y);
xlabel('x')
ylabel('y')
ftmp = figure;
atmp = axes;
copyobj(pl,atmp);
saveas(ftmp,'PlotPic.png');
delete(ftmp);
I would do it using the rect option of the getframe function.
Basically you can provide a 2nd input argument to getframe, which then captures the content of the rectangle specified as argument. The nice thing is that you can use the handles to an axes, so it does not capture your whole GUI figure but rather a specific axes.
For example, using this line:
F = getframe(gca,RectanglePosition);
Concretely, you could set the coordinates of the rectangle such that they span both axis labels and the title as well. Here is a sample code. The pushbutton callback executes getframe and opens a new figure with the content of F.cdata:
function GUI_GetFrame
clc
clear
close all
%// Create GUI components
hFigure = figure('Position',[100 100 500 500],'Units','Pixels');
handles.axes1 = axes('Units','Pixels','Position',[60,90,400,300]);
handles.Button = uicontrol('Style','Push','Position',[200 470 60 20],'String','Get frame','Callback',#(s,e) GetFrameCallback);
%// Just create a dummy plot to illustrate
handles.Period = 2*pi;
handles.Frequency = 1/handles.Period;
handles.x = 0:pi/10:2*pi;
handles.y = rand(1)*sin(handles.Period.*handles.x);
plot(handles.x,handles.y,'Parent',handles.axes1)
title('This is a nice title','FontSize',18);
guidata(hFigure,handles); %// Save handles structure of GUI.
function GetFrameCallback(~,~)
handles = guidata(hFigure);
%// Get the position of the axes you are interested in. The 3rd and
%// 4th coordinates are useful (width and height).
AxesPos = get(handles.axes1,'Position');
%// Call getframe with a custom rectangle size.You might need to change this.
F = getframe(gca,[-30 -30 AxesPos(3)+50 AxesPos(4)+80]);
%// Just to display the result
figure()
imshow(F.cdata)
end
end
The GUI looks like this:
And once I press the pushbutton, this is the figure that pops up:
So the only trouble you have is to figure out the dimensions of the rectangle you need to select to capture the axis labels and the title.
Hope that solves your problem!

Resizeable Legend in Matlab GUI or Legend Scroll Bar

In Matlab I have a GUI that analyses and plots data on to a plot in my main figure of the GUI. I often have to plot a lot of different data sets though with it and have two main problems:
I cannot set a fixed size area for the legend to be constructed in
I cannot work out how to make the legend text and box scale when the GUI is full screened
One solution I was thinking about is a scroll bar in the legend, is this possible? Hopefully the image below highlights the problem:
Here is a solution that will scale the legend with whatever scaling factor you desire:
close all;
% Generate data
N = 10;
T = 10;
x = rand(T, N);
% How much to scale by
xLegScale = 0.5;
yLegScale = 0.5;
% Plot some data
labels = arrayfun(#(n){sprintf('Legend Entry for Line %i', n)}, 1:N);
plot(x, 'LineWidth', 2);
hLeg = legend(labels);
% Figure out new legend width / height, including a little fudge
legPos = get(hLeg, 'Position');
widthFudgeFactor = 0.1;
legPosNew = legPos;
legPosNew(3:4) = legPosNew(3:4) .* [xLegScale yLegScale];
legPosNew(3) = legPosNew(3) * (1 + widthFudgeFactor);
% Create a new axes that matches the legend axes and copy all legend
% children to it, then delete the legend
axNew = axes('Parent', gcf);
xlim(axNew, get(hLeg, 'XLim'));
ylim(axNew, get(hLeg, 'YLim'));
box(axNew, 'on');
set(axNew, 'Position', legPosNew);
set(axNew, 'XTick', [], 'YTick', []);
copyobj(get(hLeg, 'Children'), axNew)
delete(hLeg);
hLeg = axNew;
% Find text objects inside legend
hLegTexts = findobj('Parent', hLeg, 'Type', 'text');
% Scale font size
legTextFontSize = get(hLegTexts, 'FontSize');
fszScale = mean([xLegScale yLegScale]);
legTextFontSizeNew = cellfun(#(x){fszScale * x}, legTextFontSize);
arrayfun(#(h, fontSize)set(h, 'FontSize', fontSize{:}), hLegTexts, legTextFontSizeNew);
This code creates a new axes that is a facsimile of the original legend axes and does all the position setting work on that. The reason is that the legend object doesn't like being resized smaller than it thinks it should be (presumably there is some code doing this when it resizes, but there is no ResizeFcn property for axes objects, so I can't see a way to disable this functionality aside from making a copy of the axes).
The only thing inside the axes you actually need to scale is the font size: the rest will be scaled automatically due to the use of normalized units.
If this kind of scaling solution doesn't tickle your fancy, then you could do something similar (copy the legend axes children) but add a scrollbar to the new axes (and set its units to something other than normalized so that it doesn't scale its contents when you resize it). You might draw some inspiration for how to do the scrolling from this question.

using slider to rotate image in Matlab

I have a GUI (using GUIDE) in Matlab, this is how it looks:
I want to rotate the image using slider and to show the change in real time.
I use axes to display the image.
how can I do this?
EDIT: I'm building OCR application. this is how the plate looks when I'm rotate it, the numbers are totally deformed.
thanks.
Here is an example GUI:
function rotationGUI()
%# read image
I = imread('cameraman.tif');
%# setup GUI
hFig = figure('menu','none');
hAx = axes('Parent',hFig);
uicontrol('Parent',hFig, 'Style','slider', 'Value',0, 'Min',0,...
'Max',360, 'SliderStep',[1 10]./360, ...
'Position',[150 5 300 20], 'Callback',#slider_callback)
hTxt = uicontrol('Style','text', 'Position',[290 28 20 15], 'String','0');
%# show image
imshow(I, 'Parent',hAx)
%# Callback function
function slider_callback(hObj, eventdata)
angle = round(get(hObj,'Value')); %# get rotation angle in degrees
imshow(imrotate(I,angle), 'Parent',hAx) %# rotate image
set(hTxt, 'String',num2str(angle)) %# update text
end
end
If you prefer to build the GUI in GUIDE, follow these steps:
create GUI, and add necessary components: axis, slider, static text (drag-and-drop)
Using the "Property Inspector", change slider properties as required:: Min/Max/Value/SliderStep. Also would help if you assign a Tag to be able to find components in the code.
In the figure's xxxx_OpeningFcn function, read and store the image in the handles structure, then show it:
handles.I = imread('cameraman.tif');
imshow(I, 'Parent',findobj(hObject,'Tag','imgAxis')) %# use tag you assigned
guidata(hObject, handles); %# Update handles structure
Create a callback event handler for your slider, and add the code:
angle = round( get(hObject,'Value') );
imshow( imrotate(handles.I,angle) )
EDIT:
Image rotation is an affine transformation which maps the position (x,y) of input image pixels onto new coordinates (x2,y2) for the output image. The problem is that the output coordinates may not always be integers. Since digital images are represented on a grid of discrete pixels, thus some form of resampling/interpolation is employed (which is why straight lines might look jagged when rotated at certain angles).
(Illustration borrowed from: Understanding Digital Image Interpolation)