matlab "arrayfun" function - matlab

Consider the following function, which takes a gray image (2D matrix) as input:
function r = fun1(img)
r = sum(sum(img));
I'm thinking of using arrayfun to process a series of images(3d matrix), thus eliminating the need for a for loop:
arrayfun(#fun1, imgStack);
But arrayfun tries to treat every element of imgStack as an input to fun1, the result of the previous operation also being a 3D matrix. How can I let arrayfun know that I want to repeat fun1 only on the 3rd dimension of imgStack?
Another question, does arrayfun invoke fun1 in parallel?

In this case, you don't need arrayfun to perform your calculation, you can simply do this:
imgStack = rand( 10, 10, 4 ); % 4 10x10 images
r = sum( sum( imgStack, 1 ), 2 ); % sum along both dimensions 1 and 2
In general, lots of MATLAB operations will operate on a whole array at once, that's the usual way of avoiding loops.
MATLAB's normal "arrayfun" is not parallel. However, for GPUArrays (with Parallel Computing Toolbox), there is a parallel version of arrayfun.

On your first question:
You might try accumarray for this. One suggestion
function ds = applyfun_onfirstdim(arr, h_fun)
dimvec = size(arr);
indexarr = repmat( (1:dimvec(1))', [1, dimvec(2:end)] );
ds = accumarray(indexarr(:), arr(:), [], h_fun);
This creates an auxiliary index-array of the same dimensions as the input "arr". Every slice you want to apply h_fun to gets the same index-number. In this example it is the first.

Related

Efficient generation of permutation matrices in MATLAB

I'm trying to generate a 100-by-5 matrix where every line is a permutation of 1..100 (that is, every line is 5 random numbers from [1..100] without repetitions).
So far I've only been able to do it iteratively with a for-loop. Is there a way to do it more efficiently (using fewer lines of code), without loops?
N = 100;
T = zeros(N, 5);
for i = 1:N
T(i, :) = randperm(100, 5);
end
Let
N = 100; % desired number of rows
K = 5; % desired number of columns
M = 100; % size of population to sample from
Here's an approach that's probably fast; but memory-expensive, as it generates an intermediate M×N matrix and then discards N-K rows:
[~, result] = sort(rand(N, M), 2);
result = result(:, 1:K);
There is very little downside to using a loop here, at least in this minimal example. Indeed, it may well be the best-performing solution for MATLAB's execution engine. But perhaps you don't like assigning the temporary variable i or there are other advantages to vectorization in your non-minimal implementation. Consider this carefully before blindly implementing a solution.
You need to call randperm N times, but each call has no dependency on its position in the output. Without a loop index you will need something else to regulate the number of calls, but this can be just N empty cells cell(N,1). You can use this cell array to evaluate a function that calls randperm but ignores the contents (or, rather, lack of contents) of the cells, and then reassemble the function outputs into one matrix with cell2mat:
T = cell2mat(cellfun(#(~) {randperm(100,5)}, cell(N,1)));

In matlab is it possible to vectorize in more than one dimension?

The matlab documentation explains vectorization with
i = 0;
for t = 0:.01:10
i = i + 1;
y(i) = sin(t);
end
This is a vectorized version of the same code:
t = 0:.01:10;
y = sin(t);
Can I apply vectorization to a function with non-scalar inputs and outputs? As a toy example, take the function foo
function out = foo(in)
out(1) = in(1);
out(2) = in(2);
end
It's just the identity. I'd like to do something like
inputs = [1,2; 3,4; 5,6];
t = 1:3;
outputs = foo(inputs(t,:))
and get
ans =
1 2
3 4
5 6
Instead I end up with
ans =
1 3
Clearly, I'm either doing it wrong or it's not possible. Help!
It is possible to vectorize in Matlab in N-dimensions. As it was mentioned by Andrew you can simply writte a function like:
function out = foo(in)
out(:,1:size(in,2)) = in(:,1:size(in,2));
end
Output will be as desired.
Using the (:) index operator on n-dimensional arrays allows you to perform vectorized operations on all elements. You can use e.g. reshape to put the result back into the same form as the input.
function out=foo(in)
out=reshape(in(:),size(in));
The unexpected output
The reason your output is [1 3] has to do with linear indexing of matrixes. In particular this means that you can access the full matrix with a vector, where you first count through the first column, then the second column and so on. For a 3x2 matrix this would be:
1 4
2 5
3 6
Therefore in(1) = 1 is the first element in the first column. in(2) = 3 is the second element in the first column. Find the full documentation for matrix indexing here.
The input
Secondly writing outputs = foo(inputs(t,:)) means that you take all rows specified in t with no condition to the columns. Therefore in your example it is equivalent to write outputs = foo(inputs) and outputs = foo(inputs(t,:)) as you put in all 3 rows. What you could do is let foo() have two arguments.
function out = foo(t,in)
out = in(t,:)
To have access to the rows inside the function you could write something like:
function out = foo(in);
[x,y] = size(in);
for t = 1:x
out(t,:) = in(t,:);
end
Normally vectorization is used to avoid looping through scalars. There are a lot of clever ways to simplify code and reduce it's computation time. Most techniques like .* ,.^, bsxfun() are already presented in the documentation about vectorization you already found. The tricky part is to find the right way to apply these methods. It takes a lot of experience and a sharp eye to fully utilize them, as in every case you need to adjust to the specific logic of your opperations.
Feel free to ask if you still struggle with your problem.

vectorizing a matlab / octave FOR loop

I'm a little confused as to how to vectorize this for loop see code below:
array1=[xfreq_orig,yamp_orig,yamp_inv,phase_orig] %frequency, amplitudes, phases to use
t_rebuilt=linspace(0,2*pi,44100)
aa_sig_rebuilt_L=zeros(1,length(t_rebuilt));
aa_sig_combined_L=zeros(1,length(t_rebuilt));
sig_full_L=zeros(1,length(t_rebuilt));
for kk=1:1:numel(xfreq_orig);
aa_sig_rebuilt_L = array1(kk, 2)*cos ((array1(kk,1))*t_rebuilt+(array1(kk, 4)));
aa_sig_combined_L = aa_sig_combined_L + aa_sig_rebuilt_L;
end
sig_full_L=(aa_sig_combined_L/max(abs(aa_sig_combined_L))*.8);
I came up with this as vectorization
Example:
array1=[10,.4,.34,2.32;12,.3,.45,.4];
t_rebuilt=linspace(0,2*pi,44100)
aa_sig_rebuilt_L = array1(kk, 2).*cos ((array1(kk,1)).*t_rebuilt+(array1(kk, 4)));
aa_sig_combined_L = sum(aa_sig_rebuilt_L);
What I don't know how to do is how to get the kk variable to access the rows incrementally
THanks.
One option is to use bsxfun as follows
a = array1;
t = t_rebuilt;
aa_sig_rebuilt_L = bsxfun(#times, a(:,2) , ...
cos( bsxfun(#plus, bsxfun(#times, a(:,1), t), a(:,4)) ));
aa_sig_combined_L = sum(aa_sig_rebuilt_L);
Bear in mind that this will use more memory than the version will a loop (it will use numel(xfreq_orig) times as much memory, as it computes every row of aa_sig_rebuilt_L before summing them, whereas the loop computes each row, adds it to the sum and then discards it).
The function bsxfun is used when you need to perform a binary operation between arrays of different sizes, e.g. a TxN matrix and a Tx1 vector. In this case it would perform the operation between each column of the matrix and the vector.
In your case you have a column vector and a row vector, and the operation is applied to the i'th element of the column vector and the j'th element of the row vector, to get the ij'th element of a matrix.

Apply function to every pair of columns in two matrices in MATLAB

In MATLAB, I'd like to apply a function to every pair of column vectors in matrices A and B. I know there must be an efficient (non for) way of doing this, but I can't figure it out. The function will output a scalar.
Try
na = size(A,1);
nb = size(B,1);
newvector = bsxfun(#(j,k)(func(A(j,:),B(k,:))),1:na,(1:nb)');
bsxfun performs singleton expansion on 1:na and (1:nb)'. The end result, in this case, is that func will be applied to every pair of column vectors drawn from A and B.
Note that bsxfun can be tricky: it can require that the applied function support singleton expansion itself. In this case it will work to do the job you want.
Do you mean pairwise? So in a for-loop the function will work as scalar_val = func(A(i),B(i))?
If A and B have the same size you can apply ARRAYFUN function:
newvector = arrayfun(#(x) func(A(x),B(x)), 1:numel(A));
UPDATE:
According your comment you need to run all combinations of A and B as scalar_val = func(A(i), B(j)). This is a little more complicated and for large vectors can fill the memory quickly.
If your function is one of standard you can try using BSXFUN:
out = bsxfun(#plus, A, B');
Another way is to use MESHGRID and ARRAYFUN:
[Am, Bm] = meshgrid(A,B);
out = arrayfun(#(x) func(Am(x),Bm(x)), 1:numel(Am));
out = reshape(out, numel(A), numel(B));
I believe it should work, but I don't have time to test it now.

Blockproc-like function for cell array output

I like blockproc, it makes working with large (very large) images easily. However, as far as I understand, it is limited to working with functions that output a matrix of the same size as the input they take.
So I was wondering if there is a way of replicating/simulating what blockproc does but for functions that output a cell array. We can either assume that the output array from the processing function is of the same dimensions of the input matrix, or that it just outputs one cell element, in which case the final output from the total processing would be a cell array with M x N elements, with M and N specifying the tiling for the processing.
I believe I can build this myself using cellfun, but I was wondering if there is are any other builtins or libraries (maybe third-party?) that I can use for this, and maybe even completely avoid reinventing the wheel.
More specifically, I am looking for something that has the same strengths as blockproc:
Can load a large image from disk progressively tile-by-tile to minimize the memory footprint of the processing
Takes care of the final concatenation of results for building the final cell array
Has an interface similar to blockproc (e.g. # of tiles, etc.)
Below is a solution that satisfies your criteria except for the first point
Use the IM2COL function to arrange distinct image blocks from the image into columns, then apply your function to each column storing the result in a cell array.
Of course this only works if all blocks fit into memory, otherwise you would have to manually write code that extracts one block at a time and process it in that way...
%# read image
img = im2double(imread('tire.tif'));
%# blocks params
sizBlk = [8 8];
numBlk = ceil( size(img) ./ sizBlk );
%# extract blocks
B = im2col(img, sizBlk, 'distinct');
B = reshape(B, [sizBlk size(B,2)]); %# put blocks on the 3rd dimension
B = squeeze( num2cell(B,[1 2]) ); %# convert to cell array
B = reshape(B, numBlk); %# reshape as blocks overlayed on image
%# process blocks
myFcn = #(blk) [mean2(blk) std2(blk)]; %# or any other processing function
I = cellfun(myFcn, B, 'UniformOutput',false);
%# in this example, we can show each component separately
subplot(121), imshow( cellfun(#(c)c(1),I) ), title('mean')
subplot(122), imshow( cellfun(#(c)c(2),I) ), title('std')
Alternatively, you could still use the BLOCKPROC function, but you have to call it multiple times, each time computing a single feature:
%# compute one feature at a time
b1 = blockproc(img, sizBlk, #(b)mean2(b.data), 'PadPartialBlocks',true);
b2 = blockproc(img, sizBlk, #(b)std2(b.data), 'PadPartialBlocks',true);
%# combine into cellarray of features
II = arrayfun(#(varargin)[varargin{:}], b1, b2, 'UniformOutput',false);
%# compare to previous results
isequal(I,II)
I've been doing something similar, although with numeric values rather than cell.
Something like this should work :
I = imread('pout.tif');
G = blockproc(I, [8 8], #(b) shiftdim(imhist(b.data)', -1), 'PadPartialBlocks', true);
G = reshape(G, size(G, 1) * size(G, 2), size(G, 3));
pout.tif is a greyscale image but I'm sure this can be changed up for RGB.
Also take care when using shiftdim, imhist returns a row vector so I transpose it to a column.