Matlabで時間軸方向に連続する動画データを可視化する。この際に必要になる動画の各フレームに対する処理と、動画データにカラーマップを適用する処理をまとめた。
ソースは以下で公開
gist
使ったもの
- Matlab R2016a student
- Image Processing Toolboxが必要
問題点
matlabのim2frameを用いると、イメージをムービーフレーム(構造体配列)に変換することができる。
f = im2frame(X);
ムービーフレームを作製しておくと動画の再生(movie)や書き込み(writeVideo)に使うことができる。
そこでim2frameを用いて、動画データ(m x n x c x t
)をムービーフレームに変換したい。
しかしこの関数の引数X
は
1. インデックス付きイメージかトゥルーカラー イメージだけしか許されていない(see also: イメージの種類)
2. ndims>3の動画データ(m x n x c x t
)は許されていない
の2点の制約があるため動画データを直接変換することはできない。
解決法
動画データの種類によって変わる
動画データ(トゥルーカラー)からムービーフレームへの変換
動画データ(m x n x 3 x t
)の各フレームがトゥルーカラー イメージの場合はそれぞれをim2frameに代入するだけでよい。
普通にfor文を用いて以下のように処理してもよいが、
%% Test RGB Data (with for loop)
NofFrame = 300;
MovieData = rand(64, 64, 3, NofFrame);
for fi = 1:NofFrame
frame(fi) = im2frame(MovieData(:, :, :, fi));
end
movie(frame, 1, 30);
arrayfunでスライスするとスッキリとなる。
%% Test RGB Data
NofFrame = 300;
MovieData = rand(64, 64, 3, NofFrame);
frame = arrayfun(@(fi) im2frame(MovieData(:, :, :, fi)), 1:NofFrame);
movie(frame, 1, 30);
データはランダムなカラーノイズ
動画データ(インデックス付き)からムービーフレームへの変換
動画データ(m x n x 1 x t
)のインデックスに対応するmapを添える。
%% Test Ind Data
NofFrame = 300;
NofScale = 256;
MovieData = randi(NofScale, 64, 64, 1, NofFrame);
frame = arrayfun(@(fi) im2frame(MovieData(:, :, :, fi), hot(NofScale)), 1:NofFrame);
movie(frame, 1, 30);
動画データ(未整形)からムービーフレームへの変換
動画データ(m x n x 1 x t
)が未整形の場合はmat2gray, gray2ind を使って動画の各フレームをインデックス付きイメージに変換する。
%% Test Mat Data (convert to Ind Data)
NofFrame = 300;
NofScale = 256;
MovieData = rand(64, 64, 1, NofFrame);
% convert mat -> (gray) -> ind
MovieData = gray2ind(mat2gray(MovieData , [min(MovieData(:)), max(MovieData(:))]), NofScale);
frame = arrayfun(@(fi) im2frame(MovieData(:, :, :, fi), cool(NofScale)), 1:NofFrame);
movie(frame, 1, 30);
ind2rgbを用いると、インデックス付きイメージからトゥルーカラー イメージに変換できるが、この関数は画像(m x n
)に対してのみしかうまく動作しない。(色チャネルを結合する際のインデックスの振り方のせい)
どうしてもトゥルーカラーの動画データがほしい場合は以下のようにrgbを分けて出力し、catで3次元目を結合する。
%% Test Mat Data (convert to RGB Data)
% ind2rgb function doesn't work for 3-or-more dimentional FrameData
NofFrame = 300;
NofScale = 256;
MovieData = rand(64, 64, 1, NofFrame);
% convert mat -> (gray) -> (ind) -> (r, g, b) -> rgb
[r, g, b] = ind2rgb(gray2ind(mat2gray(MovieData , [min(MovieData(:)), max(MovieData(:))]), NofScale), spring(NofScale);
MovieData = cat(3, r, g, b);
frame = arrayfun(@(fi) im2frame(MovieData(:, :, :, fi)), 1:NofFrame);
movie(frame, 1, 30);
まとめ
- 動画データをムービーフレームに変換することができる。
- arrayfunを用いることでfor文を書かずにデータをスライスできる。
- mat2gray, gray2indを連続して使うことでデータを変換できる。
参考
im2frame | movie | writeVideo | arrayfun | mat2gray | gray2ind | ind2rgb