Create distance matrix from the result of pdist - matlab

I would like to create a matrix from the result of pdist.
pdist returns a vector of distances: 1-2, 1-3, 1-4.. 2-3.. etc.
i have tried to use this as suggested to get the upper triangle:
a = [1,2,3,4,5,6,7,8,9,10]
b=triu(ones(5),1);
b(b==1)=a;
but this returns
0 1 2 4 7
0 0 3 5 8
0 0 0 6 9
0 0 0 0 10
0 0 0 0 0
Is there a oneliner/function to do this correctly?

As I understand from the title you want to create a square matrix from PDIST function result. It can be easily done with SQUAREFORM function. And it works in both directions.
a = pdist(...);
asq = squareform(a);

Related

Matlab: enter same vector repeatedly to matrix using logical indexing

I would like to enter the same vector of numbers repeatedly to an existing matrix at specific (row) logical indices. This is like an extension of entering just a single number at all logical index positions (at least in my head).
I.e., it is possible to have
mat = zeros(5,3);
rowInd = logical([0 1 0 0 1]); %normally obtained from previous operation
mat(rowInd,1) = 15;
mat =
0 0 0
15 0 0
0 0 0
0 0 0
15 0 0
But I would like to do sth like this
mat(rowInd,:) = [15 6 3]; %rows 2 and 5 should be filled with these numbers
and get an assignment mismatch error.
I want to avoid for loops for the rows or assigning vector elements single file. I have the strong feeling there is an elementary matlab operation that should be able to do this? Thanks!
The problem is that your indexing picks two rows from the matrix and tries to assign a single row to them. You have to replicate the targeted row to fit your indexing:
mat = zeros(5,3);
rowInd = logical([0 1 0 0 1]);
mat(rowInd,:) = repmat([15 6 3],sum(rowInd),1)
This returns:
mat =
0 0 0
15 6 3
0 0 0
0 0 0
15 6 3

How to make an array of matrix (of varying sizes)

I'm trying to get to grips with matlab, so this question is more about syntax than anything else.
I want to create a vector (1xn) of matrices. The matrices are all possibly of different dimensions eg. matrix 1 = 4 x 5, matrix 2 = 5 x 6 etc.
I tried using a for loop, but I had the following error:
Subscripted assignment dimension mismatch.
You can store an array of matrices of different sizes as a cell array of matrices. Often you'll want to create these cell arrays dynamically using the arrayfun function which will do this for you if you set the UniformOutput option to 0.
Example:
cols = [4 5 6];
rows = [1 2 3];
A = arrayfun(#(i) zeros(rows(i),cols(i)),1:3,'UniformOutput',0);
A{:}
Outputs:
ans =
0 0 0 0
ans =
0 0 0 0 0
0 0 0 0 0
ans =
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0

assigning coordinate to a matrix in MATLAB

I'm writing a MATLAB code, I encountered a problem: I have a (2N+1)*(2N+1) matrix for example 7*7. I want to assign coordinate system to it such that the matrix center is the origin of coordinate system. I mean I want to assign (0,0) to row 4 and column 4 of matrix, (1,0) to row 4 and column 5 of matrix and so on. please help me
Thank you in advance
I want to generate a line of ones in all possible directions in a square matrix like this:
0 0 0 0 0 0 0
0 0 0 0 0 0 1
0 0 0 0 0 1 0
0 0 0 1 0 0 0
0 1 0 0 0 0 0
1 0 0 0 0 0 0
0 0 0 0 0 0 0
center of matrix is the origin. this line has 30 degree from horizontal axis.
What you want is a simple mapping from the original matrix counting system to a customized one. Here I have built two cell matrices, representing the coordinates of the elements in the matrix.
Here I have done a simple mapping as follows:
for ii = 1:7
for jj=1:7
D{ii,jj} = C{ii,jj} - [4,4];
end
end
Generally, for matrix of size 2*N+1, you will do the following:
for ii = 1:2*N+1
for jj = 1:2*N+1
D{ii,jj} = C{ii,jj} - [N+1,N+1];
end
end
where C is the original matrix and D is the mapped matrix. After you well-understood what I have done here, you can then replace the for-loops with more efficient functions such as bsxfun.

Index an Array using values from a Matrix, Matlab [duplicate]

This question already has answers here:
2D logical matrix from vector of coordinates (Basic matlab)
(2 answers)
Closed 9 years ago.
I would like to use values from a matrix to index an array. I will use a 3x2 matrix in the example but it could be a matrix of any height in the actual code. The array will be 5x5 in the example but could be a square array of any size. The size of the array and height of the matrix have no relationship.
Here is my code
X =
2 1
4 3
1 4
Grid=zeros(5,5)
Grid =
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
So i would like to access points 2,1 4,3 and 1,4 and add one to the value in that location.
I have tried the following code
Grid(X(:,1),X(:,2))=Grid(X(:,1),X(:,2))+1
Which gives this result
Grid =
1 0 1 1 0
1 0 1 1 0
0 0 0 0 0
1 0 1 1 0
0 0 0 0 0
Which is not what I require.
I have tried other ways with no luck, I think i could use a loop or create a FLAT array but don't really want to, I think there must be a more efficient way.
Anyone have any ideas? I'm using Matlab 2012b.
As always thanks for your time and any help you may be able to give.
Edit-1 Required Result
This is the result I would like
Grid =
0 0 0 1 0
1 0 0 0 0
0 0 0 0 0
0 0 1 0 0
0 0 0 0 0
Edit-2
The coordinate matrix may hold duplicate values, so I would like the value in the relative location in the Array (Grid in the example) to show how many times this coordinate occurs. So my solution is
Grid(sub2ind(size(Grid),X(:,1),X(:,2)))=Grid(sub2ind(size(Grid),X(:,1),X(:,2)))+1
Using the answer to 2D logical matrix from vector of coordinates (Basic matlab) that Oleg pointed me to. I managed to solve my question by converting subscripts to linear indexes:
pos = sub2ind(size(Grid), X(:,1), X(:,2));
Grid(pos) = 1;

How can I find local maxima in an image in MATLAB?

I have an image in MATLAB:
y = rgb2gray(imread('some_image_file.jpg'));
and I want to do some processing on it:
pic = some_processing(y);
and find the local maxima of the output. That is, all the points in y that are greater than all of their neighbors.
I can't seem to find a MATLAB function to do that nicely. The best I can come up with is:
[dim_y,dim_x]=size(pic);
enlarged_pic=[zeros(1,dim_x+2);
zeros(dim_y,1),pic,zeros(dim_y,1);
zeros(1,dim_x+2)];
% now build a 3D array
% each plane will be the enlarged picture
% moved up,down,left or right,
% to all the diagonals, or not at all
[en_dim_y,en_dim_x]=size(enlarged_pic);
three_d(:,:,1)=enlarged_pic;
three_d(:,:,2)=[enlarged_pic(2:end,:);zeros(1,en_dim_x)];
three_d(:,:,3)=[zeros(1,en_dim_x);enlarged_pic(1:end-1,:)];
three_d(:,:,4)=[zeros(en_dim_y,1),enlarged_pic(:,1:end-1)];
three_d(:,:,5)=[enlarged_pic(:,2:end),zeros(en_dim_y,1)];
three_d(:,:,6)=[pic,zeros(dim_y,2);zeros(2,en_dim_x)];
three_d(:,:,7)=[zeros(2,en_dim_x);pic,zeros(dim_y,2)];
three_d(:,:,8)=[zeros(dim_y,2),pic;zeros(2,en_dim_x)];
three_d(:,:,9)=[zeros(2,en_dim_x);zeros(dim_y,2),pic];
And then see if the maximum along the 3rd dimension appears in the 1st layer (that is: three_d(:,:,1)):
(max_val, max_i) = max(three_d, 3);
result = find(max_i == 1);
Is there any more elegant way to do this? This seems like a bit of a kludge.
bw = pic > imdilate(pic, [1 1 1; 1 0 1; 1 1 1]);
If you have the Image Processing Toolbox, you could use the IMREGIONALMAX function:
BW = imregionalmax(y);
The variable BW will be a logical matrix the same size as y with ones indicating the local maxima and zeroes otherwise.
NOTE: As you point out, IMREGIONALMAX will find maxima that are greater than or equal to their neighbors. If you want to exclude neighboring maxima with the same value (i.e. find maxima that are single pixels), you could use the BWCONNCOMP function. The following should remove points in BW that have any neighbors, leaving only single pixels:
CC = bwconncomp(BW);
for i = 1:CC.NumObjects,
index = CC.PixelIdxList{i};
if (numel(index) > 1),
BW(index) = false;
end
end
Alternatively, you can use nlfilter and supply your own function to be applied to each neighborhood.
This "find strict max" function would simply check if the center of the neighborhood is strictly greater than all the other elements in that neighborhood, which is always 3x3 for this purpose. Therefore:
I = imread('tire.tif');
BW = nlfilter(I, [3 3], #(x) all(x(5) > x([1:4 6:9])) );
imshow(BW)
In addition to imdilate, which is in the Image Processing Toolbox, you can also use ordfilt2.
ordfilt2 sorts values in local neighborhoods and picks the n-th value. (The MathWorks example demonstrates how to implemented a max filter.) You can also implement a 3x3 peak finder with ordfilt2 with the following logic:
Define a 3x3 domain that does not include the center pixel (8 pixels).
>> mask = ones(3); mask(5) = 0 % 3x3 max
mask =
1 1 1
1 0 1
1 1 1
Select the largest (8th) value with ordfilt2.
>> B = ordfilt2(A,8,mask)
B =
3 3 3 3 3 4 4 4
3 5 5 5 4 4 4 4
3 5 3 5 4 4 4 4
3 5 5 5 4 6 6 6
3 3 3 3 4 6 4 6
1 1 1 1 4 6 6 6
Compare this output to the center value of each neighborhood (just A):
>> peaks = A > B
peaks =
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0
or, just use the excellent: extrema2.m