How can I combine two arrays of vector components into an array of vectors in matlab - arrays

I have two arrays of the same size, ux and uy, which I want to combine into a cell array of vectors such that U(1,1) contains a vector composed of uy(1,1),ux(1,1) and `numel(U)=numel(ux)=numel(uy)'
The components ux and uy represent the unit vector of the image gradient. The component arrays are created by elementwise multiplication:
ux = I1x./I1mag;
uy = I1y./I1mag;
I need to be able to access each vector multiple times, and call them as arguments of dot and cross and making an array of vectors would be faster and more convenient than creating an ad hoc vector for each one on every iteration where it is called.
Thanks
Edit for further clarity:
suppose I have an array
uy = (1,2,3;4,5,6);
and another array of the same size
ux = (9,8,7;6,5,4);
I need the yx vectors, so for our example that's
([1,9], [2,8], [3,7]; [4,6], [5,5], [6,4])
What's the most efficient way to do that, please? I'm going to get dot products of each pixel with its neighbours and vice versa, so each vector will be used 16 times and the full arrays contain on the order of 10^4 or 10^5 elements...
Thanks for your continued help.

You can create two layers. One layer contains ux and other layer contains uy.
ux = [10 8 7;6 5 4];
uy = [1 2 3;4 5 6];
xy(:,:,1) = ux; // [10 8 7;6 5 4]
xy(:,:,2) = uy; // [1 2 3;4 5 6]
aaa=xy(1,1,:); // [10 1]
bbb=xy(1,2,:); // [8 2]
dot(aaa,bbb)
Result will be:
82

If you really want it to be a cell vector, where each element is a [1 x 2] vector, use mat2cell:
ux = rand(15,1);
uy = rand(15,1);
U = [ux, uy];
K = mat2cell(U,ones(size(U,1),1),2);
But as others have pointed out, U = [ux, uy] is sufficient, as you can just call U(1,:) to get the exact same result without having to worry about cells.
If you are wanting to alculate the dot product on the two vectors, arrayfun(#dot,ux,uy) does that job element-wise.

Related

Multiplying arrays of matrices in MATLAB

I have a data set that consists of two 1800 x 900 x 3 x 3 arrays, which should each be interpreted as a 1800x900 array of 3x3 matrices. As part of the analysis, at one point I need to create another such array by, at each point of the 1800x900 array, multiplying the corresponding 3x3 matrices together.
There seem to be two ways to do this that I can think of. The obvious way is
C = zeros(size(A))
for i = 1:900
for j = 1:1800
C(i,j,:,:) = A(i,j,:,:)*B(i,j,:,:)
end
end
But that's quite a long loop and doesn't really take advantage of MATLAB's vectorization. The other way is
C = zeros(size(A))
for i = 1:3
for j = 1:3
for k = 1:3
C(:,:,i,j) = C(:,:,i,j) + A(:,:,i,k).*B(:,:,k,j)
end
end
end
where the large dimensions are getting vectorized and I'm basically using the for loops to implement the Einstein summation convention. This seems really inelegant, though, which makes me think there should be a better way. Is there?
Perfect job for bsxfun with permute:
C = permute(sum(bsxfun(#times, A, permute(B, [1 2 5 3 4])), 4), [1 2 3 5 4]);
In R2016b onwards you can avoid bsxfun thanks to implicit singleton expansion:
C = permute(sum(A .* permute(B, [1 2 5 3 4]), 4), [1 2 3 5 4]);

add vector to multi dimensional array matlab

Thanks in advance for the help.
Suppose I have a multi D array x such that
x(:,:,1) = [1 2; 3 4];
x(:,:,2) = [5 6; 7 8];
and a matrix y such that
y = [1 2; 5 6];
I would like to add the first row of y to each row of x(:,:,1) and the second row of y to each element of x(:,:,2). This will produce an array z such that
z(:,:,1) = [2 4; 4 6];
z(:,:,2) = [10 12; 12 14];
In reality (not the example I am giving) I would like to do this operation on a very large multi D array x and a very large matrix y. I therefore want to do this as efficiently as possible.
The naive approach would be to use for loops to do this, but this would not be efficient what-so-ever. I believe that an efficient approach would be to incorporate bsxfun to accomplish this, but I haven't been able to figure out an approach. y and x can and be restructured to accomplish this task as long as the same z is produced and, most importantly, the amount of time needed to build z is less than the for loop approach.
I was able to find this which does what I want, but only for multiplication and not summation. I could modify this code to do what I want but I feel as though with summation that there has to be a simpler approach.
You just need bsxfun and a little bit of permute:
z = bsxfun(#plus, x, permute(y, [3 2 1]));
The key is to properly rearrange the dimensions of y so that the singleton expansion performed by bsxfun gives you the desired result.

Trying to compare elements of on array with every element of another array in matlab

I'm using Matlab, and I'm trying to come up with a vectorized solution for comparing the elements of one array to every element of another array. Specifically I want to find the difference and see if this difference is below a certain threshold.
Ex: a = [1 5 10 15] and b=[12 13 14 15], threshold = 6
so the elements in a that would satisfy the threshold would be 10 and 15 since each value comes within 6 of any of the values in b while 1 and 5 do not. Currently I have a for loop going through the elements of a and subtracting an equivalently sized matrix from b (for 5 it would be a = [5 5 5 5]). This obviously takes a long time so I'm trying to find a vectorized solution. Additionally, the current format I have my data in is actually cells where each cell element has size [1 2], and I have been using the cellfun function to perform my subtraction. I'm not sure if this complicates the solution of each [1 2] block with the [1 2] block of the second cell. A vectorized solution response is fine, there is no need to do the threshold analysis. I just added it in for a little more background.
Thanks in advance,
Manwei Chan
Use bsxfun:
>> ind = any(abs(bsxfun(#minus,a(:).',b(:)))<threshold)
ind =
0 0 1 1
>> a(ind)
ans =
10 15

Sort cell array base on the 2D value

I have a 3X3 cell array and each element store a (x,y) point.
The point are generate by random number from [0,1].
What I want to do is sort the cell array so that it looks like following
ex: 9 points
each circle is one 2D point
index:(1,1) in the left top corner and (3,3) to the right bottom corner as the usual array index
that is to ensure the topological order.
How do I do it?
Thank in advance.
for the example
pairs = [4 9 2 6 5 1 7 8 3; 9 6 2 1 3 8 7 4 5] (row 1 = x-values, row 2 = y-values))
what I want to do is put them in the cell array so that they can be connected by read lines like the image's topology.
The number of permutations is factorial(9), which is not terribly large. So a brute-froce approach is feasible: test all permutations for your desired conditions, and pick the first that is valid.
In the following I'm using a 2x3x3 array, instead of a 3x3 cell array containing length-2 vectors, because it's much easier that way.
N = 3;
data = rand(2,N,N);
permutations = perms(1:N^2); %// generate all permutations
for k = 1:numel(permutations)
dx = reshape(data(1,permutations(k,:)),N,N); %// permuted x data
dy = reshape(data(2,permutations(k,:)),N,N); %// permuted y data
if all(all(diff(dy,[],1)<0)) && all(all(diff(dx,[],2)>0)) %// solution found
disp(dx) %// display solution: x values
disp(dy) %// y values
break %// we only want one solution
end
end
Note that for some choices of data there may not be a solution.

Easiest way to create arrays based on repeating character positions

I want to group my elements using the repeated segments in the array. The breaking is basically depend on where the repeated segments are, in my real data contains ~10000 elements and I want to know if there is a easier way to do that.
Here is a short example to clarify what I want:
Let's say I have an array,
A=[1 5 3 4 4 4 6 9 8 8 9 5 2];
What I want is to break A into [1 5 3],[6 9], and [9 5 2];
What is the easiest to code this using matlab??
Thanks.
For a vectorized solution, you can find out the places where either forward or backward differences to the neighbor are zero, and then use bwlabel (from the Image Processing Toolbox) and accumarray to gather the data.
A=[1 5 3 4 4 4 6 9 8 8 9 5 2];
d = diff(A)==0;
%# combine forward and backward difference
%# and invert to identify non-repeating elments
goodIdx = ~([d,false]|[false,d]);
%# create list of group labels using bwlabel
groupIdx = bwlabel(goodIdx);
%# distribute the data into cell arrays
%# note that the first to inputs should be n-by-1
B = accumarray(groupIdx(goodIdx)',A(goodIdx)',[],#(x){x})
EDIT
Replace the last two lines of code with the following if you want the repeating elements to appear in the cell array as well
groupIdx = cumsum([1,abs(diff(goodIdx))]);
B = accumarray(groupIdx',A',[],#(x){x})
EDIT2
If you want to be able to split consecutive groups of identical numbers as well, you need to calculate groupIdx as follows:
groupIdx = cumsum([1,abs(diff(goodIdx))|~d.*~goodIdx(2:end)])
Here is a solution that works if I understand the question correctly. It can probably be optimised further.
A=[1 5 3 4 4 4 6 9 8 8 9 5 2];
% //First get logical array of non consecutive numbers
x = [1 (diff(A)~=0)];
for nn=1:numel(A)
if ~x(nn)
if x(nn-1)
x(nn-1)=0;
end
end
end
% //Make a cell array using the logical array
y = 1+[0 cumsum(diff(find(x))~=1)];
x(x~=0) = y;
for kk = unique(y)
B{kk} = A(x==kk);
end
B{:}

Resources