VideoWriterについての質問です

フレームレート100の各画像上に10ミリ秒ごとのプロットを重ね、最終的にそれらを結合してアニメーションを作りたいのですが、いちいち各画像をimreadしてその時点に対応するプロットをhold onしてwriteVideoするというやり方だとループが膨大になり時間がかかってしまいます。
プロット結合画像をあらかじめcell配列などに格納してからwriteVideoするというようなやり方はありますでしょうか。ちなみにMatlab R2016aを使用しています。
参考までに私のスクリプトの一部を添付いたします。
*movieimgというcellにもとの画像ファイル名が格納されています。
savefn=['C:\Users\Desktop\Movie_File'];
v = VideoWriter(savefn);
v.FrameRate = 100;
open(v);
for t=1:length(movieimg)
imread(cell2mat(movieimg(t)));
hold on;
scatter(x,y,'r');
frame = getframe(gcf);
writeVideo(v,frame);
end

1 Comment

KO
KO on 27 Jun 2021
なお、画像データはunit8です。

Sign in to comment.

Answers (1)

Shunichi Kusano
Shunichi Kusano on 27 Jun 2021

0 votes

複数フレームをまとめて書き込めるようですね。R2016だとこれできない、ということでしょうか。
メモリに収まりきる分だけのフレームを保持して書込み、をforで回せば良いかと思います。

6 Comments

KO
KO on 27 Jun 2021
ご回答ありがとうございます。
複数フレームをまとめて書き込む、や、メモリに収まりきる分だけのフレームを保持して書き込む、とは具体的にどういうことでしょうか。
理解できずすみません。
Shunichi Kusano
Shunichi Kusano on 28 Jun 2021
説明不足ですみません。
複数フレームをまとめて書き込むは、KOさんがされたいことそのままだと理解しています。「プロット結合画像をあらかじめcell配列などに格納してからwriteVideoする」の部分です。cellではなくて、getFrameで得られる構造体を、複数まとめてwriteVideoできます。詳細はリンクをご覧ください。
メモリに収まりきる分だけ、というのは100fpsの動画ということで、場合によっては動画一本分の画像データをメモリに保持できないかも、と思ったので加えた文言です。close さえしなければ動画ファイルにいくらでも追記できますので、例えば1000フレーム(10秒分)処理しておいてwriteVideo、そして次の1000フレーム処理してwriteVideo、という形で繰り返せばお手持ちのメモリに収まる範囲内で処理を書けます。
不明な点ありましたらお知らせください。
KO
KO on 28 Jun 2021
何度もすみませんが、僕の頭では十分に理解できません。そもそも、フレームやaxなどの概念が理解できていないと思います。
イメージとしては、cellではなくてgetFrameで得られる構造体の空行列を設定し、そこにframeを格納し、ループで回したいのですが、先に空行列を作ろうにも「有効な Figure または Axes のハンドルを指定しなければなりません」などといった表示が出てしまいます。そもそもgetframeで空の構造体を作るというやり方が違うのかもしれませんが。
具体的には以下のようにしたいのですが、そもそも1行目の使い方が間違っていると思います。また、これでは対象のFigureを指定できていないのも問題だと思います。ただ、このやり方ですとforループの外にwriteVideoを置けるので高速化することができそうです。何かいい方法はありますでしょうか。
frame=getframe(1,length(movieimg)); (←ここがそもそもおかしい)
savefn=['C:\Users\Desktop\Movie_File'];
v = VideoWriter(savefn);
v.FrameRate = 100;
open(v);
for t=1:length(movieimg)
imread(cell2mat(movieimg(t)));
hold on;
scatter(x,y,'r');
frame(t) = getframe(gcf);
end
writeVideo(v,frame);
Shunichi Kusano
Shunichi Kusano on 29 Jun 2021
Edited: Shunichi Kusano on 30 Jun 2021
説明も大変なので、下記のようにコードを作ってみました。
が、まとめて数フレーム書き込むと逆に遅くなってしまいました。これは私も計算外です。現状解決策が思い浮かばないのですが、とりいそぎ共有いたします。
maxFrame = 100; % 全フレーム数
frameStep = 10; % 一時保存する画像データのフレーム数
v = VideoWriter('test','MPEG-4');
open(v);
f = figure; % figureを非表示で出す(描画分の計算時間節約)
imshow(rand(100,100));
s_frame = getframe(f);
s_frames = repmat(s_frame,[1 frameStep]); % 一時保存用の配列の準備
tic
for framei = 2:maxFrame % フレームごとに
% 保存する画像を作成
imshow(rand(100,100)); % ダミーデータ
frame_mod = mod(framei,frameStep);
if frame_mod > 0 % frameStep数分の保存を開始
s_frames(frame_mod) = getframe(f);
else
s_frames(frameStep) = getframe(f);
writeVideo(v,s_frames); % frameStep数分だけまとめて書込み
framei
end
end
toc
close(v);
% ちなみに下記が1フレームずつ書き込むテスト
v = VideoWriter('test','MPEG-4');
open(v);
f = figure; % figureを出す
tic
for framei = 2:maxFrame % フレームごとに
imshow(rand(100,100)); % ダミーデータ
writeVideo(v,getframe(f)); %
end
toc
close(v);
KO
KO on 30 Jun 2021
ご回答ありがとうございます。
matlabでも画像データの処理には時間がかかってしまうのでしょうかね。
上の式を完全に理解するのにまだ時間がかかりそうですが、たくさんのヒントをありがとうございました。とても勉強になりました。
Shunichi Kusano
Shunichi Kusano on 30 Jun 2021
バタバタしたときに回答したので、説明が少なくすみません。上のコードも一部訂正しました。
(figureのVisibleプロパティですが、offにしても大して実行時間は変わらずでした)
上のコードでわかりづらいところはif文のあたりかと思いますが、少し解説します。
frame_modはframei / frameStepを計算したときの余りです。frameiは現在何回目のfor文内実行か、frameStepは一時保存するフレーム数です。frameiはfor文繰り返しごとに2から3,4,5…と増えていきますが、余りも同じように2,3,4,5…と増えていきます。が、このときは、描画した画像のデータをどんどんs_framesに保存していきます。
frameiがframeStepで割り切れる数まで来ると、これまで保存してきたフレームデータを一気にまとめてwriteVideoします。
次のループではframe_modはまた1から2,3,4…と増えていくことになるので、s_framesに保存するだけとなり、またframeiがframeStepで割り切れる数まで来たら保存、と、これを繰り返して、必要なフレーム数maxFrameまで達したら終了、という流れとなります。文章だとわかりづらいと思いますが、コードと見比べながら咀嚼してみてください。
いま気付きましたが、上のコードですと、maxFrameがframeStepで割り切れないときは、最後の端数分の書込みが実行されないことになるので、elseif framei == maxFrameを足した方がいいですね。

Sign in to comment.

Categories

Asked:

KO
on 27 Jun 2021

Commented:

on 30 Jun 2021

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!