I have a solution to creating a vector for just one element of a matrix:
[dx,dy] = gradient(Im);
orient11 = [(-dx(1,1)) (dy(1,1)) 0];
where
size(orient11) =
0 0 0
ie for the first element of orient, namely orient11, is a vector. How do I do this for all the other elements, so I have orient12, orient13....orientnn. I know I need a for loop, however what object do I store the vectors into from the for loop? I have discovered I can't create a matrix of vectors.
Thanks in advance.
You can try building an N-by-N-by-3 matrix, but it won't be so convenient to manipulate. This is because extracting a vector from this matrix would yield a 1-by-1-by-3 vector, which you would need to reshape. Definitely not fun.
Instead, I suggest that you build an N-by-N cell array of 1-by-3 vectors, like so:
[dx, dy] = gradient(Im);
vec = #(i)[-dx(i), dy(i), 0];
orient = arrayfun(vec, reshape(1:numel(dx), size(dx)), 'UniformOutput', 0);
To access a vector, use the curly braces. For example, the vector at the (1, 2) position would be:
orient12 = orient{1, 2};
Hope it helps!
v = -2:0.2:2;
[x,y] = meshgrid(v);
z = x .* exp(-x.^2 - y.^2);
[px,py] = gradient(z,.2,.2);
orient11 = [(-px(1,1)) (py(1,1)) 0]; % based off of your concatination there.
size(orient11)
I then get:
ans =
1 3
If you're looking to just grab the first column of data from the gradients you have and want to just stack zeros with them, you can do this:
orient11 = [(-px(:,1)) (py(:,1)) zeros(size(px,1),1)];
Instead of a for loop.
Update:
Orient = zeros(size(px,1),3,size(px,2));
for n = 1:size(px,1)
Orient(:,:,n) = [(-px(:,n)) (py(:,n)) zeros(size(px,1),1)];
end
The layout of Orient is now your -px, py, 0 in layers. Each layer represents the column from the initial data. So if you wanted to get access to row 4 column 14, you would call Orient(4,:,14).
Hope that makes sense and helps!
Related
Sorry about the bad title, I'm struggling to word this question well. Basically what I want to do is extract elements from a 2d matrix, from row by row, taking out a number of elements (N) starting at a particular column (k). In for loops, this would look like.
A = magic(6);
k = [2,2,3,3,4,4]; % for example
N = 3;
for j = 1:length(A)
B(j,:) = A(j,k(j):k(j)+N-1);
end
I figure there must be a neater way to do it than that.
You could use bsxfun to create an array of indices to use. Then combine this with the row numbers and pass it to sub2ind.
inds = sub2ind(size(A), repmat(1:size(A, 1), 3, 1), bsxfun(#plus, k, (0:(N-1))')).';
B = A(inds);
Or alternately without sub2ind (but slightly more cryptic).
B = A(bsxfun(#plus, 1:size(A,1), ((bsxfun(#plus, k, (0:(N-1)).')-1) * size(A,1))).');
Here's one approach using bsxfun's masking capability and thus logical indexing -
C = (1:size(A,2))';
At = A.';
B = reshape(At(bsxfun(#ge,C,k) & bsxfun(#lt,C,k+N)),N,[]).';
I have an array with n dimensions, and I have a sequence along one dimension at a certain location on all other dimensions. How do I find the location of this sequence? Preferably without loops.
I use matlab. I know what dimension it should be in, but the sequence isnt necessarily there. Find and == dont work. I could make an nd find function using crosscorrelation but Im guessing this is already implemented and I just dont know what function to call.
example:
ND = rand(10,10,10,10);
V = ND(randi(10),randi(10),randi(10),:);
[I1, I2, I3] = find(ND==V);
Edit: The sequence to be found spans the entire dimension it is on, I did not mention this in my original formulation of the problem. Knedlsepp`s solution solves exactly the problem I had, but Luis' solution solves a more general problem for when the sequence doesn't necessarily span the entire dimension.
As there are multiple ways to interpret your question, I will clarify: This approach assumes a 1D sequence of size: numel(V) == size(ND, dimToSearch). So, for V = [1,2] and ND = [1,2,1,2] it is not applicable. If you want this functionality go with Luis Mendo's answer, if not this will likely be faster.
This will be a perfect opportunity to use bsxfun:
We start with some example data:
ND = rand(10,10,10,10);
V = ND(3,2,:,3);
If you don't have the vector V given in the correct dimension (in this case [1,1,10,1]) you can reshape it in the following way:
dimToSearch = 3;
Vdims = ones(1, ndims(ND));
Vdims(dimToSearch) = numel(V);
V = reshape(V, Vdims);
Now we generate a cell that will hold the indices of the matches:
I = cell(1, ndims(ND));
At this point we compute the size of ND if it were collapsed along the dimension dimToSearch (we compute dimToSearch according to V, as at this point it will have the correct dimensions):
dimToSearch = find(size(V)>1);
collapsedDims = size(ND);
collapsedDims(dimToSearch) = 1;
Finally the part where we actually look for the pattern:
[I{:}] = ind2sub(collapsedDims, find(all(bsxfun(#eq, ND, V), dimToSearch)));
This is done in the following way: bsxfun(#eq, ND, V) will implicitly repmat the array V so it has the same dimensions as ND and do an equality comparison. After this we do a check with all to see if all the entries in the dimension dimToSearch are equal. The calls to find and ind2sub will then generate the correct indices to your data.
Let d be the dimension along which to search. I'm assuming that the sought sequence V may be shorter than size(ND,d). So the sequence may appear once, more than once, or never along each dimension-d- "thread".
The following code uses num2cell to reshape ND into a cell array such that each dimension-d-thread is in a different cell. Then strfind is applied to each cell to determine matches with V, and the result is a cell array with the same dimensions as ND, but where the dimension d is a singleton. The contents of each cell tell the d-dimension-positions of the matches, if any.
Credit goes to #knedlsepp for his suggestion to use num2cell, which greatly simplified the code.
ND = cat(3, [1 2 1 2; 3 4 5 6],[2 1 0 5; 0 0 1 2] ); %// example. 2x4x2
V = 1:2; %// sought pattern. It doesn't matter if it's a row, or a column, or...
d = 2; %// dimension along which to search for pattern V
result = cellfun(#(x) strfind(x(:).', V(:).'), num2cell(ND,d), 'UniformOutput', 0);
This gives
ND(:,:,1) =
1 2 1 2
3 4 5 6
ND(:,:,2) =
2 1 0 5
0 0 1 2
V =
1 2
result{1,1,1} =
1 3 %// V appears twice (at cols 1 and 3) in 1st row, 1st slice
result{2,1,1} =
[] %// V doesn't appear in 2nd row, 1st slice
result{1,1,2} =
[] %// V appears appear in 1st row, 2nd slice
result{2,1,2} =
3 %// V appears once (at col 3) in 2nd row, 2nd slice
One not very optimal way of doing it:
dims = size(ND);
Vrep = repmat(V, [dims(1), dims(2), dims(3), 1]);
ND_V_dist = sqrt(sum(abs(ND.^2-Vrep.^2), 4));
iI = find(ND_V_dist==0);
[I1, I2, I3] = ind2sub([dims(1), dims(2), dims(3)], iI);
Say I have a nxm matrix and want to treat each row as vectors in a function. So, if I have a function that adds vectors, finds the Cartesian product of vectors or for some reason takes the input of several vectors, I want that function to treat each row in a matrix as a vector.
This sounds like a very operation in Matlab. You can access the ith row of a matrix A using A(i, :). For example, to add rows i and j, you would do A(i, :) + A(j, :).
Given an nxm matrix A:
If you want to edit a single column/row you could use the following syntax: A(:, i) for the ith-column and A(i, :) for ith-row.
If you want to edit from a column/row i to a column/row j, you could use that syntax: A(:, i:j) or A(i:j, :)
If you want to edit (i.e.) from the penultimate column/row to the last one, you could you: A(:, end-1:end) or A(end-1:end, :)
EDIT:
I can't add a comment above because I don't have 50 points, but you should post the function setprod. I think you should be able to do what you want to do, by iterating the matrix you're passing as an argument, with a for-next statement.
I think you're going to have to loop:
Input
M = [1 2;
3 4;
5 6];
Step 1: Generate a list of all possible row pairs (row index numbers)
n = size(M,1);
row_ind = nchoosek(1:n,2)
Step 2: Loop through these indices and generate the product set:
S{n,n} = []; //% Preallocation of cell matrix
for pair = 1:size(row_ind,1)
p1 = row_ind(pair,1);
p2 = row_ind(pair,2);
S{p1,p2} = setprod(M(p1,:), M(p2,:))
end
Transform the matrix into a list of row vectors using these two steps:
Convert the matrix into a cell array of the matrix rows, using mat2cell.
Generate a comma-separated list from the cell array, using linear indexing of the cell contents.
Example: let
v1 = [1 2];
v2 = [10 20];
v3 = [11 12];
M = [v1; v2; v3];
and let fun be a function that accepts an arbitrary number of vectors as its input. Then
C = mat2cell(M, ones(1,size(M,1)));
result = fun(C{:});
is the same as result = fun(v1, v2, v3).
Essentially I have an image mask and I want to find the width of the image in each column. Is there a way to vectorise this for speed? I tried to figure out a way with arrayfun but haven't hit on anything yet.
r = zeros(1,cols);
for i = 1 : cols
r(i) = range(find(img(:,i)));
end
The following code does the same as yours in a vectorized manner:
imglog = img~=0; %// convert to 0 and 1 values
[~, i1] = max(imglog); %// i1 is the position of the first 1
[~, i2] = max(flipud(imglog)); %// size(img,1)+1-i2 is the position of the last 1
r = size(img,1)+1-i2 - i1;
It exploits the fact that the second output of max gives the position of the first maximizer (for each column).
I am not sure whether this is faster, but num2cell + cellfun seems to be the only way to vectorize general functions on columns:
r = cellfun(#(x)range(find(x)),num2cell(img,1));
find + unique approach -
[row1,col1] = find(img);
[~,start1] = unique(col1,'first');
[~,stop1] = unique(col1);
r = row1(stop1) - row1(start1);
I need to make a scilab / MATLAB program that averages the values of a 3D matrix in cubes of a given size(N x N x N).I am eternally grateful to anyone who can help me.
Thanks in advance
In MATLAB, mat2cell and cellfun make a great team for working on N-dimensional non-overlapping blocks, as I think is the case in the question. An example scenario:
[IN]: A = [30x30x30] array
[IN]: bd = [5 5 5], size of cube
[OUT]: B = [6x6x6] array of block means
To accomplish the above, the solution is:
dims = [30 30 30]; bd = [5 5 5];
A = rand(dims);
f = floor(dims./bd);
remDims = mod(dims,bd); % handle dims that are not a multiple of block size
Ac = mat2cell(A,...
[bd(1)*ones(f(1),1); remDims(1)*ones(remDims(1)>0)], ....
[bd(2)*ones(f(2),1); remDims(2)*ones(remDims(2)>0)], ....
[bd(3)*ones(f(3),1); remDims(3)*ones(remDims(3)>0)] );
B = cellfun(#(x) mean(x(:)),Ac);
If you need a full size output with the mean values replicated, there is a straightforward solution involving the 'UniformOutput' option of cellfun followed by cell2mat.
If you want overlapping cubes and the same size output as input, you can simply do convn(A,ones(blockDims)/prod(blockDims),'same').
EDIT: Simplifications, clarity, generality and fixes.
N = 10; %Same as OP's parameter
M = 10*N;%The input matrix's size in each dimensiona, assumes M is an integer multiple of N
Mat = rand(M,M,M); % A random input matrix
avgs = zeros((M/N)^3,1); %Initializing output vector
l=1; %indexing
for i=1:M/N %indexing 1st coord
for j=1:M/N %indexing 2nd coord
for k=1:M/N % indexing third coord
temp = Mat((i-1)*N+1:i*N,(j-1)*N+1:j*N,(k-1)*N+1:k*N); %temporary copy
avg(l) = mean(temp(:)); %averaging operation on the N*N*N copy
l = l+1; %increment indexing
end
end
end
The for loops and copying can be eliminated once you get the gist of indexing.