How to display coordinates within a matrix? - matlab

I would like to display the coordinates of a matrix in terms of X and Y. For example
if matrix = [ 0 0 5 0; 0 0 1 0; 0 0 0 1; 0 0 0 0]
Say, i want the coordinate for 5...how can i write a code that says 5 = 1x and 3 y.
I don't want to display the element in the matrix, just the coordinates of that element.

use find
[y x] = find( matrix ~= 0 ); % gives you the x y coordinates of all non-zero elements
Note the order of y and x, since Matlab is indexing using row-column.

Related

matlab - line equation to 2D matrix with values of 1 and 0

As the title says, I want to covert a line(or any equation) to 2D matrix.
For example: If I have a line equation y = x, then I want it to be like:
0 0 0 0 0 1
0 0 0 0 1 0
0 0 0 1 0 0
0 0 1 0 0 0
0 1 0 0 0 0
1 0 0 0 0 0
and the length of rows and columns can be variable.
Is there a function or method to implement that?
use meshgrid to get x-y grids:
% set resolution parameters
xmin = 1;
xmax = 100;
dx = 0.1;
ymin = 1;
ymax = 100;
dy = 0.1;
% set x-y grid
[xg, yg] = meshgrid(xmin:dx:xmax, ymin:dy:ymax);
% define your function
f = #(x) (x - 30).^2;
% apply it on the x grid and get close y values
D = abs(f(xg) - yg);
bw = D <= 1;
figure;
imshow(bw);
% flip y axis
set(gca,'YDir','normal')
you get:
and then you can further dilate/erode/skeletonize the output
Given x and y coordinates, how to fill in a matrix with those coordinates? As it is said, just do it in a for loop, or use the "sub2ind" function.
% x,y coordinates
x=0:.01:30;
y=10*sin(2*pi*.1*x);
% add offset so that (x,y)-coordinates are always positive
x=x+abs(min(x))+1;
y=y+abs(min(y))+1;
figure,plot(x,y,'.');axis tight
x=ceil(x); y=ceil(y);
im=zeros(max(y),max(x));
ind=sub2ind(size(im),y,x);
im(ind)=1;
figure,imagesc(im),axis image, axis xy;colormap gray;axis tight
xlabel('x'); ylabel('y')
Why not doing it on your own? You loop through all x-coordinates of the matrix that you (probably scaled) use as the x for your function and get an y out, that you (probably scaled) can round and then use as a y coordinate for your matrix to set the 1.

Nodes that form a loop in adjacency matrix (Matlab)

I have an adjacency matrix with directed edges. Computing A^3, would help me detect if there are any cycles of length 3 (triangle) in the matrix. But, I want to know which nodes form the triangle. How can I achieve this in Matlab?
Thanks
The problem with matrix multiplication is that it adds up all the rows. When you multiply the first row of matrix P by the first column of matrix Q, it does an element-wise multiplication and then generates the sum of the resulting vector, throwing away all of the data about the intermediate nodes. Well, we want that vector, so let's stop it from adding them up.
Say we have our adjacency matrix A:
A =
0 1 0 0 0
0 0 1 0 0
1 0 0 1 0
0 0 0 0 0
0 0 0 1 0
and we want to find out if there are any paths (not cycles, yet) from node x to node z passing through node y. Row x tells us what nodes have edges from x to y, and column z tells us what nodes have edges from y to z. If we do an element-wise AND of row x and column z, we should get a vector of all of the nodes y that are connected to both x and z.
For example, if we AND row 1 and column 3 for this adjacency matrix:
A =
0 1 0 0 0
x x 1 x x
x x 0 x x
x x 0 x x
x x 0 x x
>> A(1,:) & A(:,3).' %// remember to transpose the column first...
ans =
0 1 0 0 0
We see that they're connected by node 2. Awesome, now we know that for this case we have a path 1->2->3. In general though, there could be multiple paths from 1 to 3, so we're going to use the whole vector.
Now all we have to do is make sure that there's a path from node 3 back to node 1. Well, that's row 3, column 1 in our adjacency matrix. If we AND A(3,1) with our vector, we should the same vector back if there's an edge from 3 to 1 and get zeros back if there isn't (and thus, no cycle).
>> (A(1,:) & A(:,3).') & A(3,1)
ans =
0 1 0 0 0
Generalizing this, the vector for each path from x to z is
C(x,:,z) = (A(x,:) & A(:,z).') & A(z,x);
Unfortunately I have been unable to find a way to vectorize this, so a double for loop will have to suffice for now:
for x = 1:size(A,1)
for z = 1:size(A,2)
C(x,:,z) = (A(x,:) & A(:,z).') & A(z,x);
end
end
The resulting matrix will have C(x,y,z) = 1 if there is a cycle from x to y to z (and back), and 0 otherwise. Note that each cycle will be listed 3 times:
C(x,y,z) == C(y,z,x) == C(z,x,y)

Matlab calculate 3D similarity transformation. fitgeotrans for 3D

How can I calculate in MatLab similarity transformation between 4 points in 3D?
I can calculate transform matrix from
T*X = Xp,
but it will give me affine matrix due to small errors in points coordinates. How can I fit that matrix to similarity one? I need something like fitgeotrans, but in 3D
Thanks
If I am interpreting your question correctly, you seek to find all coefficients in a 3D transformation matrix that will best warp one point to another. All you really have to do is put this problem into a linear system and solve. Recall that warping one point to another in 3D is simply:
A*s = t
s = (x,y,z) is the source point, t = (x',y',z') is the target point and A would be the 3 x 3 transformation matrix that is formatted such that:
A = [a00 a01 a02]
[a10 a11 a12]
[a20 a21 a22]
Writing out the actual system of equations of A*s = t, we get:
a00*x + a01*y + a02*z = x'
a10*x + a11*y + a12*z = y'
a20*x + a21*y + a22*z = z'
The coefficients in A are what we need to solve for. Re-writing this in matrix form, we get:
[x y z 0 0 0 0 0 0] [a00] [x']
[0 0 0 x y z 0 0 0] * [a01] = [y']
[0 0 0 0 0 0 x y z] [a02] [z']
[a10]
[a11]
[a12]
[a20]
[a21]
[a22]
Given that you have four points, you would simply concatenate rows of the matrix on the left side and the vector on the right
[x1 y1 z1 0 0 0 0 0 0] [a00] [x1']
[0 0 0 x1 y1 z1 0 0 0] [a01] [y1']
[0 0 0 0 0 0 x1 y1 z1] [a02] [z1']
[x2 y2 z2 0 0 0 0 0 0] [a10] [x2']
[0 0 0 x2 y2 z2 0 0 0] [a11] [y2']
[0 0 0 0 0 0 x2 y2 z2] [a12] [z2']
[x3 y3 z3 0 0 0 0 0 0] * [a20] = [x3']
[0 0 0 x3 y3 z3 0 0 0] [a21] [y3']
[0 0 0 0 0 0 x3 y3 z3] [a22] [z3']
[x4 y4 z4 0 0 0 0 0 0] [x4']
[0 0 0 x4 y4 z4 0 0 0] [y4']
[0 0 0 0 0 0 x4 y4 z4] [z4']
S * a = T
S would now be a matrix that contains your four source points in the format shown above, a is now a vector of the transformation coefficients in the matrix you want to solve (ordered in row-major format), and T would be a vector of target points in the format shown above.
To solve for the parameters, you simply have to use the mldivide operator or \ in MATLAB, which will compute the least squares estimate for you. Therefore:
a = S^{-1} * T
As such, simply build your matrix like above, then use the \ operator to solve for your transformation parameters in your matrix. When you're done, reshape T into a 3 x 3 matrix. Therefore:
S = ... ; %// Enter in your source points here like above
T = ... ; %// Enter in your target points in a right hand side vector like above
a = S \ T;
similarity_matrix = reshape(a, 3, 3).';
With regards to your error in small perturbations of each of the co-ordinates, the more points you have the better. Using 4 will certainly give you a solution, but it isn't enough to mitigate any errors in my opinion.
Minor Note: This (more or less) is what fitgeotrans does under the hood. It computes the best homography given a bunch of source and target points, and determines this using least squares.
Hope this answered your question!
The answer by #rayryeng is correct, given that you have a set of up to 3 points in a 3-dimensional space. If you need to transform m points in n-dimensional space (m>n), then you first need to add m-n coordinates to these m points such that they exist in m-dimensional space (i.e. the a matrix in #rayryeng becomes a square matrix)... Then the procedure described by #rayryeng will give you the exact transformation of points, you then just need to select only the coordinates of the transformed points in the original n-dimensional space.
As an example, say you want to transform the points:
(2 -2 2) -> (-3 5 -4)
(2 3 0) -> (3 4 4)
(-4 -2 5) -> (-4 -1 -2)
(-3 4 1) -> (4 0 5)
(5 -4 0) -> (-3 -2 -3)
Notice that you have m=5 points which are n=3-dimensional. So you need to add coordinates to these points such that they are n=m=5-dimensional, and then apply the procedure described by #rayryeng.
I have implemented a function that does that (find it below). You just need to organize the points such that each of the source-points is a column in a matrix u, and each of the target points is a column in a matrix v. The matrices u and v are going to be, thus, 3 by 5 each.
WARNING:
the matrix A in the function may require A LOT of memory for moderately many points nP, because it has nP^4 elements.
To overcome this, for square matrices u and v, you can simply use T=v*inv(u) or T=v/u in MATLAB notation.
The code may run very slowly...
In MATLAB:
u = [2 2 -4 -3 5;-2 3 -2 4 -4;2 0 5 1 0]; % setting the set of source points
v = [-3 3 -4 4 -3;5 4 -1 0 -2;-4 4 -2 5 -3]; % setting the set of target points
T = findLinearTransformation(u,v); % calculating the transformation
You can verify that T is correct by:
I = eye(5);
uu = [u;I((3+1):5,1:5)]; % filling-up the matrix of source points so that you have 5-d points
w = T*uu; % calculating target points
w = w(1:3,1:5); % recovering the 3-d points
w - v % w should match v ... notice that the error between w and v is really small
The function that calculates the transformation matrix:
function [T,A] = findLinearTransformation(u,v)
% finds a matrix T (nP X nP) such that T * u(:,i) = v(:,i)
% u(:,i) and v(:,i) are n-dim col vectors; the amount of col vectors in u and v must match (and are equal to nP)
%
if any(size(u) ~= size(v))
error('findLinearTransform:u','u and v must be the same shape and size n-dim vectors');
end
[n,nP] = size(u); % n -> dimensionality; nP -> number of points to be transformed
if nP > n % if the number of points to be transform exceeds the dimensionality of points
I = eye(nP);
u = [u;I((n+1):nP,1:nP)]; % then fill up the points to be transformed with the identity matrix
v = [v;I((n+1):nP,1:nP)]; % as well as the transformed points
[n,nP] = size(u);
end
A = zeros(nP*n,n*n);
for k = 1:nP
for i = ((k-1)*n+1):(k*n)
A(i,mod((((i-1)*n+1):(i*n))-1,n*n) + 1) = u(:,k)';
end
end
v = v(:);
T = reshape(A\v, n, n).';
end

manipulate zeros matrix to put boolean at certain position in rows

So I have a matrix X of size m,10 that is initialized to all zeros.
then I have a vector of size m,1 that contains digits from 1 to 10
what I want to do (hopefully in a single operation with no loops), is for each row of the matrix X and vector y, I want to put a '1' in the column indexed by the value written in the row of vector y.
Here's what I want with a small example: X = [0 0 0; 0 0 0; 0 0 0]; lets say y= [3; 2; 1];
then I would expect the operation to return X = [0 0 1; 0 1 0; 1 0 0]
Do you have a command that can do that easily ?
X(sub2ind(size(X),y',1:numel(y)))=1
or
X((0:numel(y)-1)*size(X,2) + y')=1

Locate touching pixels of two objects

Suppose I have matrix, where each cell of this matrix describes a location (e.g. a bin of a histogram) in a two dimensional space. Lets say, some of these cells contain a '1' and some a '2', indicating where object number 1 and 2 are located, respectively.
I now want to find those cells that describe the "touching points" between the two objects. How do I do that efficiently?
Here is a naive solution:
X = locations of object number 1 (x,y)
Y = locations of object number 2 (x,y)
distances = pdist2(X,Y,'cityblock');
Locations (x,y) and (u,v) touch, iff the respective entry in distances is 1. I believe that should work, however does not seem very clever and efficient.
Does anyone have a better solution? :)
Thank you!
Use morphological operations.
Let M be your matrix with zeros (no object) ones and twos indicating the locations of different objects.
M1 = M == 1; % create a logical mask of the first object
M2 = M == 2; % logical mask of second object
dM1 = imdilate( M1, [0 1 0; 1 1 1; 0 1 0] ); % "expand" the mask to the neighboring pixels
[touchesY touchesX] =...
find( dM1 & M2 ); % locations where the expansion of first object overlap with second one
Code
%%// Label matrix
L = [
0 0 2 0 0;
2 2 2 1 1;
2 2 1 1 0
0 1 1 1 1]
[X_row,X_col] = find(L==1);
[Y_row,Y_col] = find(L==2);
X = [X_row X_col];
Y = [Y_row Y_col];
%%// You code works till this point to get X and Y
%%// Peform subtractions so that later on could be used to detect
%%// where Y has any index that touches X
%%// Subtract all Y from all X. This can be done by getting one
%%//of them and in this case Y into the third dimension and then subtracting
%%// from all X using bsxfun. The output would be used to index into Y.
Y_touch = abs(bsxfun(#minus,X,permute(Y,[3 2 1])));
%%// Perform similar subtractions, but this time subtracting all X from Y
%%// by putting X into the third dimension. The idea this time is to index
%%// into X.
X_touch = abs(bsxfun(#minus,Y,permute(X,[3 2 1]))); %%// for X too
%%// Find all touching indices for X, which would be [1 1] from X_touch.
%%// Thus, their row-sum would be 2, which can then detected and using `all`
%%// command. The output from that can be "squeezed" into a 2D matrix using
%%// `squeeze` command and then the touching indices would be any `ones`
%%// columnwise.
ind_X = any(squeeze(all(X_touch==1,2)),1)
%%// Similarly for Y
ind_Y = any(squeeze(all(Y_touch==1,2)),1)
%%// Get the touching locations for X and Y
touching_loc = [X(ind_X,:) ; Y(ind_Y,:)]
%%// To verify, let us make the touching indices 10
L(sub2ind(size(L),touching_loc(:,1),touching_loc(:,2)))=10
Output
L =
0 0 2 0 0
2 2 2 1 1
2 2 1 1 0
0 1 1 1 1
L =
0 0 10 0 0
2 10 10 10 1
10 10 10 10 0
0 10 10 1 1