Matlab - create .gif file from a series of fig - matlab

So, as I browse through google on the problem of how to create a .gif animation from series of .fig files, i stumble through one that uses .sdf file, I tried to rewrite the program to work for my .fig files
clear all;
close all;
dynam = 156;
gif_fps = 24;
video_filename = 'A.gif';
fh = figure(1);
for i = 1:dynam
F_data = getdata(['F' num2str(i,'_%03i', '.fig');
imagesc(F_data);
drawnow;
frame = getframe(fh);
im = frame2im(frame);
[imind,cm] = rgb2ind(im,256);
if a == 0;
imwrite(imind,cm,video_filename,'gif', 'Loopcount',inf);
else
imwrite(imind,cm,video_filename,'gif','WriteMode','append','DelayTime',1/gif_fps);
end
end
so it pops up an error saying
??? frame = getframe(fh);
|
Error: The expression to the left of the equals sign is not a valid target for an assignment.
which I don't understand why this is happening, and I also notice that Matlab is not drawing the figs, the figure that pop us is completely blank.

The error comes from a typo. The line
F_data = getdata(['F' num2str(i,'_%03i', '.fig'); %bracket missing at the end
should read
F_data = getdata(['F' num2str(i,'_%03i', '.fig']);
Without the bracket, Matlab sees
['F' num2str(i,'_%03i', '.fig');
imagesc(F_data);
drawnow;
frame
as a single string of letters. The code's logic is therefore a = b = c and matlab can't interpret this.
To prevent such errors, matlab and its editor have some nice coloring schemes that highlight in dark red the text following an opening string ', and turn the full string in purple when a closing ' is used. If you see some red characters spanning over several lines, that's a sign of a potential problem. Unfortunately, brackets don't have such behavior...
Additionnaly, what about opening the figures per se? You will see if each figure renders well (no blank) and will be able to capture the frame.
for i = 1:dynam
%open, get the frame from and close the figure
fh_tmp = open(['F' num2str(i,'_%03i', '.fig'])
frame = getframe(fh_tmp);
close(fh_tmp);
im = frame2im(frame);
...
I still struggle to find where the getdata is coming from.

Related

MATLAB: After deleting imrect object, can not create another

I'm having a problem when developing a simple program for manual image cropping. I used imrect to let the user drag and create rectangle selected area, and use getPosition(imrect_object) to get the position information for further cropping (using imcrop). I need a feature that I could 'undo' a rectangle selection, so I looked it up on the net and used 'KeyPressFcn' callback. You can see the code in the end for more description. Also an example is at the end.
However, whenever I 'undo' an rectangle creation, I couldn't create another rectangle in the same figure. I got the error 'imageslib:iptPointer:invalidHandleMultipleInput' but I can't find enough information to solve it by myself.
Thanks very much for your help. Any advice is invaluable to me!
Code is here:
The first one is the main program. It used another callback function in another file (shown later).
close all
clear all
clc
global posR;
global Rec;
reference = 'w1DIC'; %specifier of reference file
target = {'w2405','w3488','w4561'}; %specifier of target file
targetBkgClear = 1; %if=1 then cropped target files would be subtracted by background noise which is calculated using borders of the target files.
%--------------READ FILE--------------
%select the dir where the image data are saved
pathdir=uigetdir(pwd,'Select image data dir');
filename1AllStruct=dir(fullfile(pathdir,'*.TIF'));
pathname1=[pathdir '\']; %THIS LINE IS PLATFORM SPECIFIC (WINDOWS)!
filename1={};
cropRegions={};
for i=1:length(filename1AllStruct)
currFileName = filename1AllStruct(i).name;
if strfind(currFileName,reference)
filename1{length(filename1)+1}=currFileName;
end
end
m=length(filename1);
%-------------PROCESS EVERY FILE, GET CROPPING AREAS-------------
for i=1:m
I = imread(strcat(pathname1,filename1{i}));
I = imadjust(I);
posR = {};
imshow(I);
set(gcf,'KeyPressFcn',#keyboard_response); %set keyboard callbacks
while true
try
Rec=imrect;
posR{length(posR)+1}=getPosition(Rec);
catch ME
disp(ME.identifier);
break
end
end
cropRegions{length(cropRegions)+1} = posR;
close all
end
%-------------PROCESS EVERY FILE, USE IMCROP TO CROP AND WRITE RESULTS-------------
for i=1:m
tG = {};
for j=1:length(target)
tG{length(tG)+1} = strrep(filename1{i},reference,target{j});
end
for j=1:length(target)
try
I = imread(strcat(pathname1,tG{j}));
catch
error(sprintf('Target file not found %s',tG{j}));
end
if targetBkgClear==1
bkg = [I(:,1) I(:,end) I(1,:)' I(end,:)'];
bkg = mean(bkg(:));
I = I-bkg;
end
for k=1:length(cropRegions{i})
Ji = imcrop(I,cropRegions{i}{k});
outName = strrep(tG{j},target{j},strcat(target{j},sprintf('_%d',k)));
outName = strcat('Crop_',outName);
imwrite(Ji,outName,'TIF');
end
end
end
The callback function is here:
function keyboard_response(fig_obj,event)
global posR;
global Rec;
switch event.Key
case 'C'
imcontrast
case 'c'
imcontrast
case 'u'
size(posR)
Rec
Rec.delete(); %delete most recent rectangle
temp={};
for i=1:length(posR)-1
temp{length(temp)+1} = posR{i};
end
posR = temp;%rewrite rectangle position records
size(posR)
Rec
case 'U'
Rec.delete(); %delete most recent rectangle
temp={};
for i=1:length(posR)-1
temp{length(temp)+1} = posR{i};
end
posR = temp;%rewrite rectangle position records
end
end
Here is an example:
The testing directory has following files:
Testing directory content
Then I ran the main program and select the testing directory.
Then I create two rectangles in the poped figure window:
Two rectangles
Then I press 'u' to 'undo' the last operation and then the second rectangle was deleted.
Then I try to create a new rectangle in the same figure by dragging the mouse. Right after mouse button's up, the figure window closed and I catched the error message 'imageslib:iptPointer:invalidHandleMultipleInput'.
Sorry that I can't provide more links because I'm only allowed to provide two. I'm using MATLAB R2016a.

Why is Matlab placing text spaces in legend using Latex when the figure gets saved as a PDF?

I am trying to put a legend in Matlab figures that include a symbol in Latex. When I plot the figure, the legend looks fine. However, when I export the figure as a PDF, the legend gets spaces put into it. I don't know why this is happening. Sample code is as follows:
set(groot,'defaultLineLineWidth',2,'defaultAxesFontSize',...
12,'defaultAxesFontName','timesnewroman',...
'defaulttextinterpreter','latex')
x0 = 8;
y0 = 5;
width = 5;
height = 4;
kappa1 = 0.1;
kappa2 = 0.5;
f = linspace(0,2*pi,1000);
y1 = sin(f+kappa1*f.^2);
y2 = sin(f+kappa2*f.^2);
figure(1)
hold on
plot(f,y1,'k')
plot(f,y2,'b')
xlabel('Frequency (MHz)')
ylabel('Amplitude')
legend(strcat('\kappa = 0.1 MHz/','\mu','s'),...
strcat('\kappa = 0.5 MHz/','\mu','s'))
grid on;
set(gcf,'units','inches','Position',[x0,y0,width,height],...
'PaperPositionMode','Auto','PaperUnits','Inches',...
'PaperSize',[width, height]);
saveas(gcf,'legendtest.pdf')
It seems like the error happens when I save the file as a PDF. It saves as a JPG just fine. Below are the two images I get. The jpg is:
But the PDF I get is:
I am using Matlab version R2017a on a Mac running OS 10.12.5. Thanks in advance for any help!
This is a known bug. See the bug report according to which it affects the versions from R2014b to R2017a. A workaround is suggested in that bug report as well which is to generate the pdf file by setting the Renderer to opengl i.e.
set(gcf,'Renderer','opengl');
But then the generated pdf file contains a pixel graphic instead of a vector graphic.
Better thing would be to use the respective unicode values which will produce a vector graphic. i.e.
legend([char(954), ' = 0.1 MHz/',char(956),'s'],...
[char(954), ' = 15 MHz/',char(956),'s']); %char(954) equals 'κ', char(956) equals 'μ'
If you want to use italic characters, it is also possible with unicode characters.
legend([char([55349,57093]), ' = 0.1 MHz/',char([55349,57095]),'s'],...
[char([55349,57093]), ' = 15 MHz/',char([55349,57095]),'s']);
%char([55349,57093]) equals '𝜅' (italic κ), char([55349,57095]) equals '𝜇' (italic μ)
Another workaround is to just interpret the whole legend text with Latex:
h = legend(strcat('$\kappa$ = 0.1 MHz/','$\mu$','s'),...
strcat('$\kappa$ = 0.5 MHz/','$\mu$','s'))
set(h,'Interpreter','latex')
It requires some basic Latex knowledge, e.g. you have to wrap all math signs (kappa, mu) with $ and beware if you want to use any special non-english characters. Changes the look of the legend a bit, but arguably for the better.
Btw, you can skip strcat, it does not serve any purpose.
h = legend('$\kappa$ = 0.1 MHz/$\mu$s',...
'$\kappa$ = 0.5 MHz/$\mu$s')
set(h,'Interpreter','latex')
Works just as well, the same goes for the non latex version.

Repeating trials in MatLab

i'm am very new to Matlab but really want improve. For my experiment i want to show a picture which the participant response yes/no to, using two different keys (f&g) and then the next picture is presented and it repeats so onward.
Presenting the picture, using the keys works for far, but i can't get it to repeat the trial. Thus my question is how can i get the program to repeat/loop my trial?
Is there something wrong in my code so far or is there additional coding i should use?
this is my code so far
function try1_6()
cleanupObj= onCleanup(#() myCleanupFxn);
% PRETEST
% Initialize screen with black background
winID = Screen('openWindow',0, [0 0 0]);
%Parameter
backcol=255;
textcol=0;
% Load image file(s)
structimages= [];
TheImagesdir = dir('theImagesdir/*.jpg');
for i=1: length(TheImagesdir);
TheImages = imread(['theImagesdir/' TheImagesdir(i).name], 'JPEG');
% Get width and height
imageX = size(TheImages,2);
imageY = size(TheImages,1);
% Convert to texture
myTexture = Screen('MakeTexture', winID, TheImages);
% Set destination rectangle
destRect = [50 100 50+imageX 100+imageY];
%save to structure
structimages(end+1).filename=TheImagesdir(i).name;
structimages(end).destRect= destRect;
structimages(end).texture= myTexture;
end
%Make triallist
numberOfItems= [5]; %list of all possible items
Nrepeats=4;
Response=0;
TrialList=HH_mkTrialList({numberOfItems Response},Nrepeats);
%PRESENTATION
for trialnum=1:size(TrialList,1)
nitems = TrialList(trialnum,1);
Screen('FillRect', winID,backcol); % makes the screen blank
%displays text
DrawFormattedText(winID,'dkjfghaslkdfglksdjgfh','center','center',textcol);
Screen('Flip', winID)
HH_waitForKeyPress({'space'}); % waits for spacebar to be pressed
Screen('FillRect',winID,backcol);
Screen('Flip',winID);
WaitSecs(1);
%display picture
whichTheImages= randi(length(TheImagesdir)); % randomly selects image for directory
Screen('FillRect',winID,backcol);
Screen('DrawTexture', winID, myTexture, [], destRect);
Screen('Flip', winID);
HH_waitForKeyPress({'f','j'},5)
if resp==-1
break
end
TrialList(trialnum,4)= response; %records response
end
end
function myCleanupFxn()
Screen('CloseAll')
end
There are a number of problems with you code that you need to address. First of all, TrialList is used before it is declared/initialized. The Make triallist block of code seems out of place in the body of the for loop, and should probably be placed before you loop TrialList.
Your second problem is the inner for loop that loads images. Right now, it loads every image found in the directory, on every trial! There is no reason for you to be doing this, and you should be placing this for loop outside the trial loop as well. Furthermore, your original code never worked as intended, because you never save the loaded texture anywhere; myTexture is overwritten by the last image in your folder and that's the only texture you're ever gonna get. So in addition to pre-loading the images before the loop, you need to save them in a data structure so that you can use them later in your trial loop. A simple struct will work nicely here:
structImages = [];
TheImagesdir = dir('theImagesdir/*.jpg');
for i = 1:length(TheImagesdir);
TheImages = imread(['theImagesdir/' TheImagesdir(i).name], 'JPEG');
% Get width and height
imageX = size(TheImages,2);
imageY = size(TheImages,1);
% Convert to texture
myTexture = Screen('MakeTexture', winID, TheImages);
% Set destination rectangle
destRect = [50 100 50+imageX 100+imageY];
%save to structure
structImages(end+1).filename = TheImagesdir(i).name;
structImages(end).destRect = destRect;
structImages(end).texture = myTexture;
end
There are other inconsistencies in your code:
whichTheIamges is defined but not used
resp is used in the comparison if resp==-1 but is not defined
response is saved into TrialList before it is defined
Finally, the biggest problem is Screen('CloseAll', winID); is inside the trial loop, so you tear down your whole presentation platform after the first trial.
FYI, as noted in my comment wrapping your entire script in a try block is really poor practice. I suspect you do this because you want to be able to Ctrl+C mid-task, but there's a better way to do this. If you make your entire script a function then you can use the onCleanup method to execute code whenever your function exits (whether normally, by error, or by interruption). The method goes like this:
function myScript()
%//make your script a function. There is an additional advantages to doing this:
%//function performance is better than script performance.
%//blah-blah-blah
%//setup the cleanup object before opening screen
cleanupObj = onCleanup(#() myCleanupFxn);
%//open the screen
winID = Screen('openWindow',0, [0 0 0]);
%//blah-blah-blah
end
function myCleanupFxn()
%//local function, not visible outside of this file
Screen('CloseAll');
end

MATLAB: Print contents of uipanel to PNG image

I don't know how to accomplish the following in MATLAB. I have a figure which looks like this:
In the figure, I have a panel with many subplots and a scrollbar that allows me to view a portion of the panel.
I want to save the whole contents of the panel to a PNG image file (not just the visible portion), i.e. I want to have a file which is a tall rectangle, and doesn't require scrolling.
The code for generating the figure is as follows:
function draw(obj)
figure;
panel1 = uipanel('Parent',1);
panel2 = uipanel('Parent',panel1);
panelheight = obj.nIterations / 2;
set(panel1,'Position',[0 0 0.97 1]);
set(panel2,'Position',[0 1-panelheight 1 panelheight]); %%
nPlot = 1;
for i=1:obj.nIterations
models = obj.iterations{i};
for nModel=1:length(models)
subplot(obj.nIterations,length(models)*2,nPlot);
nPlot = nPlot + 1;
drawTransitions(models{nModel});
set(gca,'Parent',panel2);
subplot(obj.nIterations,length(models)*2,nPlot);
nPlot = nPlot + 1;
drawRewards(models{nModel});
set(gca,'Parent',panel2);
end
end
s = uicontrol('Style','Slider','Parent',1,...
'Units','normalized','Position',[0.97 0 0.03 1],...
'Value',1,'Callback',{#slider_callback1,panel2,panelheight});
end
I have tried the following, without success.
The saveas funstion saves the whole figure, not just the panel. Also, it clips the invisible portion of the panel.
export_fig(panel2.'file.png') gives just a solid gray image.
Why don't you just scroll your panel and grab the frames and concatenate them all together? Here's some code that will basically do that. I would have posted am image, but I guess I don't have enough points for that. You may need to fiddle with the scrolling, and maybe making the slider invisible, but it works.
function printPanel(pnl,filename)
fig = figure(ancestor(pnl,'figure'));
pnl_units = get(pnl,'units');
fig_units = get(fig,'units');
set(pnl,'units','pixels')
set(fig,'units','pixels')
pnl_rect = getpixelposition(pnl);
fig_rect = getpixelposition(fig);
pnl_height = pnl_rect(4);
fig_height = fig_rect(4);
pnl_rect(2) = -pnl_height;
set(pnl,'position',pnl_rect)
N = ceil(pnl_height/fig_height);
CDATA = cell(N,1);
for i = 1:N
F = getframe(fig);
CDATA{i} = F.cdata;
pnl_rect(2) = pnl_rect(2)+fig_height;
set(pnl,'position',pnl_rect)
drawnow
end
set(pnl,'units',pnl_units)
set(fig,'units',fig_units)
imwrite(cat(1,CDATA{:}),filename)
end
You could get rid of the ui elements and just make a figure with all the subplots, and then export that one, using e.g. print -dpng ....
saveas takes a handle as a first argument. Maybe this does not have to be a figure or model handle, but could be a reference to the contents of the panel.

Different function returns from command line and within function

I have an extremely bizzare situation: I have a function in MATLAB which calls three other main functions and produces two figures for me. The function reads in an input jpeg image, crops it, segments it using kmeans clustering, and outputs 2 figures to the screen - the original image and the clustered image with the cluster centers indicated. Here is the function in MATLAB:
function [textured_avg_x photo_avg_x] = process_database_images()
clear all
warning off %#ok
type_num_max = 3; % type is 1='texture', 2='graph', or 3='photo'
type_num_max = 1;
img_max_num_photo = 100; % 400 photo images
img_max_num_other = 100; % 100 textured, and graph images
for type_num = 1:2:type_num_max
if(type_num == 3)
img_num_max = img_max_num_photo;
else
img_num_max = img_max_num_other;
end
img_num_max = 1;
for img_num = 1:img_num_max
[type img] = load_image(type_num, img_num);
%img = imread('..\images\445.jpg');
img = crop_image(img);
[IDX k block_bounds features] = segment_image(img);
end
end
end
The function segment_image first shows me the color image that was passed in, performs kmeans clustering, and outputs the clustered image. When I run this function on a particular image, I get 3 clusters (which is not what I expect to get).
When I run the following commands from the MATLAB command prompt:
>> img = imread('..\images\texture\1.jpg');
>> img = crop_image(img);
>> segment_image(img);
then the first image that is displayed by segment_image is the same as when I run the function (so I know that the clustering is done on the same image) but the number of clusters is 16 (which is what I expect).
In fact, when I run my process_database_images() function on my entire image database, EVERY image is evaluated to have 3 clusters (this is a problem), whereas when I test some images individually, I get in the range of 12-16 clusters, which is what I prefer and expect.
Why is there such a discrepancy? Am I having some syntax bug in my process_database_images() function? If more code is required from me (i.e. segment_images function, or crop_image function), please let me know.
Thanks.
EDIT:
I found the source of the problem. In my load_image function, after I call img = imread(filename), I convert the image to double: `img = im2double(img);'. When I comment this line out, I get the desired result. Anyone know why this happens? (and also how I can 'close' this question since I have located the problem).
clear all at the top of your function is unnecessary and may be the source of your trouble.
Also, turning off all warnings is a bad idea since it may mask other problems.
Let's look at this code, simplified by removing redundant code or unused code:
function [textured_avg_x photo_avg_x] = process_database_images()
type_num_max = 1;
img_max_num_photo = 100; % 400 photo images
img_max_num_other = 100; % 100 textured, and graph images
for type_num = 1:2:type_num_max %% 1:2:1 => 1
img_num_max = 1; %This nullfiies everything in the if block above anyways
for img_num = 1:img_num_max %% 1:1 => 1
[type img] = load_image(type_num, img_num); %% Input (1,1)
img = crop_image(img);
[IDX k block_bounds features] = segment_image(img);
end
end
end
It looks like this code runs through the double nested for loop exactly once, maybe that is why you get only one answer, three clusters.
Try calling your function on the command line with the same amount of return values as in the function you wrote. Instead of
>> segment_image(img);
Try:
>> [IDX k block_bounds features] = segment_image(img);
Functions in Matlab check how many return values are expected, and may behave differently depending on that.