チュートリアル
はじめに
Streaming VIOSは、汎用OS上で疑似的なリアルタイム処理を実現するためのライブラリです。
Streaming
VIOSを用いることにより、解像度の変更をなるべく意識することなく動画像処理プログラムの記述が可能となります。
1. プログラムの流れ
- 初期化
- 初期化パラメータを SVOIS_INITPARAM 型の変数に設定し、SVIOSInitialize()の引数として呼び出すことにより、Streaming
VIOSを初期化する。
- 実際に画像処理を行う関数を CSVIOSCore::SetMainloop() を用いてStreaming VIOSに登録する。
- 処理に必要な画像などを生成、初期化
- 解像度の管理が必要な変数を CSVIOSCore::Add() を用いてStreaming
VIOSに登録する。この操作を行わない限り、解像度の変更の通知はされない。
- 実行開始
- CSVIOSCore::DoMainloop()または、CSVIOSCore::EnterMainloop()を実行
DoMainloop() では、登録された動画像処理関数を一度だけ実行する。
EnterMainloop() では、設定したフレームレートの間隔で、登録された動画像処理関数を呼び出し続ける。動画像処理関数の戻り値が負の時に終了する。
- ストリーミング処理下記、「ストリーミング処理」参照
- 終了
- Streaming VIOSを終了(SVIOSUninitialize()を呼び出す)
2. ストリーミング処理
- 初期化
- Streaming VIOSのデフォルトバッファを利用する場合、デフォルトバッファを充填する。
- 又は、CVLLStreamBuffer変数を用意し、初期化する
- 実行
- Streaming
VIOSのストリーミングバッファより CSVIOSCore::GetData() を用いて時系列データを受け取る。
- 受け取った時系列データを使って画像処理を行う。
- 時系列データに対して書き込むときは、CSVIOSCore::PushData() (時系列データへの直接書き込み)または、CSVIOSCore::GetWritePtr() (時系列データへのポインタの取得)を使う。
- 終了
- CVLLStreamBufferを用いた場合は、バッファを解放する。
3. コンパイル
Streaming VIOSを用いる場合、Streaming VIOSのヘッダーとライブラリにリンクする必要があります。
さらに、コンパイル時に、必要なオプションを付けることで、デバッグを容易にします。
- -DDEBUG or -D_DEBUG or -DSVIOS_DEBUG_MODE=1
Streaming
VIOSをデバッグモードでコンパイルします
- -DSVIOS_DEBUG_LEVEL=n
Streaming
VIOSのデバッグレベルを設定します
有効なデバッグレベルは0〜2です。
デバッグレベル0では、最小限のデバッグメッセージを出力し、レベル2ではかなりのメッセージを出力します。
sviosの使い方
画像クラスの使い方
画像クラスへのアクセス方法は、画像の絶対座標を用いる方法と、画像の相対座標を用いる方法の2通りがあります。
- 画像の絶対座標を用いる方法 pixel(w,h) = pixel(w+1,h);
- 画像の相対座標を用いる方法 pixel() = pixel(1,0);
( pixel() は pixel(0,0) と等価である。)
画像の相対座標を用いる方法で、現在の基準点が (w,h)
のとき、この2つは同じ意味を持ちます。
画像の相対座標を用いる方法は、座標を意識しないので若干速いです。
画像の絶対座標を用いる方法の例:
まず、画像の大きさを取得し、その後は通常の2次元配列と同様に画素に対してアクセスします。
CVLLImage img;
SVIOSCreateImage( &img );
CVLLImage::iterator pixel;
img.Pixel( &pixel, 0, 0 ); //“左上”(0,0)を獲得
int iw = img.Width();
int ih = img.Height();
for( int h=1; h< ih -1 ; h++ ){
for( int w=1; w< iw -1 ; w++ ){
pixel(w,h) = ABS( pixel(w,h) - pixel(w+1,h) );
}
}
画像の相対座標を用いる方法の例:
iterator
の基準点を動かして基準点にある画素に対してアクセスします。
周辺画素へのアクセスは相対座標を用いて行います。
CVLLImage img;
SVIOSCreateImage( &img );
CVLLImage::iterator pixel;
img.Pixel( &pixel, 1, 1 );
img.Pixel( &end, 1, img.Height()-1 );
for( ; pixel != end; pixel.CRLF() ){
CVLLImage::iterator endl = pixel.EndOfLine().IncX(-1);
for( ; pixel != endl; pixel.IncX() ){
//相対座標によるアクセス
pixel() = ABS(pixel() - pixel(1,0) );
}
}
ソースファイル中の../samples/image/image/main.cpp を参照してください。
履歴変数
SVIOS
で使える変数には通常の変数に加えて過去いくつかの履歴を持つ変数
CVLLStreamBuffer
があります。
const int bufferLen = 4;
CVLLStreamBuffer< int > intStream;
intStream.Create( bufferLen );
int i=0;
while( i<10 ){
//バッファへ書き込み
intStream.PushData( i++ );
//出力
for( int j=0; j< bufferLen ; j++ )
cout << "strm[" << j << "] = " << intStream.GetData(j) << ";\t";
cout << endl;
}
//終了
intStream.Destory();
このサンプルでは、CVLLStreamBuffer に一つ値を入れ、その値を出力することを繰り返しています。
出力結果は
strm[0] = 0; strm[1] = 0; strm[2] = 0; strm[3] = 0;
strm[0] = 1; strm[1] = 0; strm[2] = 0; strm[3] = 0;
strm[0] = 2; strm[1] = 1; strm[2] = 0; strm[3] = 0;
strm[0] = 3; strm[1] = 2; strm[2] = 1; strm[3] = 0;
strm[0] = 4; strm[1] = 3; strm[2] = 2; strm[3] = 1;
strm[0] = 5; strm[1] = 4; strm[2] = 3; strm[3] = 2;
strm[0] = 6; strm[1] = 5; strm[2] = 4; strm[3] = 3;
strm[0] = 7; strm[1] = 6; strm[2] = 5; strm[3] = 4;
strm[0] = 8; strm[1] = 7; strm[2] = 6; strm[3] = 5;
strm[0] = 9; strm[1] = 8; strm[2] = 7; strm[3] = 6;
ソースファイル中の../samples/stream/sbuffer/main.cpp を参照してください。
実際のアプリケーション例
この例は、隣接する2フレーム間で差分をとり、差分の値が閾値以上となった画素を白く塗るといったものです。
ここでは、パラメータを設定し、 SetMainloop() を使い画像処理関数 mainloop() を登録し、 DoMainloop() で登録されている動画像処理関数 mainloop() を呼び出すことを繰り返すことによりストリーミング処理を行う。
void main(){
//初期化処理
SVIOS_INITPARAM param;
param.theBufferLength= 2; //ストリームバッファの数
param.theTargetFPS = 15; //目標フレームレート
param.callbackSpan = 1; //フレームレート調節間隔
param.theImageWidth = 320; param.theImageHeight = 240; //最大の画像の幅、高さ
param.theScaleType = SCALE_WH_HALF; //低解像度画像のサイズの決定方法
SVIOSInitialize( ¶m ); //Streaming VIOSの初期化
SVIOSGet()->SetMainloop( mainloop ); //ユーザーが記述した画像処理関数を登録
/******************************
画像用バッファなどの初期化 省略
******************************/
do{
/******************************
画像を取得 省略
******************************/
while(SVIOSGet()->DoMainloop() >= 0); //実行
SVIOSUninitialize(); //終了処理
}
int mainloop( void* ptr ){
//画像の実体を設定する
in0.SetData( SVIOSGet()->GetData(0) ); //現在の画像を取得
in1.SetData( SVIOSGet()->GetData(1) ); //1フレーム前の画像を取得
//iterator獲得
PIX_IT32 in0i, in1i, outi;
in0.begin( &in0i );
in1.begin( &in1i );
out.begin( &outi );
const int PIXEL_TH = 120;
int w,h;
const int iw = out.Width();
const int ih = out.Height();
for( h=0; h < ih; h++ ){
for( w=0; w < iw; w++ ){
//各画素に対する処理
int d, tmp;
tmp = 0;
for( d=0; d < depth; d++ ) //画像の差分を計算
tmp += abs( in0i(w,h)[d] - in1i(w,h)[d] );
if( tmp < PIXEL_TH ){
//画素の差が閾値以下ならば画素の値をそのままコピー
memcpy( outi(w,h), in0i(w,h), depth );
}
else{
//画素の差が閾値以上ならば白で埋める。
memset( outi(w,h), 0xFF, depth );
}
}
}
return 0;
}
ソースファイル中の
../samples/capture/caplib/xcaptest.cpp
と、
../samples/capture/sample01/mainloop.cpp
を参照してください。
戻る