videoWrite​rによる動画出力の高​速化について

対象物の自動検出と追従する動画解析を行っています。解析して対象物に色を塗ったり、線を書き加えるなどして動画出力をしています。
動画出力する際に、どうしても時間を要すために、高速化の方法があればご教授ください。
以下の方法は実践済です。
・フレームレイト調整
・MPEG-4での出力
・画像の縮小
★「imshow」を行うことに時間がかかっているのですが、これは外せないでしょうか・・・
★解析結果(対象物の座標)の取得のみまず行い、動画の作成は後で行うために別変数で保存する方法などもあればお教えください。
% 解析動画読み込み
vidObj = VideoReader("video.mp4");
% 出力動画ファイル
VideoWriter(strcat('trackSoftAlphaVer2_',sprintf(filename)),
% 1frameずつ読み込み&解析
while hasFrame(vidObj)
img = readFrame(vidObj);
~~~~~~~~~~~~~~~~~~~~~
% imgに対する解析
% 目標物の座標(X, Y)を算出
% 画像内の直線の軌跡(Line)を算出
~~~~~~~~~~~~~~~~~~~~~
figure('Visible', 'off');
imshow(img); hold on
scatter(X, Y);
plot(Line);
hold off
vidImg = getframe(gcf);
writeVIdeo(outVideo, vidImg);
end

 Accepted Answer

Kojiro Saito
Kojiro Saito on 17 Oct 2024
プロファイラーをかけてみたところ、imshowとgetframe、そしてfigureの処理時間が掛かっています。
現在のコードでは画像を表示してからscatterとplotをおこなっているので、getframeで画像を取得する必要があり、imshowも必要になります。figureは毎回作成する必要ないので、これをwhileの外に置くだけで処理時間がかなり速くなります。
figure('Visible', 'off');
% 1frameずつ読み込み&解析
while hasFrame(vidObj)
% TODO
end
また、Computer Vision Toolboxを使用できるならinsertShapeinsertMarkerでplotとscatterに近いことができ、画像上に直接描けるのでより高速に実現できます。
vidObj = VideoReader("xylophone_video.mp4");
% 出力動画ファイル
outVideo = VideoWriter("out4.mp4", "MPEG-4");
open(outVideo)
figure('Visible', 'off');
% 1frameずつ読み込み&解析
while hasFrame(vidObj)
img = readFrame(vidObj);
%~~~~~~~~~~~~~~~~~~~~~
% imgに対する解析
% 目標物の座標(X, Y)を算出
% 画像内の直線の軌跡(Line)を算出
%~~~~~~~~~~~~~~~~~~~~~
X = randi(100);
Y = randi(100);
RGB = insertMarker(img, [X Y], "circle", MarkerColor="b");
lineData = reshape([0:100 0:100], [], 2);
RGB = insertShape(RGB, "line", lineData, ShapeColor="b");
writeVideo(outVideo, RGB);
end
close(outVideo)

10 Comments

HanaHana
HanaHana on 18 Oct 2024
Edited: HanaHana on 18 Oct 2024
プロファイラーまでかけていただきありがとうございます。
とてもよく理解できるとともに勉強になりました。
1)insert~の使用に関してですが、表出しているグラフの軸ラベルやメモリ等にかなり設定を加えています。そのような場合でもinsert~で対応できる範疇でしょうか?
2)上記の関係でscatterの前に、axes関数を入れているのですが、「figure('Visible', 'off');」 をfor文の外に出すと、グラフのみが動き、imgが更新されません。対応策ございますでしょうか?
Kojiro Saito
Kojiro Saito on 18 Oct 2024
inserTextで画像にテキストを挿入でき、軸ラベルの代替はできますが、等間隔の目盛りを書くのは大変だと思います。従来通りimshow、hold ongetframeでおこなったほうが良さそうです。
Kojiro Saito
Kojiro Saito on 18 Oct 2024
@HanaHanaさん
2)は、getframeの前にdrawnow limitrateを追加してみたらいかがでしょうか?
HanaHana
HanaHana on 18 Oct 2024
insertTextについて、分かりました。
drawnow limitrateでは、imgの更新がされませんでした。もし他にアイデアございましたら試してみたいと思いますので、引き続きご助言お願いいたします。
imshowは引き続き入れていますでしょうか?
下記のサンプルではimshowimgの更新がされています。
vidObj = VideoReader("xylophone_video.mp4");
% 出力動画ファイル
outVideo = VideoWriter("out.mp4", "MPEG-4");
open(outVideo)
figure('Visible', 'off');
% 1frameずつ読み込み&解析
while hasFrame(vidObj)
img = readFrame(vidObj);
X = randi(100);
Y = randi(100);
imshow(img);
hold on
scatter(X, Y);
plot(0:100, 0:100)
hold off
vidImg = getframe(gcf);
writeVideo(outVideo, vidImg);
end
close(outVideo)
HanaHana
HanaHana on 18 Oct 2024
Edited: HanaHana on 18 Oct 2024
お伝えする情報が不足しておりました。
重ね合わせるグラフが複雑かつ軸の操作を加える関係で以下のようになっております。
while hasFrame(vidObj)
img = readFrame(vidObj);
X = randi(100);
Y = randi(100);
imshow(img);
hold on
scatter(X, Y); % img全体に書き込み
ax = axes('Position', [~,~,~,~,]); % グラフは画面右側に配置するためその位置を指定
plot(0:100, 0:100); % グラフに書き込むデータ⓵
hold on % グラフに書き込むデータが複数あるので、ここで改めてhold on
plot(0:100, 0:200); グラフに書き込むデータ⓶
ax.Color = 'r';
ax.XLabel.String = "time";
hold off
vidImg = getframe(gcf);
writeVideo(outVideo, vidImg);
end
axesを使ったところでなにかおかしくなっているでしょうか。
Kojiro Saito
Kojiro Saito on 20 Oct 2024
Edited: Kojiro Saito on 20 Oct 2024
@HanaHanaさん
画像を表示する座標軸と、グラフを表示する軸が2つあるため、hold onだけではうまく画像の描画更新ができていないようです。hold(ax1, 'on')hold(ax1, 'off')のようにどちらの座標軸を固定するのか指定してみてください。
下記のコードで動作確認できました。グラフの座標軸を毎回作ると時間が掛かるので、axes(fig, 'Position', [])をwhileループの外に置いています。
% 解析動画読み込み
vidObj = VideoReader("xylophone_video.mp4");
% 出力動画ファイル
outVideo = VideoWriter("out5.mp4", "MPEG-4");
open(outVideo)
tic
fig = figure('Visible', 'off');
ax1 = gca;
ax2 = axes(fig, 'Position', [0.7, 0.7, 0.2, 0.2]); % グラフは画面右側に配置するためその位置を指定
while hasFrame(vidObj)
img = readFrame(vidObj);
X = randi(100);
Y = randi(100);
imshow(img, Parent = ax1);
hold(ax1, 'on')
scatter(ax1, X, Y); % img全体に書き込み
hold(ax1, 'off')
% グラフは画面右側に配置するためその位置を指定
plot(ax2, 0:100, 0:100); % グラフに書き込むデータ⓵
hold(ax2, 'on') % グラフに書き込むデータが複数あるので、ここで改めてhold on
plot(ax2, 0:100, 0:2:200); %グラフに書き込むデータ⓶
hold(ax2, 'off')
ax2.Color = 'r';
ax2.XLabel.String = "time";
vidImg = getframe(gcf);
writeVideo(outVideo, vidImg);
end
t = toc
close(outVideo)
HanaHana
HanaHana on 23 Oct 2024
返信が遅くなり申し訳ありません。
お示しいただいた方法で無事に描画更新ができました。
ただ、imgの画像サイズがこれまでよりも小さくなってしまいます。感覚的に75%くらい?
これまではできあがった動画画面いっぱいにimgが表示されていたのが、周りに白い余白ができてしまいます。
動画全体に対するグラフの位置は変わりません。こちらも対応策ありましたらご助言ください。
座標軸 (axes)がFigure に対して余白を持つためですね。
ax1 を定義するところで、Positionプロパティで開始位置を0、横幅と縦幅を1に設定してFigure の全領域を使うように設定してみてください。
%ax1 = gca;
ax1 = axes(fig, 'Position', [0, 0, 1, 1]);
ax2 = axes(fig, 'Position', [0.75, 0.75, 0.2, 0.2]);
ax2 の位置がやや左寄りになってしまうので、こちらのPosition の値も調整してみました。
HanaHana
HanaHana on 25 Oct 2024
無事にサイズが安定しました。
幅広い領域にわたりご助言ありがとうございました。勉強になりました。

Sign in to comment.

More Answers (0)

Products

Release

R2023a

Asked:

on 16 Oct 2024

Commented:

on 25 Oct 2024

Community Treasure Hunt

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

Start Hunting!