Save animated warp as a GIF file in MATLAB - matlab

I could finally manage to get ripple effect. I animated it and want to save the animation to a GIF file.
But I get a fixed image in the gif file.
The animation works great in MATLAB but I don't know why it won't get saved.
im = imread('peppers.png');
[m,n,~] = size(im);
n = linspace(-4 * pi,4 * pi,n);
m = linspace(-4 * pi,4 * pi,m);
[X,Y] = meshgrid(m,n);
d = (X .^ 2 + Y .^ 2) .^ .5;
d = d / max(d(:));
d = (d - .5) * 2 * pi;
j = 1;
figure(1);
for i = 0 : .2 : 2 * pi
Z = cos(2 * d + i) .* exp(-.01 .* d);
h = warp(X,Y,Z,im);
axis equal; axis off;
f = getframe;
[I,~] = frame2im(f);
[I,cm] = rgb2ind(I,256);
if j == 1
imwrite(I,cm,'B.gif','gif', 'Loopcount',inf);
else
imwrite(I,'B.gif','gif','WriteMode','append','DelayTime',1/24);
end
j = 0;
end
Question 1 How can I save it (or what is the problem with current code)?
Question 2 How can I save it in a way that there is no white background ?
(for example with view([0 45]) and a little zoom)
Thanks,
Edit Thanks to #Ayb4btu, I made some improvements,
However using close all slows thing down, even sometimes getframe captures my desktop!

For some reason the imwrite doesn't like how the figure is being updated. The following inelegant code works by closing the figure and drawing a new one:
clear all, close all, clc
I = imread('peppers.png');
[m,n] = size(I);
n = linspace(-4 * pi,4 * pi,n);
m = linspace(-4 * pi,4 * pi,m);
[X,Y] = meshgrid(m,n);
d = (X .^ 2 + Y .^ 2) .^ .5;
d = d / max(d(:));
d = (d - .5) * 2 * pi;
j = 1;
for p = 0 : .2 : 4 * pi
figure(1)
Z = cos(2 * d + p) .* exp(-.01 .* d);
h = warp(X,Y,Z,I);
axis equal; axis off;
frame = getframe(1);
im = frame2im(frame);
[A,map] = rgb2ind(im,256);
if j == 1
imwrite(A,map,'B.gif','gif', 'Loopcount',Inf,'DelayTime',1/24);
else
imwrite(A,map,'B.gif','gif','WriteMode','append','DelayTime',1/24);
end
j = 0;
close all
end
Use this as a basis and you might be able to figure out where the problem lies.
As for your question 2, this code uses the background color of the figure, though I believe imwrite has a color property that you can play with.

Related

Implementing i(t) function in Matlab

I have a problem in which I have to implement the following question in Matlab.
i(t) = A2 * sin(wr*t) * exp(-alpha*t); for t [0, 10] with step 0.5s
My approach is as follows
clc;
clear;
% Given Data
Vs = 220;
L = 5e-3;
C = 10e-6;
R = 22;
Vo = 50;
% a)
alpha = R / (2 * L);
omega_not = 1 / sqrt(L*C);
omega_r = sqrt( omega_not^2 - alpha^2 );
A2 = Vs / (omega_r * L);
t = 1:0.5:10;
i = A2 * sin( omega_r * t ) .* exp(-alpha * t);
% b)
t1 = pi / omega_r;
% c)
plot(t, i);
But it yields all the values of current equal to zero. Please help me solve the problem.
I think the problem is this part of the expression:
exp(-alpha * t)
When I run your code, -alpha equals -2200. The exponential for such a large negative number is so small that the code returns zero.
>> exp(-200)
ans =
1.3839e-87
>> exp(-1000)
ans =
0

how to improve the running speed of this Matlab code?

I am trying to simulate a motion of some particles.The program seems to be very slow.
I just started lean programming so I dont know where is the problem exactly that make it slow, I think that plotting is take much time.
could some sone suggest me how to improve it?
function folks(N , T)
if nargin < 1
N = 50;
T = 100;
end
A=20;R=50;a=100;r=2;
x0=10*randn(3,N);
v0=0*randn(3,N);
clear c
% Initilazing plot
color = hsv(N);
xh=zeros(1,N);
f=2*max(max(x0));ff=f/1000000;
figure(2),clf
set(gcf,'doublebuffer','on')
hold on, grid on, axis([-1 1 -1 1 -.5 .5]*f)
for j = 1:N
xh(j) = line(x0(1,j),x0(2,j),x0(3,j),'color',color(j,:), ...
'marker','.','markersize',15);
end
title('t = 0','fontsize',18)
rotate3d;
view([1.8,-1.8,1])
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Solving the ode system
tol = 3e-14;
opts = odeset('reltol',tol,'abstol',tol);
X0=[x0(:);v0(:)];
dt=T/1000;
for tnext = dt:dt:10*T
tspan = [tnext-dt tnext];
[T1,X1] = ode45(#odefolk,tspan,X0,opts,r,R,a,A);
X0 = X1(end,:);
if max(abs(X0(1:3*N)))>f
f=1.1*f;
axis([-1 1 -1 1 -1 1]*f)
end
for j=0:N-1
set(xh(j+1),'xdata',X0(3*j+1),'ydata',X0(3*j+2),'zdata',X0(3*j+3))
end
title(sprintf('t = %3.0f %5.0e',tnext),'fontsize',18),
drawnow
end
I tried to save the data in a matrix and then plot every thing in new loop but it make it much slower.
And also its not related to the solver ode45 or the system odefolk
function dx = fkt(~,x,r,R,a,A)
n = length(x); % n = 90 = 6 *N
M = n/6; % M= 15
dx = zeros(n,1);
for i = 1 : 3 : n/2
vx = 0 ; vy = 0 ; vz = 0;
for j = 1 : 3 : n/2
if (i~=j)
vx = x(i) - x(j) ;
vy = x(i+1) - x(j+1);
vz = x(i+2) - x(j+2);
% ex = expo (vx , vy , vz ,r , a);
%
% val = (ex(1) * R - ex(2) * A);
leng = sqrt(vx^ 2 +vy^ 2 + vz^ 2);
expo1 = exp(-1 * leng / r) / r;
expo2 = exp(-1 * leng / a) / a;
val = (expo1 * R - expo2 * A);
vx = vx * val;
vy = vy * val;
vz = vz * val;
end
end
vx = vx/M ;
vy = vy/M;
vz = vz/M;
dx(i) = x(i + 3 * M );
dx(i + 1) = x(i + 3 * M + 1);
dx(i + 2) = x(i + 3 * M + 2);
dx(i + 3 * M ) = vx;
dx(i + 3 * M + 1 ) = vy;
dx(i + 3 * M + 2 ) = vz;
end
end
To perform a code, it's a good idea to analyze it with the Profiler:
https://es.mathworks.com/help/matlab/ref/profile.html
Anyway, I see some things you could change. First, avoid to draw in each iteration. Do it in the end or draw every M interations.
Secondly, avoid using a loop to define the graphic. Plot it with vector type input data.
Thirdly, ode45 can do the iterations for you and can return you a vector with all the interations. Use it to plot.
Some tips:
use tic and toc to measure the execution time of your code (lines, functions, etc.)
preassign arrays and avoid letting them grow in loops
do not use plot in a loop. Try to use low-level commands and change the value of exisiting lines by refering to their handles (like for example handle = line([0 1][2 3][4 5]) and then set(handle,'XDATA',[4 7],'YDATA',[2 6],'ZDATA',[2 4]))
MATLAB is an interpreted language, so your code will run slower in most cases compared to compiled programs

solving integral in rectangular method in matlab

This is my code to make an integration in the rectangular method in the matlab
f=#(x) (x^(1/2))
a = 1
b = 10
% step size
h = 0.25
n = 0 % the counter
xn= a + (n * h)
%%
%Rectangle Method:
s=0
for i =0:n-1
s = s + f(xn)
end
Rectangle = h * s
the answer should be around 20, but i'm getting 29.5
what's the problem?
Two errors:
1) xn is not updated.
2) number of points n is set to zero.
There are other minor issues which I did not fix, e.g. right and left boundary points should both contribute to the sum with weight 1/2.
Quick fix:
f=#(x) (x^(1/2));
a = 1;
b = 10 ;
% step size
h = 0.25;
n = (b-a)/h; % the counter
%%
%Rectangle Method:
s=0;
for i =0:n-1
xn= a + (i * h);
s = s + f(xn);
end
Rectangle = h * s;

matlab function to return an image

I have created a function in matlab which returns an image:
function [BW3] =lineAnalysis( BW1, O)
BW2 = double(BW1 > 0);
BW3 = BW2(2:end, :); % <-- REMOVE 1st LINE (ARTIFACT)!
if O==0; % 1 for left
BW3 = fliplr(BW3); % <-- FLIP IT HERE!
end
BW3_orig = BW3; % <-- SAVE ORIGINAL VERSION
% STEP 1
n = 10; t = 0.9;
c = 0:(n - 1);
j0 = 1;
while mean(mean(BW3(1 + c, j0 + c))) < t
j0 = j0 + 1;
end
% STEP 2
i0 = 1;
while mean(mean(BW3(i0 + c, 1 + c))) < t
i0 = i0 + 1;
end
% STEP 3
a = (1 - j0) / (i0 - 1);
b = j0 - a;
for i = 1:i0
for j = 1:round(a * i + b)
BW3(i, j) = 0;
end
end
% STEP 4
w = 20;
for i = 1:round(i0 - w / a)
for j = max(1, round(a * i + b + 1)):round(a * i + b + w)
BW3(i, j) = 1;
end
end
% PLOT RESULT
[BW3] = size(BW3);
[nr, nc] = size(BW3);
% figure
subplot(122), imagesc(BW3), colormap(gray)
axis equal off, axis([1, nc, 1, nr]), title('Corrected')
This works perfectly.
However I would like to return the result in my main program instead of executing the line
imshow(BW3);
within the function.
I have tried doing this:
[BW3]=lineAnalysis(P, O);
I then tried to show the image by doing
imshow(BW3);
However this doesnt work when I show the image like this. It simply diplays one black image and one white image.
Can anyone tell me how to fix this??
Thanks :)
The problem is near the end of your code:
function [BW3] =lineAnalysis( BW1, O)
%% your calculations here
% PLOT RESULT
[BW3] = size(BW3);
imshow(BW3);
In the line [BW3] = size(BW3); you are replacing the image with a 2 element vector that has the numbers of rows and columns of your image.

Double Summation in MATLAB and vectorized loops

Here's my attempt in implementing this lovely formula.
http://dl.dropbox.com/u/7348856/Picture1.png
%WIGNER Computes Wigner-Distribution on an image (difference of two images).
function[wd] = wigner(difference)
%Image size
[M, N, ~] = size(difference);
%Window size (5 x 5)
Md = 5;
Nd = 5;
%Fourier Transform
F = fft2(difference);
%Initializing the wigner picture
wd = zeros(M, N, 'uint8');
lambda =0.02;
value = (4/(Md*Nd));
for x = 1+floor(Md/2):M - floor(Md/2)
for y = 1+floor(Nd/2):N - floor(Nd/2)
for l = -floor(Nd/2) : floor(Nd/2)
for k = -floor(Md/2) : floor(Md/2)
kernel = exp(-lambda * norm(k,l));
kernel = kernel * value;
theta = 4 * pi * ((real(F(x, y)) * (k/M) )+ (imag(F(x, y)) * (l/N)));
wd(x, y) = (wd(x, y)) + (cos(theta) * difference(x + k, y + l) * difference(x - k, y - l) * (kernel));
end
end
end
end
end
As you can see, the outer two loops are for the sliding window, while the remaining inner ones are for the variables of the summation.
Now, my request for you my beloved stackoverflow users is: Can you help me improve these very nasty for loops that take more than its share of time, and turn it into vectorized loops?
And will that improvement be of a significant change?
Thank you.
this might not be what you are asking, but it seems (at first glance) that the order of the summations are independent and that instead of {x,y,l,k} you could go {l,k,x,y}. doing this will allow you to evaluate kernel fewer times by keeping it in the outer most loop.
Those four nested loops are basically processing each pixel in the image in a sliding-neighborhood style. I immediately thought of NLFILTER and IM2COL functions.
Here is my attempt at vectorizing the code. Note that I haven't thoroughly tested it, or compared performance against loop-based solution:
function WD = wigner(D, Md, Nd, lambda)
%# window size and lambda
if nargin<2, Md = 5; end
if nargin<3, Nd = 5; end
if nargin<4, lambda = 5; end
%# image size
[M,N,~] = size(D);
%# kernel = exp(-lambda*norm([k,l])
[K,L] = meshgrid(-floor(Md/2):floor(Md/2), -floor(Nd/2):floor(Nd/2));
K = K(:); L = L(:);
kernel = exp(-lambda .* sqrt(K.^2+L.^2));
%# frequency-domain part
F = fft2(D);
%# f(x+k,y+l) * f(x-k,y-l) * kernel
C = im2col(D, [Md Nd], 'sliding');
X1 = bsxfun(#times, C .* flipud(C), kernel);
%# cos(theta)
C = im2col(F, [Md Nd], 'sliding');
C = C(round(Md*Nd/2),:); %# take center pixels
theta = bsxfun(#times, real(C), K/M) + bsxfun(#times, imag(C), L/N);
X2 = cos(4*pi*theta);
%# combine both parts for each sliding-neighborhood
WD = col2im(sum(X1.*X2,1), [Md Nd], size(F), 'sliding') .* (4/(M*N));
%# pad array with zeros to be of same size as input image
WD = padarray(WD, ([Md Nd]-1)./2, 0, 'both');
end
For what its worth, here is the loop-based version with the improvement that #Laurbert515 suggested:
function WD = wigner_loop(D, Md, Nd, lambda)
%# window size and lambda
if nargin<2, Md = 5; end
if nargin<3, Nd = 5; end
if nargin<4, lambda = 5; end
%# image size
[M,N,~] = size(D);
%# frequency-domain part
F = fft2(D);
WD = zeros([M,N]);
for l = -floor(Nd/2):floor(Nd/2)
for k = -floor(Md/2):floor(Md/2)
%# kernel = exp(-lambda*norm([k,l])
kernel = exp(-lambda * norm([k,l]));
for x = (1+floor(Md/2)):(M-floor(Md/2))
for y = (1+floor(Nd/2)):(N-floor(Nd/2))
%# cos(theta)
theta = 4 * pi * ( real(F(x,y))*k/M + imag(F(x,y))*l/N );
%# f(x+k,y+l) * f(x-k,y-l)* kernel
WD(x,y) = WD(x,y) + ( cos(theta) * D(x+k,y+l) * D(x-k,y-l) * kernel );
end
end
end
end
WD = WD * ( 4/(M*N) );
end
and how I test it (based on what I understood from the paper you previously linked to):
%# difference between two consecutive frames
A = imread('AT3_1m4_02.tif');
B = imread('AT3_1m4_03.tif');
D = imsubtract(A,B);
%#D = rgb2gray(D);
D = im2double(D);
%# apply Wigner-Distribution
tic, WD1 = wigner(D); toc
tic, WD2 = wigner_loop(D); toc
figure(1), imshow(WD1,[])
figure(2), imshow(WD2,[])
you might then need to scale/normalize the matrix, and apply thresholding...