Search code examples
matlabcell-array

Extract contents from cell array


I have a series of Images, stored into an array A. So every entry of A contains an Image (matrix). All matrices are equally sized.

Now I want to extract the value of a specific position (pixel), but my current approach seems to be slow and I think there may be a better way to do it.

% Create data that resembles my problem
N = 5
for i = 1:N
A{i} = rand(5,5);
end

% my current approach
I = size(A{1},1);
J = size(A{1},2);
val = zeros(N,1);
for i = 1:I
    for j = 1:J
        for k = 1:N
            B(k) = A{k}(i,j);
        end
        % do further operations on B for current i,j, don't save B
    end
end

I was thinking there should be some way along the lines of A{:}(i,j) or vertcat(A{:}(i,j)) but both lead to

??? Bad cell reference operation.

I'm using Matlab2008b.

For further information, I use fft on B afterwards.

Here are the results of the answer by Cris

|     Code     | # images | Extracting Values |   FFT    |  Overall  |
|--------------|----------|-------------------|----------|-----------|
| Original     | 16       | 12.809 s          | 19.728 s | 62.884 s  |
| Original     | 128      | 105.974 s         | 23.242 s | 177.280 s |
| ------------ | -------- | ----------------- | -------  | --------- |
| Answer       | 16       | 42.122 s          | 27.382 s | 104.565 s |
| Answer       | 128      | 36.807 s          | 26.623 s | 102.601 s |
| ------------ | -------- | ----------------- | -------  | --------- |
| Answer (mod) | 16       | 14.772 s          | 27.797 s | 77.784 s  |
| Answer (mod) | 128      | 13.637 s          | 28.095 s | 83.839 s  |

The answer codes was modded to double(squeeze(A(i,j,:))); because without double the FFT took much longer.

Answer (mod) uses double(A(i,j,:));

So the improvement seems to really kick in for larger sets of images, however I currently plan with processing ~ 500 images per run.

Update

Measured with the profile function, the result of using/omitting squeeze

|              Code              | # Calls |   Time   |
|--------------------------------|---------|----------|
| B = double(squeeze(A(i,j,:))); | 1431040 | 36.325 s |
| B= double(A(i,j,:));           | 1431040 | 14.289 s |

Solution

  • A{:}(i,j) does not work because A{:} is a comma-separated list of elements, equivalent to A{1},A{2},A{3},...A{end}. It makes no sense to index into such an array.

    To speed up your operation, I recommend that you create a 3D matrix out of your data, like this:

    A3 = cat(3,A{:});
    

    Of course, this will only work if all elements of A have the same size (as was originally specified in the question).

    Now you can quickly access the data like so:

    for i = 1:I
        for j = 1:J
            B = squeeze(A3(i,j,:));
            % do further operations on B for current i,j, don't save B
        end
    end
    

    Depending on the operations you apply to each B, you could vectorize those operations as well.

    Edit: Since you apply fft to each B, you can obtain that also without looping:

    B_fft = fft(A3,[],3); % 3 is the dimension along which to apply the FFT