Reputation: 4975
I am trying to do an operation like the following for every pixels in an image:
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
Upvotes: 0
Views: 3831
Reputation: 733
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)
Upvotes: 2
Reputation: 7028
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:
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) );
Upvotes: 0
Reputation: 600
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);
Upvotes: 1
Reputation:
you should use squeeze
to get to a vector form. try
a=squeeze(L(1,1,1,:))
Upvotes: 1