How to sort the rows of a multidimensional matrix in Matlab without changing the order of the elements in the first column? - matlab

I have a 3D matrix A(i, j, k). The problem is the following:
I have a number of rooms. I use the first dimension (the i's) to denote the room IDs. Each room has a number of chairs in it. I use the 2nd dimension (the j's) to denote the chairs' IDs. Each chair has coordinates x,y,z. I use the 3rd dimension (the k's) to denote the coordinates.
For example, A(4,3,1) denotes the 4th room, 3rd chair, x-coordinate; A(4,3,2) denotes the same room and chair but the y-coordinate; and A(4,3,3) the z-coordinate.
I need to sort the chairs in each room independently of the other rooms, according to one of the dimensions.
Let's say I want to sort the chairs of the first room only, that is A(1 , : , :), according to their x-coordinate, that is A(1 , : , 1).
Could anyone help me on how to do that in Matlab 2016b?
Thanks a lot!

I think this does what you want:
A = randi(99,3,3,3); % example data
room = 1; % desired room
coord = 1; % desired coordinate
[~, ind] = sort(A(room,:,coord)); % get indices of the sorting
B = A; % result. Initiallize
B(room,:,:) = B(room,ind,:); % apply sorting to chairs in that room

Related

Faster way of putting Matrix elements into vectors other than a for loop

Hopefully this will come across correctly. I have 4 clouds/groups of points in a grid array (imagine a 2D space with 4 separate clusters of for example 3x3 grid of points) with each point having an X and Y coordinate. I'd like to write a vector of four points in the form of (X1, Y1, X2, Y2, X3, Y3, X4, Y4) where the number represents each cloud/group. Now I would actually like to write a matrix of all the combinations of the above vector covering all the points, so upper left points in all four groups in the first line, same for the second line, but the top middle point for group 4, etc.
One way to do it is to for-loop over all the variable, which would mean 8 nested for loops (4 for each X coordinate of 4 groups, 4 for each Y coordinate of 4 groups).
Is there a faster way maybe? 4 3x3 groups means 6561 combinations. Going to a larger array in each group, 11x11 for example, would mean 214 million combinations.
I'm trying to parallelize some calculations using these point coordinates, but writing the results in a parfor loop presents it's own set of issues if I was to do it on the points themselves. With a matrix of combinations I could just write the results in another matrix with the same number of rows and write the result of the nth row of point coordinates to the nth row of results.
As I understand, you have 4 groups of 3x3=9 coordinate pairs. You need to draw one pair from each group as one result, and produce all possible such results.
Thus, reducing each of the groups of 9 coordinate pairs to a lookup-table that is indexed with a number from 1 to 9, your problem can be reduced to drawing, with replacement, 4 values from the set 1:9.
It is fairly easy to produce all such combinations. permn is one function that does this (from the File Exchange). But you can actually get these even easier using ndgrid:
ind = 1:9;
[a1,a2,a3,a4] = ndgrid(ind,ind,ind,ind);
ind = [a1(:),a2(:),a3(:),a4(:)];
Each row in ind is the indices into one of your 3x3 grids.
For example, if grid 1 is:
x1 = [0.5,0.7,0.8];
y1 = [4.2,5.7,7.1];
then you can generate the coordinate pairs as follows:
[x1,y1] = meshgrid(x1,y1); % meshgrid is nearly the same as ndgrid...
xy1 = [x1(:),y1(:)];
Now your combination k is:
k = 563;
[xy1(ind(k,1),:), xy2(ind(k,2),:), xy3(ind(k,3),:), xy4(ind(k,4),:)]
You probably want to implement the above using multidimensional arrays rather than x1, x2, x3, etc. Adding indices to variables makes for confusing code that is difficult to extend. For example, for n groups you could write:
n = 4;
ind = 1:9;
ind = repmat({ind},n,1);
[ind{:}] = ndgrid(ind{:});
ind = cellfun(#(m)reshape(m,[],1), ind, 'UniformOutput',false);
ind = [ind{:}]; % ind is now the same as in the block of code above
etc.

pixels' indices related to Features points detection

The code below shows the correspondence features points between two images. how can i get the pixels' indices of this points? for example, i want to get the pixel's indices(row and column) of the first feature point located into first image.
I1=rgb2gray(imread('peau.jpg'));
I2=imresize(imrotate(I1,-20),1.2);
points1=detectSURFFeatures(I1);
points2=detectSURFFeatures(I2);
[f1,vpts1] = extractFeatures(I1, points1);
[f2,vpts2] = extractFeatures(I2, points2);
[indexPairs,cv] = matchFeatures(f1, f2) ;
matchedPoints1 = vpts1(indexPairs(:, 1));
matchedPoints2 = vpts2(indexPairs(:, 2));
figure; ax = axes;
showMatchedFeatures(I1,I2,matchedPoints1,matchedPoints2);
legend(ax,'Matched points 1','Matched points 2');
vpts1 and vpts2 give you the feature points that were detected between the first and second image respectively. indexPairs returns a N x 2 matrix where each row gives you which two features matched between the corresponding images. The first element of each row give you the index of which feature in vpts1 matched with the corresponding feature in vpts2, which is the second element of the row.
If you want the actual pixel locations of each feature, you need to access the Location field of vpts1 and vpts2 respectively, and so:
loc1 = vpts1.Location;
loc2 = vpts2.Location;
Each will give you a N x 2 matrix where the first column denotes the x or horizontal coordinates while the second column denotes the y or vertical coordinates. Now, to get the pixel coordinates of the first feature matched between the two images, simply do:
pt1_loc = loc1(indexPairs(1,1),:);
pt2_loc = loc2(indexPairs(1,2),:);
indexPairs(1,1) and indexPairs(1,2) determines the corresponding indices of the features that matched between first and second images, so you use these indices to index into the location arrays of the two images themselves.

Euclidean distance between two columns of two vector Matlab

I have two vectors A & B of size 250x4. The first column in each vector has the X values and the second column has the Y values. I want to calculate the euclidean distance between each the X & Y of each row in the two vectors and save the result in a new vector C of size 250x1 which holds the result of the euclidean distance. For example, if the first row in A is A1x, A1y, A1n, A1m and the first row in B is B1x, B1y, B1n, B1m so I want to get the eucledian distance which will be [(A1x-B1x)^2 + (A1y-B1y)^2]^0.5 and the result will be saved in C1 and same will be done for the rest of the 250 rows. So if anyone could please advise how to do this in Matlab.
Like this:
%// First extract on x-y data from A and B
Axy = A(:,1:2);
Bxy = B(:,1:2);
%// Find all euclidean distances (row-wise)
C1 = sqrt(sum((Axy-Bxy).^2,2));
plus it handles higher dimension too
use pdist2:
C1=diag(pdist2(A(:,1:2),B(:,1:2)));
Actually, pdist2 will give you a 250x250 matrix, because it calculate all the distances. You need only the main diagonal, so calling diag on the result (as in the code above) will produce the wanted result.

How to connect a 3D points with a distance threshold Matlab

I have a vector of 3D points lets say A as shown below,
A=[
-0.240265581092000 0.0500598627544876 1.20715641293013
-0.344503191645519 0.390376667574812 1.15887540716612
-0.0931248606994074 0.267137193112796 1.24244644549763
-0.183530493218807 0.384249186312578 1.14512014134276
-0.0201358671977785 0.404732019283683 1.21816745283019
-0.242108038906952 0.229873488902244 1.24229940627651
-0.391349107031230 0.262170158259873 1.23856838565023
]
what I want to do is to connect 3D points with lines which only have distance less than a specific threshold T. I want to get a list of pairs of points needed to be connected. Such as,
[
( -0.240265581092000 0.0500598627544876 1.20715641293013), (-0.344503191645519 0.390376667574812 1.15887540716612);
(-0.0931248606994074 0.267137193112796 1.24244644549763),(-0.183530493218807 0.384249186312578 1.14512014134276),.....
]
So as shown, I'll have a vector of pairs of points needed to be connected. So if anyone could please advise how this can be done in Matlab.
The following example demonstrates how to accomplish this.
%# Build an example matrix
A = [1 2 3; 0 0 0; 3 1 3; 2 0 2; 0 1 0];
Threshold = 3;
%# Calculate distance between all points
D = pdist2(A, A);
%# Discard any points with distance greater than threshold
D(D > Threshold) = nan;
If you wish to extract an index of all observation pairs that are linked by a distance less than (or equal to) Threshold, as well as the corresponding distance (your question didn't specify what form you wanted the output to take, so I am essentially guessing here), then instead use the following:
%# Obtain a list of linear indices of observations less than or equal to TH
I1 = find(D <= Threshold);
%#Extract the actual distances, as well as the corresponding observation indices from A
[Obs1Index, Obs2Index] = ind2sub(size(D), I1);
DList = [Obs1Index, Obs2Index, D(I1)];
Note, pdist2 uses Euclidean distance by default, but there are other options - see the documentation here.
UPDATE: Based on the OP's comments, the following code will express the output as a K*6 matrix, where K is the number of distance measures less than the threshold value, and the first three columns of each row is the first data point (3 dimensions) and the second three columns of each row is the connected data point.
DList2 = [A(Obs1Index, :), A(Obs2Index, :)];
SECOND UPDATE: I have not made any assumptions on the distance measure in this answer. That is, I'm deliberately using pdist2 in case your distance measure is not symmetric. However, if you are using a symmetric distance measure, then you could probably speed up the run-time by using pdist instead, although my indexing code would need to be adjusted accordingly.
Plot3 and pdist2 can be used to achieve what you want.
D=pdist2(A,A);
T=0.2;
for i=1:7
for j=i+1:7
if D(i,j)<T & D(i,j)~=0
i
j
plot3(A([i j],1),A([i j],2),A([i j],3));
hold on;
fprintf('line is plotted\n');
pause;
end
end
end

mean squared displacement from multiple trajectories

I have a matrix of multiple particle trajectories that I would like to analyze separately The trajectory number is one of the columns of the matrix, so I am trying to sort based on that number. I am using some of the code from this answer: MSD with matlab (which was very helpful, thank you!) to calculate MSD, but I am having difficulty parsing out the individual trajectories. To explain in more detail what I am trying to do: I have trajectory outputs that are in matrix format, with one column for trajectory number, one column for x-position, one column for y-position, etc. I want to be able to take this information and calculate the mean-squared displacement for each trajectory. In order to do this, I have to create a way to distinguish data points based on trajectory number (which is listed in row 7 of mymatrix). This seems to be where I am having trouble. The important columns in this matrix are 1: x-position, 2: y-position and 7: trajectory number. So far I have
total_rows=size(mymatrix,1);
max_trajectory_number=mymatrix(total_rows,7);
nData=0;
msd=zeros(total_rows, 4)
for i=0:max_trajectory_number
trajectornumber= mymatrix(i,7);
if trajectorynumber.equals(i)
nData=nData+1; %counts the number of instances of this trajectory number, which is the number of data points in the trajectory
for dt = 1:nData
deltaCoords = mymatrix(1+dt:end,1:2) - traj0mat(1:end-dt,1:2); %calculates time-averaged MSD based on y and y positions in colums 1 and 2 respectively
squaredDisplacement = sum(deltaCoords.^2,2); %# dx^2+dy^2+dz^2
msd(dt,1) = trajectorynumber; %trajectory number
msd(dt,2) = mean(squaredDisplacement); %# average
msd(dt,3) = std(squaredDisplacement); %# std
msd(dt,4) = length(squaredDisplacement); %# n
end
end
Unfortunately when I run this on mymatrix, the resulting msd matrix remains all zeros. I think this is likely due to an error in sorting based on the trajectory number. I do not get an error just not the results I was looking for
If anyone has any suggestions on how to fix this, it would be greatly appreciated.
It looks like you want to bundle all rows identified by the same trajectory number. I assume that they show up in chronological order as you continue down a column. Then try something like
tnumbs = unique(mymatrix(:,7)); % identify unique trajectory numbers
for i=1:length(tnumbs) % loop through trajectories
icurr = find(mymatrix(:,7)==tnumbs(i)); % find indices to entries for current trajectory
% perform your averaging
deltaCoords = mymatrix(icurr(1+dt:end),1:2) - traj0mat(icurr(1:end-dt),1:2); %calculates time-averaged MSD based on y and y positions in colums 1 and 2 respectively
squaredDisplacement = sum(deltaCoords.^2,2); %# dx^2+dy^2+dz^2
msd(i,1) = tnumbs(i); %trajectory number
msd(i,2) = mean(squaredDisplacement); %# average
msd(i,3) = std(squaredDisplacement); %# std
msd(i,4) = length(squaredDisplacement); %# n
end