AVI 形式の動画ファイルを扱う例
AVI 形式の動画ファイルを扱う例を説明
- 動画ファイルの読み込み(フレーム単位)
- 簡単なフレーム間差分表示
- 動画ファイルの全フレームを順に読み込み,png 形式で保存
前準備
- Octave のインストールが済んでいること.
- (Linux の場合)Octave の video パッケージのビルドが済んでおり,ビルドで出来た oct ファイルが,Octave のパスが通ったディレクトリに格納されていること.
- avi 形式の動画ファイルを準備しておく
codec の種類によっては octave で扱えない (正確には ffmpeg で扱えない)場合があることに留意しておく.
動画ファイルを再エンコードすると使えるようになる.
必見 Web ページ: http://www.eecs.berkeley.edu/Research/Projects/CS/vision/bsds/
* プロンプトを変えたいときは,次のように操作する.
PS1('> ')
* Octave のインストールによっては,Octave の起動時に毎回次の操作を行う必要があるかもしれない
pkg load image
実行方法と実行結果の例
- Octave の起動
* Linux の場合
- (オプション)Cygwin からリモートログインする場合
startx xhost + ssh -X username@ipaddress
- octave の起動
octave
* Windows の場合
デスクトップのアイコン等を使って Octave を起動
- (オプション)Cygwin からリモートログインする場合
- 動画ファイルの読み込み(1フレーム分)とフレームの確認表示
ファイル名とフレーム番号を指定している./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
Octave で avi 形式動画ファイルを扱う例
avi 形式動画ファイルに関する情報取得
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 形式動画ファイルの各フレームに関する繰り返し処理
ガウシアンフィルタを使って,avi 形式動画ファイルの各フレームを「ぼかし」た後,32 色に減色することを繰り返す例. kbhit() 関数を使っているので,何かのキーを押すと次のフレームに移る.
- ぼかし:ガウシアンフィルタ
- 減色:ppmquant コマンドを system 関数を使って呼び出す.
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");
avi 形式動画ファイルの生成の例
上の例では,画像を 1枚1枚表示していましたが,新しい avi 動画ファイルを作ってみることにします.
- avi 形式動画ファイルの生成: avifile() 関数
- avi 形式動画ファイルの末尾にフレームを追加: addframe() 関数
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 );