0
votes

I am trying to do an operation like the following for every pixels in an image:

equation

A is x*y*4 matrix, w is simply an 1x9 vector.

I have a matrix L which is 200x200x4x9.

The first two dimensions of L are (x,y) location of pixels. Each location has 4 different sub-pixel (the third dimension). Every sub-pixel has a vector m, which is the last dimension is the m in my equation.

I plan to get the result for the 1st sub-pixel for the whole image, that's what I tried:

A (:,:,1) = w * L (:, :, 1, :)  ====> Inputs must be 2-D, or at least one input must be scalar.
A (:,:,1) = w * L (:, :, 1, :)' ====> Transpose on ND array is not defined.
A (:,:,1) = w * reshape (L (:, :, 1, :), 1, 9)' ===> To RESHAPE the number of elements must not change.

If I just print L (1,1,1,:) I get values of individual elements (does not look like a vector):

ans(:,:,1,1) = 0.8980
ans(:,:,1,2) = 0.8065
ans(:,:,1,3) = 0.8471
ans(:,:,1,4) = 0.7607
ans(:,:,1,5) = 0.7175
ans(:,:,1,6) = 0.9020
ans(:,:,1,7) = 0.8100
ans(:,:,1,8) = 0.7640
ans(:,:,1,9) = 0.8135

EDIT: For reference,

Size(A) = [200 200 4]
Size(L) = [200 200 4 9] 
Size(w) = [1 9]

EDIT: That's how I do it using loops

loop

4
To get a vector, try squeeze(L(1,1,1,:)).H.Muster

4 Answers

0
votes

Multidimensional multiplication doesn't work in Matlab and that's why you can't do A = L * w!

From Mathworks page (How can I perform multi-dimensional matrix multiplication in MATLAB?):

Solution:

The ability to perform multi-dimensional matrix multiplication in MATLAB is not available.

As a workaround, use a FOR loop.

In addition, there is a user created function called NDFUN than performs N-D matrix multiplication. For more information, see the section on NDFUN at the following URL:

http://www.mit.edu/~pwb/matlab/

Solution with loops should look like this:

A = zeros( size(L)(1:3) );
for i = 1:size(L,1)
    for j = 1 : size(L,2)
        A(i,j,:) = squeeze( L(i,j,:,:) ) * w';
    end
end

But if you would prefer concise solution over the faster one (looping should be fast), you could use approach from answer Multiply a 3D matrix with a 2D matrix (assuming size(L) == [200 200 4 9] and size(w) = [1 9]):

Ac = cellfun( @(x) squeeze(x)' * w', num2cell(L,4), 'UniformOutput', false);
A = cell2mat( squeeze(Ac) );
2
votes

Rather than using matrix multiplication with reshape, etc, in a double for loop, it might be better to reverse the process and loop over the shorter dimensions, like this:

A=zeros(size(L)(1:3));
for i=1:9
    A(:,:,:)=A(:,:,:)+w(i).*L(:,:,:,i);
end

As a result, rather than doing 40000 loops through a double for loop, you do a total of 9 loops. And I suspect that Matlab's JITA will work on such a loop, too, to produce an even better result (I use octave, so I can't be certain - it's also not worth me doing any timing tests, as octave's timings wouldn't be valid for matlab).

It's also possible to do it purely in a vector form, by simply using vector indexing rather than matrix indexing. It works like this:

A=zeros(size(L)(1:3));
A(:)=reshape(L,numel(A),9)*w';

This version uses reshape, of course, but it avoids bsxfun and squeeze, and I suspect that it'll be faster than other solutions except the aforementioned for loop over the 9 values.

(naturally, if you want to restrict it to only the "First subpixel", you need to restrict the data. For the for loop option, just put a 1 in place of a colon in the appropriate places. For the reshape and matrix multiply option, replace L with L(:,:,1,:) in both places that it appears)

1
votes

you should use squeeze to get to a vector form. try

a=squeeze(L(1,1,1,:))
1
votes

I've recently become a big fan of bsxfun and, assuming I've understood you correctly, this seems like a perfect fit for it. We only need to reshape w and then take advantage of bsxfun's ability to automatically expand singleton dimensions to make the sizes of its inputs match.

w = reshape(w, [1, 1, 1, length(w)]);
A = sum(bsxfun(@times, L, w), 4);