フィルタインスペクタ

ここでは基本的な画像処理を施すためのフレームフィルタの使用方法について説明します。
以下の処理の手順について紹介します

  • 利用可能なフレームフィルタの列挙(エニュメレート)
  • フレームフィルタ・インスタンスの作成
  • フレームフィルタを使ってライブ画像に画像処理をかける

このサンプルは IC Imaging Controlインストールディレクトリの%TOPLEVEL%\samples\VCx\Filter Inspectorにございます。VC++2010バージョンでは%TOPLEVEL%\Samples\VC10になります。

初期化

OnInitDialogメソッドによってGrabberクラスライブラリリファレンス>クラス>Grabberが初期化されます。最も重要なことはGrabber::setOverlayBitmapPathPositionクラスライブラリリファレンス>クラス>OverlayBitmap>Grabber::setOverlayBitmapPathPosition Methodをコールしてオーバーレイを完全に無効化することです。これによってフレームフィルタのカラーフォーマットとの干渉を回避します。 その後デバイス選択ダイアログが表示されライブ画像が開始されます。

// ライブビデオ出力ウィ ンドウを静的IDC_DISPLAYに設定
m_Grabber.setHWND( GetDlgItem( IDC_DISPLAY )->GetSafeHwnd() );

// オーバーレイの無効化
m_Grabber.setOverlayBitmapPathPosition( ePP_NONE );

// ビデオキャプチャデバイス選択の為のページの表示
m_Grabber.showDevicePage( m_hWnd );

// デバイス選択されるとライブモードを開始する
if( m_Grabber.isDevValid() )
{
   Startlive();
}

利用可能なフレームフィルタの列挙(エニュメレート)

フレームフィルタの一覧を取得するために FilterLoader::getAvailableFrameFiltersクラスライブラリリファレンス>クラス>FilterLoader>FilterLoader::getAvailableFrameFilters Methodをコールします。これはFilterInfoクラスライブラリリファレンス>構造体>FlterInfo Structure構造体のvectorを返すものです。この静的メソッドのパラメータはどの種類のフィルタをロードすべきかをチェックするものです。全ての環境において動作するジェネリックフィルタ( eFC_GENERIC )と特定のプログラムでしか動作しないフィルタのどちらかを選択することになります。後者のフィルタは正しく初期化を行わないときちんと動作しない可能性があります。個々の例では、eFC_ALLを使って利用可能なフィルタを全てロードすることにします。

// 利用可能なフレームフィルタのリストを取得
std::vector<FilterInfo> filterInfos = FilterLoader::getAvailableFrameFilters( eFC_ALL );

ではリストボックスにフィルタの見つかったファイル名を入れていくようにしたいと思います。そのためにFilterFileListにフィルタのモジュールパスを入れていくのと同時に各フィルタを見てそのモジュール名をリストボックスに追加していくようにします。モジュールパスがすでにvectorの中にある場合はモジュール名は追加されません。

CListBox* pFilesList = (CListBox*)GetDlgItem( IDC_FILES );

// このループではフィルタを格納するファイルのリストを作成します。
for( size_t i = 0; i < filterInfos.size(); ++i )
{
  // 各フィルタごとに、そのモジュールがすでにリストに追加されているかどうかをチェック
   // リストにない場合は追加、すでにある場合は何もしない
  bool bFound = false;
  for( size_t j = 0; j < m_FilterFileList.size(); ++j )
  {
     if( m_FilterFileList[j] == filterInfos[i].getModulePath() )
  {
     bFound = true;
     break;
  }
  }
   if( !bFound )
  {
    // リスト内にフィルタモジュールパスを保存し、ユーザーがリストのエントリーを選択した際に
    // アクセスできるようにする
    m_FilterFileList.push_back( filterInfos[i].getModulePath() );

    // フレームフィルタ名をリストに追加する
    pFilesList->AddString( filterInfos[i].getModuleNameW().c_str() );
  }
}

ユーザーがリストボックスよりフィルタモジュール名を選択した際にコールされるイベントハンドラ内では、2つ目のリストボックスにそのモジュール内のフィルタ名が入れられることになります。

void CFilterInspectorDlg::OnLbnSelchangeFiles()
{
  CListBox* pFilesList = (CListBox*)GetDlgItem( IDC_FILES );
  CListBox* pFilterList = (CListBox*)GetDlgItem( IDC_FILTERS );

  // 利用可能なフレームフィルタのリストの取得
  std::vector<FilterInfo> filterInfos = FilterLoader::getAvailableFrameFilters( eFC_ALL );

  // 選択されているフィルタファイルのインデックスの取得
  int sel = pFilesList->GetCurSel();
  if( sel != -1 )
  {
    // フィルタファイルが選択されている場合、フィルタリストにそのファイルのフィルタを入れる

    // 最初にリストのクリアを行う
    pFilterList->ResetContent();           

    // 選択されたファイルのフィルタを全てリストに追加
    int n = 0;
    for( int i = 0; i < int(filterInfos.size()); ++i )
    {
      FilterInfo& fi = filterInfos[i];               

      // フィルタのモジュールが選択されたファイルに対応しているかをチェック
      if( m_FilterFileList[sel] == fi.getModulePath() )
      {
        pFilterList->AddString( fi.getFilterNameW().c_str() );                   

         // リスト項目の項目データ内にある利用可能なフィルタのリスト内に
        // フィルタのインデックスを保存
        pFilterList->SetItemData( n++, i );
      }
    }
  }
}

ループ内で全てのフィルタのフィルタモジュールパスは選択されたファイルのパスと比較されます。フィルタが選択済みファイルより来ている場合にはその名前がフィルタリストボックスに追加されます。FilterLoader::getAvailableFrameFiltersクラスライブラリリファレンス>クラス>FilterLoader>FilterLoader::getAvailableFrameFilters Methodより取得されるオリジナルのフィルタリスト内のフィルタインデックスはCListBox::SetItemDataへのコールするによってリストボックス項目データに格納されます。これによってユーザーが項目をクリックした際にフィルタを見つけることができるようになります。

フレームフィルタのインスタンスを作成する

ユーザーがリストからフィルタを選択する際、選択された項目のデータはCListBox::GetItemDataを使って読み取られます。さきほど項目データ内の利用可能なフィルタのリストにあるインデックスをソートしたので、これをリスト内のFilterInfoクラスライブラリリファレンス>構造体>FlterInfo Structureを選択するのに使用することができます。

// さきほど格納したフィルタのインデックスを読み込む
int filterIndex = (int)pFilterList->GetItemData( sel );

// フィルタはライブモード停止中のみ設定可能
bool bIsLive = m_Grabber.isLive(); Stoplive();

// 新しいフィルタインスタンスの作成
m_pFilter = FilterLoader::createFilter( filterInfos[filterIndex] );

フレームフィルタのインスタンスはFilterLoader::createFilterクラスライブラリリファレンス>クラス>FilterLoader>FilterLoader::createFilter MethodをコールすることでFilterInfoクラスライブラリリファレンス>構造体>FlterInfo Structure構造体をパラメータとして作成されます。

フレームフィルタを設定する

フレームフィルタを有効にするにはgrabberオブジェクトで登録する必要があります。Grabber::setDeviceFrameFiltersクラスライブラリリファレンス>クラス>Grabber>Grabber::setDeviceFrameFilters Methodを使ってフレームフィルタを設定しビデオキャプチャデバイスから来る画像データを変換します。

// フィルタをデバイスフレームフィルタとして設定
m_Grabber.setDeviceFrameFilters( m_pFilter.get() );  

// 可能である場合、ライブモードを再開する
if( m_Grabber.isDevValid() && bIsLive )
{
  Startlive();
}

// フィルタが標準ダイアログを持っている場合"Dialog..." ボタンを有効にする 
GetDlgItem( IDC_DIALOG )->EnableWindow( m_pFilter->hasDialog() );

フレームフィルタを設定するにはライブモードを停止する必要があります。

フィルタインスタンスへのポインタをハンドルする

フレームフィルタインスタンスへのポインタはダイアログクラスのメンバ変数に格納されます。そうすることでフィルタインスタンスはイベントハンドラの実行後に存在することになります。フレームフィルタインスタンスへのポインタはsmart_comクラスライブラリリファレンス>クラス>smart_comでローカルポインタ変数のスコープ(有効範囲)でなくなった時に破壊されます。

ポイントされていたフィルタインスタンスが破壊されてしまうため、新しいフィルタインスタンスがメンバ変数m_pFilterに割り当てられるまえにライブモードを停止する必要があります。