Question involving nested 'for loops' pertaining to structs and cell arrays
2 ビュー (過去 30 日間)
古いコメントを表示
Hello,
In this script, I'm intending to create a cell array of contructs with each column corresponding to a contruct (11 total). I then intend on assigning a 'video' field to each of those constructs. For now, each 'video' field only has one video. I then intend on extracting each frame of these videos, and assign them to a 'frames' field corresponding to each trial. I know for a fact that these videos don't have the same number of frames (different video lengths).
Here's the issue. After the script is evaluated, each 'frames' field has 20 frames. While the first frames of each of these 'frames' fields is different, they all share the same last field. I'd appreciate it if someone could help me figure out why this happens.
I've been debugging this for a while now, all to no avail.
Please find the script below:
for n=2:12
t_x{1,n-1}.video=strcat('GN',num2str(n*25),'_1.mov');
end
%extracting frames of the video of each trial
n=size(t_x);
number_of_trials=n(1,2);
for n=1:number_of_trials
v=VideoReader(t_x{1,n}.video);
for m=1:v.NumberOfFrames
frames{1,m}=read(v,m);
t_x{1,n}.frames=frames;
end
end
0 件のコメント
採用された回答
Guillaume
2019 年 3 月 13 日
First a few comments about your code:
t_x{n}.video = sprintf('GN%d_1.mov', n*25);
In my opinion, it's more readable.
Secondly, since your cell array is a vector, I'd recommend that you use 1d indexing as I've done above instead of your 2d indexing. (so t_x{n} instead of t_x{1, n}). number_of_trials is then simply:
number_of_trials = numel(t_x);
You don't even need the variable, simply write numel(t_x) each time you used the variable, it's more compact anyway.
Third problem, and actually the cause of your trouble. Whenever you're assigning values to elements of an array in a loop you should make sure that the array already exist and even more importantly, that it is the correct size.
If an array does not exist, before you assign to it in a loop, matlab will grow the array at each step of the loop. That involves creating a new array one size bigger than at the previous step, copying all the elements of the previous array, and deleting the previous array. That's very inefficent. Always preallocate your arrays. For example, for your t_x:
t_x = cell(1, n-1); %preallocate cell array to avoid growing it in the following loop
for n = 2:12
t_x{n}.video = sprintf('GN%d_1.mov', n*25);
end
Now the cause of all your troubles is because you haven't preallocated frames. So, the first time your m loop runs, you're growing your cell array each step up to the number of frames in the video. However, the next time your m loop runs (for the next video), the array is already there and already filled. If the new videos have more frames than the previous one, then fine, you'll overwrite everything and grow it again, but if the array has less frames, then it won't reduce in size. So everything past the size of the current video will still be in your array. Simple way to fix that: reallocate the array before the loop:
for n = 1:numel(t_x)
v=VideoReader(t_x{n}.video);
frames = cell(1, v.NumberOfFrames); %preallocate so it's always empty and the correct size
for m = 1:v.NumberOfFrames
frames{m} = read(v, m);
end
t_x{n}.frames = frames;
end
And of course, the storing in the structure should be after the m loop, when you've finished filling the array.
その他の回答 (1 件)
Raghunandan V
2019 年 3 月 13 日
編集済み: Raghunandan V
2019 年 3 月 13 日
I think the problem is simple. Try deleting the frames using the command clear . I am pretty sure that you are just overwrite particular cells and the cells from previous iteration still exits. The code should now look like this
for n=2:12
t_x{1,n-1}.video=strcat('GN',num2str(n*25),'_1.mov');
end
%extracting frames of the video of each trial
n=size(t_x);
number_of_trials=n(1,2);
for n=1:number_of_trials
v=VideoReader(t_x{1,n}.video);
for m=1:v.NumberOfFrames
frames{1,m}=read(v,m);
end
t_x{1,n}.frames=frames;
clear frames;
end
please check and let me know if the error persists. I have also declared t_x inside other for loop as your code rewirtes everytime you are inside m loop.
6 件のコメント
Guillaume
2019 年 3 月 13 日
Yes, the size will change between loop, but with clear the size will also change during the loop. There is a big difference in efficiency between:
frames = cell(1, n); %or zeros(1, n), or whichever function preallocates the array depending on its type
for i = 1:n
frames{i} = something;
end
and
clear frames;
for i = 1:n
frames{i} = something;
end
Even though they produce exactly the same result. In the first case,
- matlab allocates memory for a 1xn array of whichever type
- at step 1, matlab copies something into the 1st element
- at step 2, matlab copies something into the 2nd element
- ...
- at step n, matlab copies something into element n
In the second case
- matlab makes sure the array doesn't exist
- at step 1, matlab sees that you want to put something in an array that does not exist, at index 1. Matlab therefore creates the array with enough room to fill that index. Hence it creates a 1x1 array and copy something in it.
- at step 2, the array exists but is only of size 1x1 whereas you want to put something at index 2. Therefore matlab, creates a new array of size 1x2, copies elements 1:1 of the existing array in the new array, copies something at index 2 and deletes the old array. frames is now the new array
- at step 3, again the array is too small. Matlab allocates a new array of size 1x3, copies the old elements 1:2, copies something into 3, deletes the old array.
- ...
- at step n, allocates a 1xn array, copies elements 1:n-1 from the old array, copies something, deletes the old array
As you can see, preallocation is so much more efficient. In the second case, matlab will actually put a wiggly line under the frames{i} = ... to warn you that you should preallocate.
参考
カテゴリ
Help Center および File Exchange で Loops and Conditional Statements についてさらに検索
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!