I'm trying to create an animation in LaTeX using the animate package with two nested loops, in which I draw graphics with Tikz. However, the picture keeps slightly rescaling for the first and last inner iteration. In the minimal example below, I want to draw two moving arrows: One at the top representing the outer layer and one at the bottom for the inner layer.
Notably, this problem vanishes if the inner layer has only one iteration, i.e. if the variable \jlimit is 1. This seems to suggest that something is going wrong on the inner layer.
Has anyone encountered this problem before or can you think of any solutions?
Thanks in advance :)
\documentclass[10pt]{beamer}
\usepackage[utf8]{inputenc}
\usepackage{tikz}
\usepackage{ifthen}
\usepackage{animate}
\newcounter{i} % Outer counter
\setcounter{i}{0}
\newcounter{j} % Inner counter
\def\ilimit{3} % Outer iteration limit
\def\jlimit{5} % Inner iteration limit, rescaling doesn't happen if this is 1
\begin{document}
\begin{frame}[fragile]{Nested animated loops}
\begin{center}
\begin{animateinline}[loop, poster = first, controls]{2}
\whiledo{\thei<\ilimit} { % Starting outer loop
\setcounter{j}{0} % Resetting inner counter
\whiledo{\thej<\jlimit} { % Starting inner loop
\begin{tikzpicture}
\draw [color=black] (-0.5,-1.5) rectangle (4.5, 0.5); % Draw a bounding rectangle
\node[shift={(\thei,0)}] at (0,0) {\Large $\downarrow$};% Draw the first level
\node[shift={(\thej,0)}] at (0,-1) {\Large $\uparrow$}; % Draw the second level
\end{tikzpicture}
\stepcounter{j} % Increase the inner counter
\ifthenelse{\thej<\jlimit} {
\newframe % Draw a new inner frame
}{}
}
\stepcounter{i} % Increase the outer counter
\ifthenelse{\thei<\ilimit} {
\newframe % Draw a new outer frame
}{
\end{animateinline}\relax % BREAK % End the animation
}
}
\end{center}
\end{frame}
\end{document}
The problem are the unprotected line endings, which are interpreted by tex as spaces. Add % signs at the end of lines to avoid this problem:
\documentclass[10pt]{beamer}
\usepackage[utf8]{inputenc}
\usepackage{tikz}
\usepackage{ifthen}
\usepackage{animate}
\newcounter{i} % Outer counter
\setcounter{i}{0}
\newcounter{j} % Inner counter
\def\ilimit{3} % Outer iteration limit
\def\jlimit{5} % Inner iteration limit, rescaling doesn't happen if this is 1
\begin{document}
\begin{frame}[fragile]{Nested animated loops}
\begin{center}%
\begin{animateinline}[loop, poster = first, controls]{2}
\whiledo{\thei<\ilimit} {% % Starting outer loop
\setcounter{j}{0}% % Resetting inner counter
\whiledo{\thej<\jlimit} {% % Starting inner loop
\begin{tikzpicture}%
\draw [color=black] (-0.5,-1.5) rectangle (4.5, 0.5); % Draw a bounding rectangle
\node[shift={(\thei,0)}] at (0,0) {\Large $\downarrow$};% Draw the first level
\node[shift={(\thej,0)}] at (0,-1) {\Large $\uparrow$}; % Draw the second level
\end{tikzpicture}%
\stepcounter{j}% % Increase the inner counter
\ifthenelse{\thej<\jlimit} {%
\newframe% % Draw a new inner frame
}{}%
}%
\stepcounter{i}% % Increase the outer counter
\ifthenelse{\thei<\ilimit} {%
\newframe% % Draw a new outer frame
}{%
\end{animateinline}\relax% % BREAK % End the animation
}%
}%
\end{center}
\end{frame}
\end{document}
(the control keys are not visible in the image above due to the conversion into .gif, they work fine in the original pdf)
Related
I have a simple pcolor plot in Matlab (Version R 2016b) which I have uploaded as shown in the image below. I need to get only the blue sloped line which extends from the middle of the leftmost corner to the rightmost corner without hard-coding the matrix values.
For instance: One can see that the desired slope line has values somewhere approximately between 20 to 45 from the pcolor plot. (From a rough guess just by looking at the graph)
I'm applying the following code on the matrix named Slant which contains the plotted values.
load('Slant.mat');
Slant(Slant<20|Slant>50)=0;
pcolor(Slant); colormap(jet); shading interp; colorbar;
As one can see I hard-coded the values which I don't want to. Is there any method of detecting certain matrix values while making the rest equal to zero?
I used an other small algorithm of taking half the maximum value from the matrix and setting it to zero. But this doesn't work for other images.
[maxvalue, row] = max(Slant);
max_m=max(maxvalue);
Slant(Slant>max_m/2)=0;
pcolor(Slant); colormap(jet); shading interp; colorbar;
Here is another suggestion:
Remove all the background.
Assuming this "line" results in a Bimodal distribution of the data (after removing the zeros), find the lower mode.
Assuming the values of the line are always lower than the background, apply a logic mask that set to zeros all values above the minimum + 2nd_mode, as demonstrated in the figure below (in red circle):
Here is how it works:
A = Slant(any(Slant,2),:); % save in A only the nonzero data
Now we have A that looks like this:
[y,x] = findpeaks(histcounts(A)); % find all the mode in the histogram of A
sorted_x = sortrows([x.' y.'],-2); % sort them by their hight in decendet order
mA = A<min(A(:))+sorted_x(2,1); % mask all values above the second mode
result = A.*mA; % apply the mask on A
And we get the result:
The resulted line has some holes within it, so you might want to interpolate the whole line from the result. This can be done with simple math on the indices:
[y1,x1] = find(mA,1); % find the first nonzero row
[y2,x2] = find(mA,1,'last'); % find the last nonzero row
m = (y1-y2)/(x1-x2); % the line slope
n = y1-m*x1; % the intercept
f_line = #(x) m.*x+n; % the line function
So we get a line function f_line like this (in red below):
Now we want to make this line thicker, like the line in the data, so we take the mode of the thickness (by counting the values in each column, you might want to take max instead), and 'expand' the line by half of this factor to both sides:
thick = mode(sum(mA)); % mode thickness of the line
tmp = (1:thick)-ceil(thick/2); % helper vector for expanding
rows = bsxfun(#plus,tmp.',floor(f_line(1:size(A,2)))); % all the rows for each coloumn
rows(rows<1) = 1; % make sure to not get out of range
rows(rows>size(A,1)) = size(A,1); % make sure to not get out of range
inds = sub2ind(size(A),rows,repmat(1:size(A,2),thick,1)); % convert to linear indecies
mA(inds) = 1; % add the interpolation to the mask
result = A.*mA; % apply the mask on A
And now result looks like this:
Idea: Use the Hough transform:
First of all it is best to create a new matrix with only the rows and columns we are interested in.
In order to apply matlab's built in hough we have to create a binary image: As the line always has lower values than the rest, we could e.g. determine the lowest quartile of the brightnesses present in the picture (using quantile, and set these to white, everything else to black.
Then to find the line, we can use hough directly on that BW image.
I am trying to discard (i.e. zero out) all of the pixels above a certain region in an image (for example, a clearly defined white bar). Is there any way I can use the result of a Sobel edge detection to accomplish this, or is there a better way?
You could try something like this:
I = imread('image.png'); % read image
E = edge(I) % get results of canny edge detector
[~,idx] = max( sum(E,2:) ); % find the row with the clearest horizontal edge
I(1:idx-1,:) = 0; % zero everything above (not including) that row
You could probably replace the canny edge image with a Sobel image and get the same results.
I want to load an image and then create a Matrix with the size of the image.
The Matrix should be transparent with only some spare values (points).
I then want to show the image in a figure and put the Matrix on top.
The code so far:
world = imread('map1.jpg'); % import image of location
[x_world,y_world] = size(world); % get the size of the image
A = zeros(x_world,y_world); % create matrix with dimension of image
imshow(world); % display image
axis image; % label the axis
My Matrix contains some points:
A(200,300) = 1;
A(500,500) = 5;
A(580,200) = 3;
if I now iterate through each value in the Matrix like that:
for i = 1:x_world
for j = 1:y_world
if(A(i,j) == 1)
plot(i,j,'r.','MarkerSize',20); % plot a single point
elseif(A(i,j) == 2)
plot(i,j,'y.','MarkerSize',20); % plot a single point
elseif(A(i,j) == 3)
plot(i,j,'m.','MarkerSize',20); % plot a single point
elseif(A(i,j) == 4)
plot(i,j,'g.','MarkerSize',20); % plot a single point
elseif(A(i,j) == 5)
plot(i,j,'b.','MarkerSize',20); % plot a single point
elseif(A(i,j) == 6)
plot(i,j,'w.','MarkerSize',20); % plot a single point
end
end
end
it would be really slow.
So what I want to do is create a transparent Matrix and then set some points, so that I just can print the Matrix over the original image.
Is that possible? How do I do that? Is there maybe another better way to do that?
As a start, you could avoid looping over all of theese rows and columns by actually looping over your 6 groups. The code blow should give the same result:
markers = {'r.', 'y.', 'm.', 'g.', 'b.', 'w.'}; % // define some markers
figure
hold on
for group = 1:6
[i, j] = ind2sub(size(A), find(A==group)); % // find indices of current group
plot(i, j, markers{group}, 'markersize', 20) % // plot them with their marker
end
If speed is an issue, you maybe can have a look at gscatter() and or sparse().
i make some compare between 2 very similar images , (by code RANSAC) and after it i rotate one of the images to the angle of the first image .
the problem is that in some images you have a black border, that Distorted the compere and the rotate
how i make that the compere will be only on the image without black border (ignore it)?
function [ output_args ] = ransac( )
%frames( filename)
global numFrames
a=sprintf('Ransac begin');
disp(a);
for i=1:numFrames
file_name = sprintf('frames/%0.3i.jpg', i);
file_name2 = sprintf('frames/%0.3i.jpg', i+1);
%file_name = sprintf('frames/008.jpg', i);
%file_name2 = sprintf('frames/049.jpg', i+1);
I1=im2double(imread(file_name2));
I2=im2double(imread(file_name));
% Get the Key Points
Options.upright=true;
Options.tresh=0.0001;
Ipts1=OpenSurf(I1,Options);
Ipts2=OpenSurf(I2,Options);
% Put the landmark descriptors in a matrix
D1 = reshape([Ipts1.descriptor],64,[]);
D2 = reshape([Ipts2.descriptor],64,[]);
% Find the best matches
err=zeros(1,length(Ipts1));
cor1=1:length(Ipts1);
cor2=zeros(1,length(Ipts1));
for i=1:length(Ipts1),
distance=sum((D2-repmat(D1(:,i),[1 length(Ipts2)])).^2,1);
[err(i),cor2(i)]=min(distance);
end
% Sort matches on vector distance
[err, ind]=sort(err);
cor1=cor1(ind);
cor2=cor2(ind);
% Make vectors with the coordinates of the best matches
Pos1=[[Ipts1(cor1).y]',[Ipts1(cor1).x]'];
Pos2=[[Ipts2(cor2).y]',[Ipts2(cor2).x]'];
Pos1=Pos1(1:30,:);
Pos2=Pos2(1:30,:);
% Show both images
I = zeros([size(I1,1) size(I1,2)*2 size(I1,3)]);
I(:,1:size(I1,2),:)=I1; I(:,size(I1,2)+1:size(I1,2)+size(I2,2),:)=I2;
% Calculate affine matrix
Pos1(:,3)=1; Pos2(:,3)=1;
M=Pos1'/Pos2';
% Add subfunctions to Matlab Search path
functionname='OpenSurf.m';
functiondir=which(functionname);
functiondir=functiondir(1:end-length(functionname));
addpath([functiondir '/WarpFunctions'])
% Warp the image
I1_warped=affine_warp(I1,M,'bicubic');
% Show the result
%figure,
subplot(1,3,1), imshow(I1);title('Figure 1');
subplot(1,3,2), imshow(I2);title('Figure 2');
subplot(1,3,3), imshow(I1_warped);title('Warped Figure 1');
imwrite(I1_warped,file_name2);
if (mod(i,20)==0 )
disp(sprintf('he make a %d',i));
end
end
sprintf('finish');
aaa();
end
Count black columns - this question. Just remove column if
there is not any non-zero pixels.
Do the same trick with rows.
Do what your need with the rest.
This will fail if black borders are not really black - for example, very dark gray. In this case apply threshold on detecting black.
Also it will be bad solution if there are any black columns in the main part of this picture. In this case you should check position of the black column and remove only columns relatively close to borders.
Here is simple version of deleting symmetric black box without black rows inside the epic
I1=im2double(imread('dart.jpg'));
sizeI = size(I1);
zeros = floor((sizeI(2) - min(sum(any(I1))))/2);
I2 = I1(:, zeros : sizeI(2)-zeros, :);
nonZero = sum(any(I1,2));
sizeI2 = size(I2);
zerosRows = floor((sizeI(1) - min(sum(any(I2, 2))))/2);
I3 = I2(zerosRows : sizeI2(1)-zerosRows, :, :);
subplot(1,3,1), imshow(I1);title('Figure 1');
subplot(1,3,2), imshow(I2);title('Figure 2');
subplot(1,3,3), imshow(I3);title('Figure 3');
Applied to "good" input:
Applied to image with inner black lines - not so good result.
In case you need precise detecting here is a plan:
Check columns from the most left to the first with color and
remove all black.
Check columns from the most right backwards to the last with color and remove black
Do the same with rows.
I will not provide code for this one because it's just some matrix operations OP can do by himself.
I've been using a function file [ret]=drawellipse(x,y,a,b,angle,steps,color,img). Calling the function through a script file to draw random ellipses in image. But once i set the random center point(x,y), and random a, b, there is high possibility that the ellipses intersection would occur. How can i prevent the intersection? (I'm supposed to draw the ellipses that are all separate from each other)
Well, over here i have a function file which is to check whether the ellipses got overlap or not,overlap = overlap_ellipses(x0,y0,a0,b0,angle0,x1,y1,a1,b1,angle1). If the two ellipses are overlap, then the 'overlap=1', otherwise 'overlap=0'.
Based on all these, i tested in the command window:
x=rand(4,1)*400; % x and y are the random coodinates for the center of ellipses
y=rand(4,1)*400;
a=[50 69 30 60]; % major axis for a and b, i intend to use random also in the future
b=[20 40 10 40]; % minor axis
angle=[30 90 45 0]; % angle of ellipse
steps=10000;
color=[255 0 0]; % inputs for another function file to draw the ellipse
img=zeros(500,500,3);
The following i want to dispaly the ellipses if overlap==0, and 'if overlap==1', decrease the a and b, till there is no intersection. Lastly, to imshow the img.
for i=1:length(x)
img=drawellipse(x(i),y(i),a(i),b(i),angle(i),steps,color,img);
end
For me now, i have difficulty in coding the middle part. How can i use the if statement to get the value of overlap and how to make the index corresponding to the ellipse i need to draw.
i tested a bit like
for k=1:(length(x)-1)
overlap = overlap_ellipses(x(1),y(1),a(1),b(1),angle(1),x(1+k),y(1+k),a(1+k),b(1+k),angle(1+k))
end
it returns
overlap=0
overlap=0
overlap=1
it is not [0 0 1]. I can't figure it out, thus stuck in the process.
The final image shoule look like the picture in this voronoi diagram of ellipses.
(There is no intersection between any two ellipses)
Assuming you are drawing the ellipses into a raster graphics image, you could calculate the pixels you would have to draw for an ellipse, check whether these pixels in the image are still of the background color, and draw the ellipse only if the answer is yes, otherwise reject it (because something else, i.e. another ellipse, is in the way) and try other x,y,a and b.
Alternatively, you could split your image into rectangles (not neccessarily of equal size) and place one ellipse in each of those, picking x,y,a,b such that no ellipse exceeds its rectangle - then the ellipses cannot overlap either, but it depends on how much "randomness" your ellipse placing should have whether this suffices.
The mathematically rigorous way would be to store x,y,a,b of each drawn ellipse and for each new ellipse, do pairwise checks with each of those whether they have common points by solving a system of two quadratic equations. However, this might be a bit complicated, especially once the angle is not 0.
Edit in response to the added code: Instead of fixing all x's and y's before the loop, you can determine them inside the loop. Since you know how many ellipses you want, but not how many you have to sample, you need a while loop. The test loop you give may come in handy, but you need to compare all previous ellipses to the one created in the loop iteration, not the first one.
i=1;
while (i<=4) %# or length(a), or, more elegantly, some pre-defined max
x(i) = rand*400; y(i) = rand*400; %# or take x and y as givren and decrease a and b
%# now, check overlap for given center
overlap = false;
for k=1:(i-1)
overlap = overlap || overlap_ellipses(x(i),y(i),a(i),b(i),angle(i),x(k),y(k),a(k),b(k),angle(k))
end
if (~overlap)
img = drawellipse(x(i),y(i),a(i),b(i),angle(i),steps,color,img);
i = i+1; %# determine next ellipse
end %# else x(i) and y(i) will be overwritten in next while loop iteration
end
Of course, if a and b are fixed, it may happen that no ellipse fits the image dimensions if the already present ones are unfortunately placed, resulting in an infinite loop.
Regarding your plan of leaving the center fixed and decreasing the ellipse's size until it fits: where does your overlap_ellipses method come from? Maybe itcan be adapted to return a factor by which one ellipse needs to be shrinked to fit next to the other (and 1 if it fits already)?
The solution proposed by #arne.b (the first one) is a good way to rasterize non-overlapping ellipses.
Let me illustrate that idea with an example. I will be extending my previous answer:
%# color image
I = imread('pears.png');
sz = size(I);
%# parameters of ellipses
num = 7;
h = zeros(1,num);
clr = lines(num); %# color of each ellipse
x = rand(num,1) .* sz(2); %# center x-coords
y = rand(num,1) .* sz(1); %# center y-coords
a = rand(num,1) .* 200; %# major axis length
b = rand(num,1) .* 200; %# minor axis length
angle = rand(num,1) .* 360; %# angle of rotation
%# label image, used to hold rasterized ellipses
BW = zeros(sz(1),sz(2));
%# randomly place ellipses one-at-a-time, skip if overlaps previous ones
figure, imshow(I)
axis on, hold on
for i=1:num
%# ellipse we would like to draw directly on image matrix
[ex,ey] = calculateEllipse(x(i),y(i), a(i),b(i), angle(i), 100);
%# lets plot the ellipse (overlayed)
h(i) = plot(ex,ey, 'LineWidth',2, 'Color',clr(i,:));
%# create mask for image pixels inside the ellipse polygon
mask = poly2mask(ex,ey,sz(1),sz(2));
%# get the perimter of this mask
mask = bwperim(mask,8);
%# skip if there is an existing overlapping ellipse
if any( BW(mask)~=0 ), continue, end
%# use the mask to place the ellipse in the label image
BW(mask) = i;
end
hold off
legend(h, cellstr(num2str((1:num)','Line%d')), 'Location','BestOutside') %'
%# set pixels corresponding to ellipses using specified colors
clr = im2uint8(clr);
II = I;
for i=1:num
BW_ind = bsxfun(#plus, find(BW==i), prod(sz(1:2)).*(0:2));
II(BW_ind) = repmat(clr(i,:), [size(BW_ind,1) 1]);
end
figure, imshow(II, 'InitialMagnification',100, 'Border','tight')
Note how the overlap test is performed in the order the ellipses are added, thus after Line1 (blue) and Line2 (green) are drawn, Line3 (red) will be skipped because it overlaps one of the previous ones, and so on for the rest...
One option is to keep track of all the ellipses already drawn, and to make sure the next set of [x,y,a,b] does not produce a new ellipse which intersects with the existing ones. You can either invoke random numbers until you come up with a set that fulfills the condition, or once you have a set which violates the condition, decrease the values of a and/or b until no intersection occurs.