MATLAB: getting rid of a for loop - matlab

I'm looping over a vector and calling a function for every element in it
I want to get rid of the loop, I can't see how.
a short description about the code:
I have imageA and ImageB, I want to map ImageB into ImageA where the user chooses 4 points in ImageA that locates the position of the pattern (ImageB)
this is the part of code that has the for loop
newIm=im1; % newIm will have the mapped image
[r,c]=size(im1); %size of imageA
[p1,p2]=meshgrid(1:c, 1:r); % using indexes matrixes
% p1 has the X indexes
% p2 has the Y indexes
z = ones(r,c); % a vector of ones (for mapping algorithm)
% now calculate for every point in imageA the indexes for its new value
% from imageB ( Inverse Mapping)
% X a b e X'
% Y = pinv c d f * Y'
% 1 g h 1 1
newmatrix=pinv(mat)*[p1(:) p2(:) z(:)]';
newX=newmatrix(1,:)./newmatrix(3,:); % devide the x with z
newY=newmatrix(2,:)./newmatrix(3,:); % devide the y with z
newX=round(newX);
newY=round(newY);
% %% the indexes we want are the ones in the range of ImageB
Xindex=(newX<Br & newX>1); % this gives us a vector of zeros and ones
Yindex=(newY<Bc & newY>1);
ourPixels=Xindex(:).*Yindex(:); % gives us a vectors that has ones
% in the places where the Y and X are both in the range
ourIndexes=find(ourPixels==1); % a vector that holds the indexes that we want
IndexesSize=size(ourIndexes);
XXX=newX(ourIndexes); %the indexes we want
YYY=newY(ourIndexes);
% loop the quadrilateral and "paint" it (only looping the quadrilateral
% and not the whole image)
for i=1 : IndexesSize(1)
newIm(ourIndexes(i))=BilinearInterpolation(im2,YYY(i), XXX(i));
end
fprintf('press any key to see the result...');
pause;
imshow(newIm);
title('The new mapped Image');
this is the function
function NewVal=BilinearInterpolation(imgB,x,y)
% inpust: ImageB- the pattern image
% x and y the coordinates that locates the inverse mapping
% returns the new color of a spicifc pixel (x',y') in imageA
% SW SE NE NW are neighboors of (x,y) which will give us the new color
SW=imgB(floor(x),floor(y)+1);
SE=imgB(floor(x)+1,floor(y)+1);
NE=imgB(floor(x)+1,floor(y));
NW=imgB(floor(x),floor(y));
% the equations are the same as in the lecture
% S = SE * delta(x) + SW*(1- delta(x))
% N = NE * delta(x) + NW*(1- delta(x))
% V = N * delta(y) + S*(1 - delta(y))
deltax=x-floor(x);
S=SE*deltax+SW*(1-deltax);
N=NE*deltax+NW*(1-deltax);
deltay=1-(y-floor(y));
NewVal=N*deltay+S*(1-deltay);
end
I tried this:
newIm(ourIndexes)=BilinearInterpolation(im2,YYY, XXX);
but of course it didn't work
I tried changing the function to work with (.*) but also had a lot of problems

With a little modification you can make your function accept an array of points.
Firstly as mentioned in the comments change your * to elementwise multiplication .*.
Also you'll need to change the times where you access imgB so that it will accept a list of points. Inputting two vectors (i.e. using the code unchanged) will call all combinations of those points i.e nxn points. Normally I would just use a for loop to avoid this as I am lazy and rarely need to optimise my code that much.
As you specifically don't want to use a loop, the easiest way I know to do this is to replace the calls to the subscripts with the appropriate linear indices using sub2ind. For example, SW=imgB(sub2ind(size(imgB),floor(x),floor(y)+1));
Other than that check that all your vectors have the same long dimension, I think they should but it depends on your input.

Related

Alter magnitude of vector

I'm trying to extend or subtract a magnitude from vectors in an array. The code to call the function is:
v_set = {[1;0],[0;2],[1;1]};
v_extensions = [1,-.5,1];
v_set_extended = vector_set_extend(v_set, v_extensions);
And the function itself is below. What I have adds the magnitude to both x and y, but I want it to add the magnitude in the direction of that the vector is pointing, if that makes sense.
function v_set_extended = vector_set_extend(v_set,v_extensions)
% Takes a set of vectors and a set of lengths by which to extend them.
% Returns a set of extended vectors
%
% Inputs:
%
% v_set: a cell array, each element of which is a vector
%
% v_extensions: a vector of the same dimensions as v_set, containing
% lengths which should be added to the vectors
%
% Outputs:
%
% v_set_extended: cell array of the same size as v_set, each element of
% which is the vector with its new length
%%%%%%%%
% Use the 'cell' and 'size' commands to create the output
% v_set_extended as an empty cell of the same size as v_set
v_set_extended = cell(size(v_set))
%%%%%%%%
% Loop over the vectors and extensions, adding the extension to the
% length of the vector, and then storing the result in the
% corresponding entry of v_set_extended
for idx = 1:numel(v_set_extended)
v_set_extended{idx} = v_set{idx}+v_extensions(idx);
end
end
This is mostly a trigonometry problem. You have your vector, let's call it v, with components v_x, v_y. Let's say now that you want to add w to the magnitude of your vector.
The magnitude of v is sqrt(v_x^2 + v_y^2), and its angle is theta = tan(v_y/v_x).
What you want to do is then create a new vector of magnitude m = sqrt(v_x^2 + v_y^2) + w but with the same direction. Once you know the new magnitude, the angle is the same and the new components of the vector are v1_x = m*cos(theta) and v1_y = m*sin(theta).
You shouldn't have any problem implementing this, just pay attention to the difference between sin/sind in Matlab.
The solution is rather simple but it is more complex since you are using cell array. Please avoid cell array and prefer normal array as much as possible. So first we convert v_set into a matrix:
v_mat = cell2mat(v_set)
Then you want to extend the vector so that the magnitude of the new vector is extended by some value. Compute first the magnitude of the vectors:
mag_v_mat = vecnorm(v_mat);
And finally make new vectors all at once:
v_extended = v_mat.*(mag_v_mat+v_extensions)./mag_v_mat;
Dotted operators are here to vectorize the operations along the vectors.
In one-line, it may be written as:
v_extended = cell2mat(v_set).*(1+v_extensions./vecnorm(cell2mat(v_set)));
Please refer to the comments for explanation, and easy way to stick to your current structure is to just compute a unit vector and scale it, rather than directly adding the extension...
for idx = 1:numel(v_set_extended)
% Compute the unit vector (magnitude 1) in the same direction
uvec = v_set{idx} / vecnorm(v_set{idx});
% Create a vector of the extension length in the unit direction
ext = uvec * v_extensions(idx);
% Add the extension
v_set_extended{idx} = v_set{idx} + ext;
end
You can sanity check this by validating the vecnorm (magnitude) values
cellfun( #vecnorm, v_set ) % = [1, 2.0, 1.4142]
cellfun( #vecnorm, v_set_extended ) % = [2, 1.5, 2.4142]
% difference = [1,-0.5, 1]

How to evaluate a vector valued function (or create vector field) on a MATLAB mesh?

I have a 3D grid set up as follows: [X,Y,Z] = ndgrid(0:2^(-8):1). I would like to evaluate and perform operations with vector fields defined at each point in a MATLAB meshgrid/ ndgrid. In other words, I want to assign three-dimensional vectors to every point in a mesh and perform pointwise operations with these vectors.
Implementations such as vec = [X.^2 ; 2*Y] end up concatenating matrices which makes it hard to perform operations such as dot and cross products.
Is there a way I can define a vector-valued function at each point in a mesh which takes as input, the coordinates of that point (the documentation only talked about evaluation scalar functions on meshes)? Or maybe there is a simpler implementation inbuilt in MATLAB?
Honestly, anything that would allow me to avoid subbing at 2^24 points would be appreciated.
Thanks!
Edit
My current implementation using symbolic substitution is as follows:
n=256;
[X,Y,Z] = ndgrid(0:1/n:1); % declaring 3D grid.
syms x y z; % declaring position variables.
xx = [x,y,z];
r1 = norm(xx-c1); % scalar field over grid.
n1 = (xx-c1)/r1; % vector field over grid.
v1 = cross(s1,n1); % vector field over grid.
w1 = n1'*v1; % tensor field over grid.
a = dot(v1,w1); % scalar field over grid.
% subbing in the value of scalar field 'a' (symbolic) into 3D array of doubles, A.
A = zeros(n+1,n+1,n+1);
for c = 1:n+1 % X
for d=1:n+1 % Y
for e= 1:n+1 % Z
A(c,d,e) = subs(a,[x,y,z],[X(c,0,0),Y(0,d,0),Z(0,0,e)]);
end
end
end
% use A in future computations.

select optimal column vector from a matrix subject to a localised goal vector constraint

How to automatically select the column vector of a matrix within which the scalar values in a subset of elements is closest to those in a predefined goal vector of the same sub set?
I solved the problem and tested method on 100,10 matrix, it works - should also work for larger matrices, while hopefully not becoming too computationally expensive
%% Selection of optimal source function
% Now need to select the best source function in the data matrix
% k = 1,2,...n within which scalar values of a random set of elements are
% closest to a pre-defined goal vector with the same random set
% Proposed Method:
% Project the columns of the data matrix onto the goal vector
% Calculate the projection error vector matrix; the null space of the
% local goal vector, is orthogonal to its row space
% The column holding the minimum error vector is the optimal column
% [1] find the null space of the goal vector, containing the projection
% errors
mpg = pinv(gloc);
xstar = mpg*A;
p = gloc*xstar;
nA = A-p;
% [2] the minimum error vector will correspond to the optimal source
% function
normnA = zeros(1,n);
for i = 1:n
normnA(i) = norm(nA(:,i));
end
minnA = min(normnA);
[row,k] = find(normnA == minnA);
disp('The optimal source function is: ')
disp(k)

rewrite the seqneighjoin function in matlab

I have the task to rewrite the seqneighjoin function in matlab by adding the frequency of all the sequences. After searching, I understand that this function returns a phylogenetic tree object obtained by seqences neighbor joinn method from the wiki http://en.wikipedia.org/wiki/Neighbor_joining
Now, I have the following two questions.
(1): what is the data structure of this phytree object obtained by this function? How to express it? For example, for the similar linkage function, it also returns a phylogenetic tree, and the data structure is very clear there, i.e., it is a matrix with three columns, where the i-th column indicates which nodes are combined and the corresponding distance when they are combined. Thanks very much for your time and attention.
(2): Based on wiki, how am I supposed to add frequency to the function seqneighjoin? I am totally confused.
Thanks so much for your time and attention. I truly appreciate that.
EDIT: the following is the code.
function z = seqneighjoin(D_all, freq)
n = size (D_all, 2);
m=(1+sqrt(8*n+1))/2;
z=zeros(m-1,3);
q=zeros(m,m);
str = zeros (m,m);
% initialize the distance matrix d
d=ones(m,m);
d(tril(d,-1)==1)=D_all;
d(triu(d,1)==1)=D_all;
d(eye(m,m)==1) = 1:m; % the diagonal entries of the matrix d is the indices of the clusters
% initialize the matrix str
for r=1:m
for c=1:m
str(r,c)=freq(r)*freq(c)*d(r,c);
str(c,r)=freq(r)*freq(c);
end
end
% loop through for m-1 times to create the matrix z
for k = 1:m-1
% initialize (for the first time) or update (for all other times)
% the matrix q
colSum = sum(d, 1);
rowSum=sum(d,2);
a=size(colSum, 2);
colSumM=colSum(ones(a,1),:);
rowSunM=rowSum(:,ones(1,a));
q=(a-2)*d-colSumM-rowSumM;
% find the minimum element in the matrix q
u=min(q);
v=min(u);
[i,j]=find(q==v);
r=i(1);
c=j(1);
% combine d(r,r) and d(c,c) to get a new node m+k
z(k,:)=[d(r,r), d(c,c), v];
% calculate the distance between the new node m+k and all other node
% which are not m+k
d(r,:) = (d(r,:) + d(c,:) - d(r,c) )/2;
d(r,r) = m+k;
d(c,:)=[]; d(:,c)=[];
end
Here, D_all is the vector representation of a distance matrix returned by the seqpdist function in matlab, and freq is the vector indicating the frequency of all the sequences.

Symbolic gradient differing wildly from analytic gradient

I am trying to simulate a network of mobile robots that uses artificial potential fields for movement planning to a shared destination xd. This is done by generating a series of m-files (one for each robot) from a symbolic expression, as this seems to be the best way in terms of computational time and accuracy. However, I can't figure out what is going wrong with my gradient computation: the analytical gradient that is being computed seems to be faulty, while the numerical gradient is calculated correctly (see the image posted below). I have written a MWE listed below, which also exhibits this problem. I have checked the file generating part of the code, and it does return a correct function file with a correct gradient. But I can't figure out why the analytic and numerical gradient are so different.
(A larger version of the image below can be found here)
% create symbolic variables
xd = sym('xd',[1 2]);
x = sym('x',[2 2]);
% create a potential function and a gradient function for both (x,y) pairs
% in x
for i=1:size(x,1)
phi = norm(x(i,:)-xd)/norm(x(1,:)-x(2,:)); % potential field function
xvector = reshape(x.',1,size(x,1)*size(x,2)); % reshape x to allow for gradient computation
grad = gradient(phi,xvector(2*i-1:2*i)); % compute the gradient
gradx = grad(1);grady=grad(2); % split the gradient in two components
% create function file names
gradfun = strcat('GradTester',int2str(i),'.m');
phifun = strcat('PotTester',int2str(i),'.m');
% generate two output files
matlabFunction(gradx, grady,'file',gradfun,'outputs',{'gradx','grady'},'vars',{xvector, xd});
matlabFunction(phi,'file',phifun,'vars',{xvector, xd});
end
clear all % make sure the workspace is empty: the functions are in the files
pause(0.1) % ensure the function file has been generated before it is called
% these are later overwritten by a specific case, but they can be used for
% debugging
x = 0.5*rand(2);
xd = 0.5*rand(1,2);
% values for the Stackoverflow case
x = [0.0533 0.0023;
0.4809 0.3875];
xd = [0.4087 0.4343];
xp = x; % dummy variable to keep x intact
% compute potential field and gradient for both (x,y) pairs
for i=1:size(x,1)
% create a grid centered on the selected (x,y) pair
xGrid = (x(i,1)-0.1):0.005:(x(i,1)+0.1);
yGrid = (x(i,2)-0.1):0.005:(x(i,2)+0.1);
% preallocate the gradient and potential matrices
gradx = zeros(length(xGrid),length(yGrid));
grady = zeros(length(xGrid),length(yGrid));
phi = zeros(length(xGrid),length(yGrid));
% generate appropriate function handles
fun = str2func(strcat('GradTester',int2str(i)));
fun2 = str2func(strcat('PotTester',int2str(i)));
% compute analytic gradient and potential for each position in the xGrid and
% yGrid vectors
for ii = 1:length(yGrid)
for jj = 1:length(xGrid)
xp(i,:) = [xGrid(ii) yGrid(jj)]; % select the position
Xvec = reshape(xp.',1,size(x,1)*size(x,2)); % turn the input into a vector
[gradx(ii,jj),grady(ii,jj)] = fun(Xvec,xd); % compute gradients
phi(jj,ii) = fun2(Xvec,xd); % compute potential value
end
end
[FX,FY] = gradient(phi); % compute the NUMERICAL gradient for comparison
%scale the numerical gradient
FX = FX/0.005;
FY = FY/0.005;
% plot analytic result
subplot(2,2,2*i-1)
hold all
xlim([xGrid(1) xGrid(end)]);
ylim([yGrid(1) yGrid(end)]);
quiver(xGrid,yGrid,-gradx,-grady)
contour(xGrid,yGrid,phi)
title(strcat('Analytic result for position ',int2str(i)));
xlabel('x');
ylabel('y');
subplot(2,2,2*i)
hold all
xlim([xGrid(1) xGrid(end)]);
ylim([yGrid(1) yGrid(end)]);
quiver(xGrid,yGrid,-FX,-FY)
contour(xGrid,yGrid,phi)
title(strcat('Numerical result for position ',int2str(i)));
xlabel('x');
ylabel('y');
end
The potential field I am trying to generate is defined by an (x,y) position, in my code called xd. x is the position matrix of dimension N x 2, where the first column represents x1, x2, and so on, and the second column represents y1, y2, and so on. Xvec is simply a reshaping of this vector to x1,y1,x2,y2,x3,y3 and so on, as the matlabfunction I am generating only accepts vector inputs.
The gradient for robot i is being calculated by taking the derivative w.r.t. x_i and y_i, these two components together yield a single derivative 'vector' shown in the quiver plots. The derivative should look like this, and I checked that the symbolic expression for [gradx,grady] indeed looks like that before an m-file is generated.
To fix the particular problem given in the question, you were actually calculating phi in such a way that meant you doing gradient(phi) was not giving the correct results compared to the symbolic gradient. I'll try and explain. Here is how you created xGrid and yGrid:
% create a grid centered on the selected (x,y) pair
xGrid = (x(i,1)-0.1):0.005:(x(i,1)+0.1);
yGrid = (x(i,2)-0.1):0.005:(x(i,2)+0.1);
But then in the for loop, ii and jj were used like phi(jj,ii) or gradx(ii,jj), but corresponding to the same physical position. This is why your results were different. Another problem you had was you used gradient incorrectly. Matlab assumes that [FX,FY]=gradient(phi) means that phi is calculated from phi=f(x,y) where x and y are matrices created using meshgrid. You effectively had the elements of phi arranged differently to that, an so gradient(phi) gave the wrong answer. Between reversing the jj and ii, and the incorrect gradient, the errors cancelled out (I suspect you tried doing phi(jj,ii) after trying phi(ii,jj) first and finding it didn't work).
Anyway, to sort it all out, on the line after you create xGrid and yGrid, put this in:
[X,Y]=meshgrid(xGrid,yGrid);
Then change the code after you load fun and fun2 to:
for ii = 1:length(xGrid) %// x loop
for jj = 1:length(yGrid) %// y loop
xp(i,:) = [X(ii,jj);Y(ii,jj)]; %// using X and Y not xGrid and yGrid
Xvec = reshape(xp.',1,size(x,1)*size(x,2));
[gradx(ii,jj),grady(ii,jj)] = fun(Xvec,xd);
phi(ii,jj) = fun2(Xvec,xd);
end
end
[FX,FY] = gradient(phi,0.005); %// use the second argument of gradient to set spacing
subplot(2,2,2*i-1)
hold all
axis([min(X(:)) max(X(:)) min(Y(:)) max(Y(:))]) %// use axis rather than xlim/ylim
quiver(X,Y,gradx,grady)
contour(X,Y,phi)
title(strcat('Analytic result for position ',int2str(i)));
xlabel('x');
ylabel('y');
subplot(2,2,2*i)
hold all
axis([min(X(:)) max(X(:)) min(Y(:)) max(Y(:))])
quiver(X,Y,FX,FY)
contour(X,Y,phi)
title(strcat('Numerical result for position ',int2str(i)));
xlabel('x');
ylabel('y');
I have some other comments about your code. I think your potential function is ill-defined, which is causing all sorts of problems. You say in the question that x is an Nx2 matrix, but you potential function is defined as
norm(x(i,:)-xd)/norm(x(1,:)-x(2,:));
which means if N was three, you'd have the following three potentials:
norm(x(1,:)-xd)/norm(x(1,:)-x(2,:));
norm(x(2,:)-xd)/norm(x(1,:)-x(2,:));
norm(x(3,:)-xd)/norm(x(1,:)-x(2,:));
and I don't think the third one makes sense. I think this could be causing some confusion with the gradients.
Also, I'm not sure if there is a reason to create the .m file functions in your real code, but they are not necessary for the code you posted.