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)
Related
I need to animate a complex figure consisting of a chain of rectangles, forming an arm.
Here is an example of how this arm looks like when not animated :
To animate this figure, I made the following code :
function renderFrame(fig, data)
hold(ax, 'on'); % Need to hold so that new elements of the arm add themselves
showMembers(fig, data); % Create patches and rotate them to the right angle to create members
showJoints(fig, data); % Draw circles at the joints betwwen the members. Use the width of rectangle members
drawnow;
hold(ax, 'off'); % Next rendering will replace this one; No need to hold
end
function rotateMember(fig, data, iMember, rotAngle)
for iAngle = 1:rotAngle
updateMemberAngle(data, i, 1); % Change thew data so the i-th member rotates by 1
renderFrame(fig); % Show frame after the data was changed
end
end
function main()
fig = figure;
ax = gca;
axis(ax, 'equal');
setAxis(data); % Set axis limits and create axis arrows with totalLength of the arm
renderFrame(ax, data);
rotateMember(fig, data, 3, 90); % Rotate 3rd member by 90 degrees
end
main()
But the frames of my animation doesn't clear at all. It results in this figure :
What am I doing wrong ? Is there a way to plot complicated figures with multiple parts and to animate it, by clearing frame ?
I looked into using newplot and nextplot, but MATLAB's documentation on the subject is incomplete, as always. I also tried creating graphic objects and then setting the data at each iteration, but it rejects an exception every time the figure is deleted since "graphics objects are deleted".
It seems to me as if in your approach, you're not erasing the plot when drawing the next frame. Maybe calling cla() prior to drawing the next frame would make it work? However, this may produce a flickering behavior if the redrawing is done in the wrong order.
I suggest taking a look at animation techniques in Matlab to see three different ways to produce animations.
Found a way to clear the axis childrens, except the two axis quivers (arrows).
Here is a code that works properly:
function renderFrame(renderAxes, data)
% CHECK IF THERE ARE MORE GRAPHIC OBJECTS THAN ONLY THE QUIVERS
if ~(length(renderAxes.Children) == 2)
% DELETE EVERYTHING EXCEPT THE AXIS QUIVERS THAT WERE RENDERED AT THE BEGINNING
% MATLAB ADDS NEW GRAPHIC OBJECTS TO THE BEGINNING OF AX.CHILDREN
delete(renderAxes.Children(1:length(renderAxes.Children)-2))
end
showMembers(renderAxes, data); % Create patches and rotate them to the right angle to create members
showJoints(renderAxes, data); % Draw circles at the joints betwwen the members. Use the width of rectangle members
drawnow;
end
function rotateMember(ax, data, iMember, rotAngle)
for iAngle = 1:rotAngle
updateMemberAngle(data, i, 1); % Change thew data so the i-th member rotates by 1
renderFrame(ax, data); % Show frame after the data was changed
end
end
function main()
fig = figure;
ax = gca;
axis(ax, 'equal');
% HOLD AXES AT THE BEGINNING OF THE SCRIPT
hold(ax, 'on');
setAxis(data); % Set axis limits and create axis arrows with totalLength of the arm
renderFrame(ax, data);
rotateMember(ax, data, 3, 90); % Rotate 3rd member by 90 degrees
end
main()
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
EDITTED:
Hii,
sorry not mentioning it earlier, what I need to do is to display 6 images in the same figure at the same time. Besides, at every image (frame) I need to draw some points (my code tracks the moves of the face - the eyes, nose, lips.)
I have 246 images (frames)
this is the main functions I use:
// The points/ coordinates of the lips, eyes and nose of the image "i".
Points = createPointsStructure (landmarks , i , NumOfLandarkPerFrame);
// Draw landmarks and splines on the frame i (and draw/show the frame)
DrawAllPointsOnFace (pointArr , Points , img , 1 , position, i);
Any ideas how can I do it?
I need to write a code that displays 6 images in the same figure (at the same time). and lets the user to choose one of the images to edit it (by clicking on it).
Any help how can I do it?
Thanks in advance.
Here is a simple example to get you started:
function ImagesExample()
%# read images in a cell array
imgs = cell(6,1);
for i=1:6
imgs{i} = imread( sprintf('AT3_1m4_%02d.tif',i) );
end
%# show them in subplots
figure(1)
for i=1:6
subplot(2,3,i);
h = imshow(imgs{i}, 'InitialMag',100, 'Border','tight');
title(num2str(i))
set(h, 'ButtonDownFcn',{#callback,i})
end
%# mouse-click callback function
function callback(o,e,idx)
%# show selected image in a new figure
figure(2), imshow(imgs{idx})
title(num2str(idx))
end
end
Another function to look into is the MONTAGE function from the IPT Toolbox:
%# given the above cell array `imgs`
montage( cat(4,imgs{:}) )
If I try to rotate camera around my current figure with plot3 using
while true; camorbit(0.9,-0.1); drawnow; end
then the rotation periodically hangs for a while (example) even on 8-core MacPro.
Can I make it smooth?
EDIT1:
While there is no solution for my original question yet, I've managed to make a better movie with getframe function. It doesn't allow recording free-hand rotation, though, and is quite buggy in MATLAB2010b for Mac.
%# fix wrong figure position in MATLAB2010b for Mac - depends on your layout
correctedPosition = get(gcf,'Position') + [21 -125 0 0];
fps = 60; sec = 10;
vidObj = VideoWriter('newfile.avi');
vidObj.Quality = 100;
vidObj.FrameRate = fps;
open(vidObj);
for i=1:fps*sec
camorbit(0.9,-0.1);
writeVideo(vidObj,getframe(gcf, correctedPosition));
end
close(vidObj);
EDIT2:
I created a similar thread at MATLAB Central.
EDIT3:
You can try it yourself downloading one of my figures.
I would say it's the large number of points you are drawing that's causing the slowdown. One option is to downsample.. Also you could use lower-level functions to draw (check this related post for a comparison of plot3/scatter3/line performance).
Consider the animation below optimized for speed:
[X Y Z] = sphere(64);
X = X(:); Y = Y(:); Z = Z(:);
%# set-up figure
hFig = figure('Backingstore','off', 'renderer','zbuffer');
%# use lower-level function LINE
line(0.50*[X,X], 0.50*[Y,Y], 0.50*[Z,Z], 'LineStyle','none', 'Marker','.', 'MarkerSize',1, 'Color','r')
line(0.75*[X,X], 0.75*[Y,Y], 0.75*[Z,Z], 'LineStyle','none', 'Marker','.', 'MarkerSize',1, 'Color','g')
line(1.00*[X,X], 1.00*[Y,Y], 1.00*[Z,Z], 'LineStyle','none', 'Marker','.', 'MarkerSize',1, 'Color','b')
view(3)
%# freeze the aspect ratio to override stretch-to-fill behaviour
axis vis3d
%# fix the axes limits manually
%#set(gca, 'xlim',[-1 1], 'ylim',[-1 1], 'zlim',[-1 1])
axis manual
%# maybe even remove the tick labels
%set(gca, 'xticklabel',[], 'yticklabel',[], 'zticklabel',[])
%# animate (until figure is closed)
while ishandle(hFig); camorbit(0.9,-0.1); drawnow; end
Note how we are using the Z-buffer renderer, and turned off the Backingstore property.
EDIT:
If I understood correctly, what you are trying to do is to record a screencast (using a 3rd-party app), while you manually rotate the figure, but in your case these manual rotations are "jumpy". On the other animating your figure with CAMORBIT/VIEW in a while-loop is running smooth...
I propose an alternative solution: start by rotating the figure using the mouse and write these view configurations at each step (azimuth,elevation). Then you can replay them using the VIEW function while recording the video, something like:
v = [...]; %# matrix where each row specify Az/El of view
for i=1:size(v,1)
view( v(i,:) )
drawnow
end
The downside is that you will have to press/rotate/release using the mouse in small steps (the ROTATE3D object does not expose a mouse-motion event)
I wrote a simple function to help you in this process. It loads the saved figure, enable 3d-rotation, and keeps track of the intermediate position at each step. Once finished, press the "Done" button to return the list of views...
function v = rotationDemo(figFileName)
views = []; %# list of views (Az,El)
hFig = hgload(figFileName); %# load the saved figure
views(1,:) = get(gca,'View'); %# store initial view
%# add a button, used to terminate the process
hButton = uicontrol('Style','pushbutton', 'Position',[400 1 80 20], ...
'String','Done?', 'Callback',#buttonCallback);
set(hFig, 'Toolbar','figure') %# restore toolbar
%# start 3d rotation, and handle post-callback to record intermediate views
h = rotate3d(hFig); %# get rotation object
set(h, 'ActionPostCallback',#rotateCallback)
set(h, 'Enable','on') %# enable rotation
msgbox('Rotate the view step-by-step', 'rotate3d', 'warn', 'modal')
uiwait(hFig) %# wait for user to click button
delete(hButton) %# delete button on finish
set(h, 'Enable','off') %# disable rotation
v = round(views); %# return the list of views
%# callback functions
function rotateCallback(o,e)
views(end+1,:) = get(e.Axes,'View'); %# add current view to list
end
function buttonCallback(o,e)
uiresume(gcbf) %# uiresume(hFig)
end
end
You can call the above function, then replay the animation:
v = rotationDemo('smooth_rotation.fig');
for i=1:size(v,1)
view(v(i,:))
drawnow
end
We can smooth the transitions by simple interpolation:
v = rotationDemo('smooth_rotation.fig');
n = size(v,1);
nn = linspace(1,n,100)'; %'# use 100 steps
vv = round( [interp1(v(:,1),nn) interp1(v(:,2),nn)] );
for i=1:size(vv,1)
view(vv(i,:))
DRAWNOW %# or PAUSE(..) to slow it down
end
As a side note, I should mention that ROTATE3D and CAMORBIT have different effects. ROTATE3D changes the View property of the current axis, while CAMORBIT controls the camera properties CameraTarget/CameraPosition/CameraUpVector of the current axis.
I recognize the same jerking movements that you are talking about on a regular MATLAB Figure. But when I tried running the Amro's code, created a movie (*.AVI), it looks smooth on my Mac notebook also.
The movie making code that I used is the following:
% Added the 'Visible' property of the figure 'off' while making a movie (although I am not exactly certain if this will make the situation better) like so:
hFig = figure('Backingstore','off','visible','off','renderer','zbuffer');
% Then, I replaced Amro's while-loop with a simple AVI production loop, as follows:
aviobj=avifile('test.avi'); %creates AVI file
for I=1:360
camorbit(0.9,-0.1); drawnow;
aviobj=addframe(aviobj,hFig); %adds frames to the AVI file
end
aviobj=close(aviobj); %closes AVI file
close(hFig); %close hFig
Question:
Would it help to decimate some points or to create a density map before rendering the figure?
[Ref. on various Rendering Options: http://www.mathworks.com/support/tech-notes/1200/1201.html ]
I hope the comments above would be of any help.
I don't know if this will help your issue, but for some reason, I've had better success with pause(0.001) than drawnow to force an update of the graphics window
You might also see if rotate3d is faster.
The number of cores doesn't matter as much as you think, as many functions in matlab do not support multi-threading.
A workaround would be to proceed as you are now, but write the figure window to a movie file. Then you can play back the movie.
Let's say I have 9 MxN black and white images that are in some way related to one another (i.e. time lapse of some event). What is a way that I can display all of these images on one surface plot?
Assume the MxN matrices only contain 0's and 1's. Assume the images simply contain white lines on a black background (i.e. pixel value == 1 if that pixel is part of a line, 0 otherwise). Assume images are ordered in such a way as to suggest movement progression of line(s) in subsequent images. I want to be able to see a "side-view" (or volumetric representation) of these images which will show the surface that a particular line "carves out" in its movement across the images.
Coding is done in MATLAB. I have looked at plot (but it only does 2D plots) and surf, which does 3D plots but doesn't work for my MxNx9 matrix of images. I have also tried to experiment with contourslice, but not sure what parameters to pass it.
Thanks!
Mariya
Are these images black and white with simple features on a "blank" field, or greyscale, with more dense information?
I can see a couple of approaches.
You can use movie() to display a sequence of images as an animation.
For a static view of sparse, simple data, you could plot each image as a separate layer in a single figure, giving each layer a different color for the foreground, and using AlphaData to make the background transparent so all the steps in the sequenc show through. The gradient of colors corresponds to position in the image sequence. Here's an example.
function plotImageSequence
% Made-up test data
nLayers = 9;
x = zeros(100,100,nLayers);
for i = 1:nLayers
x(20+(3*i),:,i) = 1;
end
% Plot each image as a "layer", indicated by color
figure;
hold on;
for i = 1:nLayers
layerData = x(:,:,i);
alphaMask = layerData == 1;
layerData(logical(layerData)) = i; % So each layer gets its own color
image('CData',layerData,...
'AlphaData',alphaMask,...
'CDataMapping','scaled');
end
hold off
Directly showing the path of movement a "line" carves out is hard with raster data, because Matlab won't know which "moved" pixels in two subsequent images are associated with each other. Don't suppose you have underlying vector data for the geometric features in the images? Plot3() might allow you to show their movement, with time as the z axis. Or you could use the regular plot() and some manual fiddling to plot the paths of all the control points or vertexes in the geometric features.
EDIT: Here's a variation that uses patch() to draw each pixel as a little polygon floating in space at the Z level of its index in the image sequence. I think this will look more like the "surface" style plots you are asking for. You could fiddle with the FaceAlpha property to make dense plots more legible.
function plotImageSequencePatch
% Made-up test data
nLayers = 6;
sz = [50 50];
img = zeros(sz(1),sz(2),nLayers);
for i = 1:nLayers
img(20+(3*i),:,i) = 1;
end
% Plot each image as a "layer", indicated by color
% With each "pixel" as a separate patch
figure;
set(gca, 'XLim', [0 sz(1)]);
set(gca, 'YLim', [0 sz(2)]);
hold on;
for i = 1:nLayers
layerData = img(:,:,i);
[x,y] = find(layerData); % X,Y of all pixels
% Reshape in to patch outline
x = x';
y = y';
patch_x = [x; x+1; x+1; x];
patch_y = [y; y; y+1; y+1];
patch_z = repmat(i, size(patch_x));
patch(patch_x, patch_y, patch_z, i);
end
hold off