AVI 形式の動画ファイルを扱う例を説明
codec の種類によっては octave で扱えない (正確には ffmpeg で扱えない)場合があることに留意しておく.
動画ファイルを再エンコードすると使えるようになる.
必見 Web ページ: http://www.eecs.berkeley.edu/Research/Projects/CS/vision/bsds/
※ プロンプトを変えたいときは,次のように操作する.
PS1('> ')
※ Octave のインストールによっては,Octave の起動時に毎回次の操作を行う必要があるかもしれない
pkg load image
■ Linux の場合
startx xhost + ssh -X username@ipaddress
octave
■ Windows の場合
デスクトップのアイコン等を使って Octave を起動
ファイル名とフレーム番号を指定している./usr/OpenCV-2.0.0/samples/c/tree.avi は OpenCV に付属のサンプルデータ
pkg load video img = aviread("/usr/local/share/OpenCV/samples/c/tree.avi", 100); imshow(img);
■ Octave 3.6.3, Ubuntu バージョン 12.04 での実行結果例
aviread() 関数で,必ずしもすべての種類 avi ファイルが読めるとは限りません. ffmpeg 内のコーデックと avi 動画ファイルの相性に起因すると思われるバグの例を示しておきます (このときは, Linux なら winff のようなツールを使ってエンコードしなおす)
1004 の挙動がおかしい
■ フレーム番号 1003
■ フレーム番号 1004
■ フレーム番号 1005
aviinfo() 関数を使って,1秒あたりのフレーム数,縦,横などを取得できる.
pkg load video avi = aviinfo("/usr/local/share/OpenCV/samples/c/tree.avi"); avi
■ Octave 3.6.3, Ubuntu バージョン 12.04 での実行結果例
pkg load video; img = aviread("/tmp/V0701001winff.avi", 1000); img2 = aviread("/tmp/V0701001winff.avi", 1002); # Octave 3.2.3 よりも古いバージョンの Octave では「imshow( (img2 - img) * 128 + 128 );」でうまく行く場合がある imshow( ( (img2 - img) + 1 ) / 2 );
■ Octave 3.3.53, Ubuntu での実行例
(参考)動画ファイルの差分画像の表示例
カメラが固定している場合,背景がきれいに除去できることが確認できた.
ガウシアンフィルタを使って,avi 形式動画ファイルの各フレームを「ぼかし」た後,32 色に減色することを繰り返す例. kbhit() 関数を使っているので,何かのキーを押すと次のフレームに移る.
pkg load video; s = 2; f = fspecial("gaussian", s * 5, s); for i = [100:110] rgb = aviread("/usr/OpenCV-2.0.0/samples/c/tree.avi", i); rgb2 = imfilter(double(rgb), f, "same"); imwrite(rgb2, "/tmp/hoge.ppm"); system( "ppmquant 32 /tmp/hoge.ppm > /tmp/hoge2.ppm" ); rgb3 = imread( "/tmp/hoge2.ppm" ); imshow( rgb3 ); kbhit(); end
※ imwrite() 関数の実行において「セマフォ・・・」のようなエラーがでることが有ります. このときは,プログラムの先頭で,関係の無い画像ファイルでいいので,imread(), imwrite() を実行しておく(つまり aviread() 関数の前に)とエラーを回避できる場合があります.
a = imread("fruits.jpg"); imwrite(a, "/tmp/fruits.jpg");
上の例では,画像を 1枚1枚表示していましたが,新しい avi 動画ファイルを作ってみることにします.
pkg load video; s = 2; f = fspecial("gaussian", s * 5, s); F = avifile("tree2.avi"); for i = [1:445] rgb = aviread("/usr/OpenCV-2.0.0/samples/c/tree.avi", i); rgb2 = imfilter(double(rgb), f, "same"); imwrite(rgb2, "/tmp/hoge.ppm"); system( "ppmquant 32 /tmp/hoge.ppm > /tmp/hoge2.ppm" ); rgb3 = imread( "/tmp/hoge2.ppm" ); addframe(F, double(rgb3) / 255); end
動画ファイルのフレーム(複数)を順に読み込み,png 形式で保存
while 文を使用.第 fromframe フレームから読み込み,toframe に達するか,フレームが無くなるまで処理を続ける.
※ AVI ファイルの全フレームについて同じ処理を繰り返すときのプログラム見本としても使えると思います.
※ 画像ファイルの確認には,ImageMagick の display コマンドが便利です.
function png2avi(filename, basename, fromframe, toframe, fps, bitrate) # png ファイルの連番画像ファイルを読み込んで,avi ファイルとして書き出す f = avifile(filename, "fps", fps, "bitrate", bitrate ); i = fromframe; while(true) # 変数 pngname は文字列データ pngname = sprintf("%s_%6.6d.png", basename, i); rgb = imread( pngname ); # 0 から 1 の範囲 rgb2 = double(rgb) / 255; addframe(f, rgb2); i = i + 1; if ( i > toframe ) break; endif endwhile endfunction function avi2png(filename, basename, fromframe, toframe) # avi ファイル(ファイル名は filename)を読み込んで,avi ファイルの中のフレームを png ファイルの連番画像ファイル(ファイル名は basename に「_」と数値をつなげたもの)として書き出す. # png ファイルとして書き出すフレームの範囲は fromframe, toframe で指定する i = fromframe; while(true) try img = aviread(filename, i); # OCtave 3.2 系列の場合 imwrite( img, sprintf("%s_%6.6d.png", basename, i) ); # OCtave 3.0 系列の場合 # imwrite( sprintf("\"%s_%6.6d.png\"", basename, i), img(:,:,1), img(:,:,2), img(:,:,3) ); fdisp(stderr, i); i = i + 1; if ( i > toframe ) break; endif catch # もし toframe の値が,動画ファイルの実際のフレーム数より大きいと実行時エラーが出るので catch して break する break; end_try_catch endwhile endfunction # avi ファイルを png 連番画像ファイルへ # avi2png( "/home/kaneko/V0701001winff.avi", "/home/kaneko/20090701001_avi01", 2000, 2200 ); # png 連番画像ファイルを avi ファイルへ # png2avi( "/home/kaneko/hoge.avi", "/home/kaneko/20090701001_avi01", 2000, 2200, 30, 800000);
avi2png( "/home/kaneko/V0701001winff.avi", "/home/kaneko/20090701001_avi01", 1, 10000 );