ORiN プログラミング入門
USB カメラで作る遠隔監視システム
執筆者:小林 佑介 (こばやし・ゆうすけ)
池添 明宏 (いけぞえ・あきひろ)
飯田 学
(いいだ・まなぶ)
所属 :株式会社セック 開発本部 宇宙先端システムビジネスフィールド
ORiN でプログラムを組みたいと思っても,FA 機器やロボッ
トのような実機を持っていない方も多いのではないでしょうか.
しかし,ORiN は,マウスや USB カメラなどの身近なハードウ
とができます.
今回作成する遠隔監視システムには,以下のような機能を持
たせることにします.
ェア,さらには,データベースやファイル,ソケット通信など
・
カメラの画像を表示する
のソフトウェア資源に対しても有効なものです.例えば,マウ
・
カメラ画像に変化があった場合にイベントを通知する
スと ORiN を使用して,図 1 のように,マウスの現在位置情報
・
画像変化の検出感度を設定する
やボタンの押下状態を監視するような簡単なアプリケーション
を作成することも可能です1.
●システム構成
遠隔監視システムの構成を図 2 および図 3 に示します.
本章では,ORiN のプログラミング入門として,身近なハー
ドウェアデバイスを対象とした簡単な CAO プロバイダとクラ
イアントアプリケーションの作成方法を解説します.
図 2 遠隔監視システムの構成(イメージ)
図 1 マウスアプリケーションの構成
1 遠隔監視システムの製作
今回作成するのは,市販の USB カメラを利用した簡単な「遠
隔監視システム」です.近年,セキュリティに関する世間の感
心は高まっており,ホームセキュリティを各家庭に設置するこ
とも一般的になってきました.USB カメラを使用した専用のソ
フトウェアもいくつか出回っていますが,ORiN を使用するこ
とで,自分好みの機能を持たせたシステムを簡単に作成するこ
1
紙面の都合上,本アプリケーションの解説は割愛します.ソース
コード一式はWebサイトからダウンロードすることができますの
で,興味のある方はお試し下さい.
図 3 遠隔監視システムの構成
ロバイダウィザードを利用します.
ORiN では,ロボット向けのインタフェースと,アプリケー
ション向けのインタフェースが用意されています.ロボット向
(3)
メソッドを実装します.
けのインタフェースに準じたソフトウェアを「CAO プロバイ
ダ」
,
アプリケーション向けのインタフェースに準じたソフトウ
生成された CAO プロバイダのテンプレートに,必要な
(4)
作成した CAO プロバイダの動作確認をおこない,正常
に動作しなかった場合はデバッグ作業を実施します3.
ェアを「クライアントアプリケーション」と呼びます.
本システムでは,USB カメラから画像を取得するなどの機能
以降,今回作成する CAO プロバイダを「USB カメラプロバ
を持つ CAO プロバイダと,取得した画像の表示などをおこな
イダ」と呼ぶこととし,上記の手順に従って,USB カメラプロ
うクライアントアプリケーションを作成します.
バイダの具体的な実装手順について,解説していきます4.
●開発の流れ
以降,この遠隔監視システムを例に,ORiN アプリケーショ
ンの開発について解説していきます.はじめに,CAO プロバイ
ダについて,USB カメラからの画像の取得,カメラ画像の変化
のチェックなど,
ハードウェア側の処理を実装します.
続いて,
クライアントアプリケーションとして,取得した画像の表示,
画像変化のイベント通知などの処理を実装します.
なお,今回は表 1 に示す環境で,開発および動作確認をおこ
ないました2.
表 1 開発環境
PC
CPU:Pentium IV 2.8GHz
メモリ:512MByte
OS
図 4 USB カメラプロバイダ構成
Windows XP SP2 Professional
利用ソフトウェア
ORiN2 SDK 評価版
DirectX 9.0 SDK
USB カメラ
●USBカメラプロバイダの設計
まずは,USB カメラプロバイダの設計をおこないます.遠隔
Microsoft Visual C++ 6.0
監視システムを構築するために,USB カメラプロバイダには以
Microsoft Visual Studio .NET 2003
下の機能を持たせることにします.
USB-CAM30MS (アイ・オー・デー
タ機器)
・
・
一定周期で USB カメラから画像を取得する
クライアントからの要求に従い,USB カメラの画像を
クライアントに渡す
・
2 USBカメラプロバイダの作成
それではまず,USB カメラを利用するための CAO プロバイ
ダを作成しましょう.CAO プロバイダの一般的な開発の流れは
以下のようになります.
(1)
CAO プロバイダの設計をおこないます.CAO プロバイ
ダで扱うターゲット(デバイスなど)にあわせて,実装する
クラスとメソッドを決定します.
(2)
カメラ画像に変化が生じた場合,それを検知し,クライ
アントに通知する
・
変化を検知する際の感度を設定する
USB カメラプロバイダの構成は図 4 のようになります.図の
ように,自動生成される CAO プロバイダのテンプレートの中
に,必要な機能を実装していくことになります.また,USB カ
メラとのアクセスには,DirectX に含まれる Windows 用マルチ
メディア拡張 API「DirectShow」を利用します.
CAO プロバイダの設計を決定したら,次に CAO プロ
バイダのテンプレートを生成します.これには,CAO プ
USBカメラは,Windows Driver Model(WDM)というドライバ規
格に対応している必要があります.お持ちのUSBカメラがWDM対
応であることをご確認ください.また,USBカメラから画像を取得
するためには,DirectX SDKが必要となります.事前にMicrosoft
社のサイト(http://www.microsoft.com/downloads/)からダウンロー
ドし,インストールをおこなってください.
2
3 CAOプロバイダのデバッグ方法については,ORiN2 SDKに収録
の「CAOプロバイダ作成ガイド」を参照して下さい.
4 CAOプロバイダの作成にあたっては,HRESULTやBSTR,
VARIANT,SAFEARRAYなど,COM(Component Object Model)
特有のデータ型を使用します.詳細はORiN2 SDKに収録の
「ORiN2プログラミングガイド」で解説しています.合わせてご覧
下さい.
表2 CAOプロバイダのクラス機能概要
クラス名
説明
CaoProvController
コントローラクラス.コントローラのリソース全般に関わる機能を提供します.
CaoProvVariable
変数クラス.変数リソースに関わる機能を提供します.
CaoProvRobot
ロボットクラス.ロボットリソースに関わる機能を提供します.
CaoProvFile
ファイルクラス.ファイル,フォルダリソースに関わる機能を提供します.
CaoProvTask
タスククラス.タスクリソースに関わる機能を提供します.
CaoProvCommand
コマンドクラス.コマンドリソースに関わる機能を提供します.
CaoProvExtension
拡張クラス.拡張ボードリソースに関わる機能を提供します.
CaoProvMessage
メッセージクラス.メッセージリソースに関わる機能を提供します.
表3 USBカメラプロバイダ仕様
クラス名
CaoProvController
メソッド
説明
FinalInitialize
カメラプロバイダの初期化処理をおこないます.
FinalConnect
USB カメラへの接続処理をおこないます.
FinalDisconnect
USB カメラリソースの開放処理をおこないます.
OnTimer
一定周期で画像の変化を監視します.
GetCameraManager カメラ管理オブジェクトへのポインタを取得します.
CaoProvVariable
CaoProvFile
FinalInitialize
CaoProvVariable の初期化をおこないます.
FinalGetValue
画像の変化の検出感度を取得します.
FinalPutValue
画像の変化の検出感度を設定します.
FinalInitialize
CaoProvFile の初期化をおこないます.
FinalGetValue
カメラから取得した画像データを取得します.
表4 CCameraManagerクラスの公開メソッド
メソッド名
説明
CCameraManager();
コンストラクタです.
virtual ~CCameraManager();
デストラクタです.
HRESULT Initialize ();
DirectShow の初期化をおこないます.
void Finalize();
DirectShow の終了処理をおこないます.
HRESULT Capture();
USB カメラから画像を取得し,カメラ管理クラスが保持しているメモリ上の画像デー
タを更新します.
BOOL IsDiffDetected();
現在の画像と 1 サンプリング前の画像を比較し,違いが検出された場合は True を返し
ます.画像を比較する際の閾値が小さい場合は,画像のわずかな変化でも検出し,True
を返します.逆に,閾値を大きくすると,画像が大きく変化しないと True を返さなく
なります.
BYTE *GetImage(long *lSize);
キャプチャした画像のバイナリデータを取得するメソッドです.引数として long 型の
long GetThreshold();
画像を比較する際の閾値を取得します.
ポインタを渡すことで,画像のサイズを取得することができます.
void SetThreshold( long threshold ); 画像を比較する際の閾値を設定します.
上にあげた機能を実現するように,USB カメラプロバイダに
DLL Name は,生成される DLL ファイルの名前になります.
実装するクラスとメソッドを決定します.CAO プロバイダは,
Vender Name と Module Name は,CAO プロバイダを利用すると
表 2 に示すような機能を持つクラスから構成されています.こ
きの ID となります.また,MFC を利用する場合は,Use MFC
の中でも最も重要なクラスは CaoProvController であり,必ず実
にチェックを入れてください.なお,DLL Name と Vender Name
装する必要があります.その他のクラスに関しては,必要な機
の入力は必須となります.Module Name は,省略した場合,DLL
能に対応するクラスだけを実装すれば OK です.また,各クラ
Name と同じ名前になります.
スには複数の公開メソッドが用意されていますが,これらをす
ここでは,カメラプロバイダに関する情報として,以下のと
べて実装する必要はなく,必要なメソッドのみを実装します5.
おり入力します.
今回は,USB カメラプロバイダを表 3 のように実装すること
・
DLL Name
:Camera
とします.また,USB カメラプロバイダのクラス構成を図 5 に
・
Vender Name
:Samples
示します.CAO プロバイダの標準クラスとは別に,USB カメ
・
Module Name
:Camera
ラを管理するクラスとして,CCameraManager クラスを用意し
・
Use MFC
:チェックなし
ます.
「Next >」ボタンを押下すると,確認ダイアログが表示され
ますので,間違いがなければ「はい」を選択してください.
これで,CAO プロバイダのテンプレートが生成されます.出
力先として選択したフォルダに,図 8 に示すようなファイルが
生成されていることを確認してください.
図5 USBカメラプロバイダのクラス構成
●テンプレートの生成
プロバイダの設計が決まったら,USB カメラプロバイダのテ
図 6 CAO プロバイダ作成フォルダ選択画面
ンプレートを作成します.ORiN2 SDK には,CAO プロバイダ
ウィザードという,CAO プロバイダの開発を支援するツールが
用意されています.このツールを利用することで,CAO プロバ
イダを開発するための Visual C++6.0 のプロジェクトと,テンプ
レートを簡単に作成することができます.
CAO プロバイダウィザードの使い方を説明します.スタート
メニューから「ORiN 2」→「CAO Provider」→「CaoProvWiz」
を選択して,CAO プロバイダウィザードを起動してください.
最初に,図 6 に示す画面が表示されますので,CAO プロバイ
ダを作成するフォルダの場所を選択してください6.
「Next >」ボタンを押すと,図 7 に示す画面が表示されます.
本画面には,作成する CAO プロバイダの情報を入力します.
5
クラスごとに,必ず実装しなければならないメソッドもあります
ので,注意して下さい.詳細は,ORiN2 SDKに附属の「CAOプロ
バイダ作成ガイド」を参照して下さい.
6 プロバイダの作成先のフォルダには,図6のように,終端に「Src」
という名のサブフォルダを含めることを推奨します.
図 7 プロバイダ情報入力画面
・ 「リンクタブ」の「オブジェクト/ライブラリモジュー
ル」に以下のライブラリを追加する.
strmiids.lib
●カメラ管理クラスCCameraManagerの実装
CAO プロバイダの各クラスの実装をおこなう前に,USB カ
メラの管理クラス CCameraManager を実装します.
カメラ管理クラスは,
DirectShow 経由で USB カメラにアクセ
スし,画像データを取得します7.また,前回撮影画像との比較
や,画像比較のための閾値の更新などをおこないます.
カメラ管理クラスの公開メソッドを表 4 に示します.また,
ソースコードをリスト 1,リスト 2 に示します,この 2 つのフ
ァイルを,
先ほどの USB カメラプロバイダのプロジェクトに追
加して下さい.
図 8 CAO プロバイダウィザードで生成されるファイル一覧
●環境設定
Visual C++ 6.0 で CAO プロバイダの開発をおこなうためには,
いくつかの環境設定が必要です.まずは,生成されたファイル
の中から,プロジェクトワークスペースファイル(CaoProv.dsw)
を選択し,Visual C++6.0 を起動して,以下の設定をおこなって
ください.
・ メニューバーの「ツール」→「オプション」でオプシ
ョンダイアログを開く.
・ ディレクトリタブを選択する.
・ 表示するディレクトリから「インクルードファイル」
を選択し,以下を追加する.
<ORiN インストールディレクトリ>¥CAO¥Include
・ 表示するディレクトリから「ライブラリファイル」を
選択し,以下を追加する.
<ORiN インストールディレクトリ>¥CAO¥Lib
同様に,DirectShow を使用するために,以下の設定をおこな
います.
・ メニューバーの「ツール」→「オプション」でオプシ
ョンダイアログを開く.
・ ディレクトリタブを選択する.
・ 表示するディレクトリから「インクルードファイル」
を選択し,以下を追加する.
<DirectX SDK インストールディレクトリ>¥Include
・ 表示するディレクトリから「ライブラリファイル」を
選択し,以下を追加する.
リスト1
CameraManager.h
#ifndef __CAMERAMANAGER_H_
#define __CAMERAMANAGER_H_
#include
#include
#include
#include
#include
"stdafx.h"
<dshow.h>
<qedit.h>
<conio.h>
<math.h>
/** USB カメラを管理するクラス */
class CCameraManager {
public:
CCameraManager();
virtual CCameraManager();
HRESULT Initialize();
void Finalize();
HRESULT Capture();
BOOL IsDiffDetected();
BYTE *GetImage(long *lSize);
long GetThreshold();
void SetThreshold( long threshold );
private:
IPin* GetPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir);
private:
IGraphBuilder *m_pGraph;
IMediaControl *m_pMC;
IMediaEvent *m_pEV;
ICaptureGraphBuilder2 *m_pCapture;
IBaseFilter *m_pF;
IBaseFilter *m_pbf;
IBaseFilter *m_pNull;
ISampleGrabber *m_pGrab;
BYTE *m_pBuffer_Cur;
BYTE *m_pBuffer_Pre;
BYTE *m_pImage;
long m_imageSize;
BOOL m_bInitialize;
long m_threshold;
HANDLE m_hMutex;
};
//
//
//
//
//
//
//
//
//
//
フィルタグラフマネージャ
メディアコントロール
メディアイベント
キャプチャグラフ
グラバフィルタ
デバイスフィルタ
Null レンダラフィルタ
サンプルグラバ
画像格納バッファ(カレント)
画像格納バッファ(前)
// 画像変化の閾値
#endif // __CAMERAMANAGER_H_
<DirectX SDK インストールディレクトリ>¥Lib
・ メニューバーから「プロジェクト」→「設定」でプロ
ジェクトの設定ダイアログを開く.
リスト2
CameraManager.cpp
・ 設定の対象を「すべての構成」にし,画面左のツリー
表示から「CAOPROV」を選択する.
7紙面の都合上,DirectXやDirectShowに関する説明は割愛します。
詳細は,DirectXのマニュアルを参照してください.
#include "stdafx.h"
#include "CameraManager.h"
return hr;
}
/** コンストラクタ */
CCameraManager::CCameraManager(){
m_pF = NULL;
m_pGrab = NULL;
m_pbf = NULL;
m_pMC = NULL;
m_pEV = NULL;
m_pGraph = NULL;
m_pCapture = NULL;
m_pBuffer_Cur = NULL;
m_pBuffer_Pre = NULL;
m_pImage = NULL;
m_bInitialize = FALSE;
m_threshold = 10;
// (4) サンプルグラバ作成
hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (LPVOID *)&m_pF);
if (FAILED(hr)) {
return hr;
}
hr = m_pF->QueryInterface(IID_ISampleGrabber, (void **)&m_pGrab);
if (FAILED(hr)) {
return hr;
}
}
/** デストラクタ */
CCameraManager:: CCameraManager(){
}
/** 初期化 */
HRESULT CCameraManager::Initialize(){
HRESULT hr;
AM_MEDIA_TYPE amt; // メディアタイプ
m_hMutex = CreateMutex(NULL,FALSE,NULL);
//ミューテックス生成
// COM の初期化
CoInitialize(NULL);
// (1) フィルタグラフマネージャ作成
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,
IID_IGraphBuilder, (void **)&m_pGraph);
if (FAILED(hr)) {
return hr;
}
// (2) デバイスフィルタの準備
// システムデバイス列挙子を作成
ICreateDevEnum *pDevEnum =NULL;
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
IID_ICreateDevEnum, (void **)&pDevEnum);
if (FAILED(hr)) {
return hr;
}
// ビデオキャプチャデバイス列挙子を作成
IEnumMoniker *pClassEnum = NULL;
pDevEnum->CreateClassEnumerator
(CLSID_VideoInputDeviceCategory, &pClassEnum, 0);
if (pClassEnum == NULL){
// ビデオキャプチャは存在しない
pDevEnum->Release();
return S_FALSE;
}
// 最初に見つかったビデオキャプチャデバイスのオブジェクトの
// インタフェースを得る
IMoniker *pMoniker = NULL;
ULONG cFetched;
if (pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK) {
pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void **)&m_pbf);
pMoniker->Release();
}
pClassEnum->Release();
pDevEnum->Release();
// デバイスフィルタをフィルタグラフに追加
hr = m_pGraph->AddFilter(m_pbf, L"Video Capture");
if (FAILED(hr)) {
return hr;
}
// (3) キャプチャグラフビルダ作成
CoCreateInstance(CLSID_CaptureGraphBuilder2 , NULL, CLSCTX_INPROC,
IID_ICaptureGraphBuilder2, (void **)&m_pCapture);
// フィルタグラフをキャプチャグラフに組み込む
hr = m_pCapture->SetFiltergraph(m_pGraph);
if (FAILED(hr)) {
// (5) メディアタイプの設定
// グラバフィルタの挿入場所の特定のための設定
ZeroMemory(&amt, sizeof(AM_MEDIA_TYPE));
// Sample Grabber の入力ピン(Capture Device の出力ピン)は UYVY
amt.majortype = MEDIATYPE_Video;
amt.subtype
= MEDIASUBTYPE_RGB24;
amt.formattype = FORMAT_VideoInfo;
hr = m_pGrab->SetMediaType(&amt);
if (FAILED(hr)) {
return hr;
}
// グラバフィルタをフィルタグラフに追加
hr = m_pGraph->AddFilter(m_pF, L"Grabber");
if (FAILED(hr)) {
return hr;
}
// (6) Null Renderer フィルタの作成
hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (void **)&m_pNull);
if (FAILED(hr)) {
return hr;
}
hr = m_pGraph->AddFilter(m_pNull, L"Renderer");
if (FAILED(hr)) {
return hr;
}
// (7) フィルタの接続
IPin *pSrcOut = GetPin(m_pbf, PINDIR_OUTPUT);
IPin *pSGrabIN = GetPin(m_pF, PINDIR_INPUT);
IPin *pSGrabOut = GetPin(m_pF, PINDIR_OUTPUT);
IPin *pNullIN = GetPin(m_pNull, PINDIR_INPUT);
// ソースフィルタ←→サンプルグラバフィルタの接続
hr = m_pGraph->Connect(pSrcOut, pSGrabIN);
if (FAILED(hr)) {
return hr;
}
// サンプルグラバフィルタ←→Null レンダラの接続
hr = m_pGraph->Connect(pSGrabOut, pNullIN);
if (FAILED(hr)) {
return hr;
}
pSrcOut->Release();
pSGrabIN->Release();
pSGrabOut->Release();
pNullIN->Release();
// (8) グラバのモードを適切に設定
hr = m_pGrab->SetBufferSamples(TRUE);
if (FAILED(hr)) {
return hr;
}
hr = m_pGrab->SetOneShot(FALSE);
if (FAILED(hr)) {
return hr;
}
// (9) メディアコントロール作成
hr = m_pGraph->QueryInterface(IID_IMediaControl, (LPVOID *)&m_pMC);
if (FAILED(hr)) {
return hr;
}
hr = m_pGraph->QueryInterface(IID_IMediaEvent, (LPVOID *)&m_pEV);
if (FAILED(hr)) {
return hr;
}
// (10) 画像格納領域確保
AM_MEDIA_TYPE mt;
// メディアタイプ取得
hr = m_pGrab->GetConnectedMediaType(&mt);
if (FAILED(hr))
{
return hr;
}
m_imageSize = mt.lSampleSize;
WaitForSingleObject(m_hMutex,INFINITE);
m_pBuffer_Cur = (BYTE *)malloc(m_imageSize);
ReleaseMutex(m_hMutex);
if (m_pBuffer_Cur==NULL) {
return S_FALSE;
}
m_pBuffer_Pre = (BYTE *)malloc(m_imageSize);
if (m_pBuffer_Pre==NULL) {
return S_FALSE;
}
m_pImage = (BYTE *)malloc(
m_imageSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER));
if (m_pImage==NULL) {
return S_FALSE;
}
// ファイルヘッダ部分を書き込む
BITMAPFILEHEADER bfh;
memset(&bfh, 0, sizeof(bfh));
bfh.bfType = 'MB';
bfh.bfSize = sizeof(bfh) + m_imageSize + sizeof(BITMAPINFOHEADER);
bfh.bfOffBits = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER);
VIDEOINFOHEADER *vih = (VIDEOINFOHEADER*)mt.pbFormat;
// ビットマップフォーマットを書き込む
BITMAPINFOHEADER bih;
memset(&bih, 0, sizeof(bih));
bih.biSize = sizeof(bih);
bih.biWidth = vih->bmiHeader.biWidth;
bih.biHeight = vih->bmiHeader.biHeight;
bih.biPlanes = 1;
bih.biBitCount = 24;
memcpy(m_pImage, &bfh, sizeof(bfh));
memcpy(m_pImage + sizeof(bfh), &bih, sizeof(bih) );
hr = m_pMC->Run();
if (FAILED(hr)) {
return hr;
}
m_bInitialize = TRUE;
// (11) スナップショット取得
Sleep(1000);
Capture();
return S_OK;
}
/** 終了処理 */
void CCameraManager::Finalize(){
if (m_pF != NULL)
m_pF->Release();
if (m_pGrab != NULL)
m_pGrab->Release();
if (m_pbf != NULL)
m_pbf->Release();
if (m_pMC != NULL)
m_pMC->Release();
if (m_pEV != NULL)
m_pEV->Release();
if (m_pGraph != NULL)
m_pGraph->Release();
if (m_pCapture != NULL)
m_pCapture->Release();
if (m_pNull != NULL)
m_pNull->Release();
if (m_pBuffer_Cur != NULL)
free(m_pBuffer_Cur);
if (m_pBuffer_Pre != NULL)
free(m_pBuffer_Pre);
if (m_pImage != NULL)
free(m_pImage);
// COM のリリース
CoUninitialize();
CloseHandle(m_hMutex);
}
/** キャプチャ */
HRESULT CCameraManager::Capture(){
HRESULT hr;
if (!m_bInitialize) {
return S_FALSE;
}
// 画像格納バッファの退避
WaitForSingleObject(m_hMutex,INFINITE);
CopyMemory(m_pBuffer_Pre, m_pBuffer_Cur ,m_imageSize);
// バッファサイズ取得
long work;
hr = m_pGrab->GetCurrentBuffer(&work, NULL);
if (FAILED(hr)) {
return hr;
}
// バッファ取得
hr = m_pGrab->GetCurrentBuffer(&work, (long *)m_pBuffer_Cur);
ReleaseMutex(m_hMutex);
if (FAILED(hr)) {
return hr;
}
return S_OK;
}
/** ピン取得 */
IPin* CCameraManager::GetPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir){
BOOL
bFound = FALSE;
IEnumPins *pEnum;
IPin
*pPin;
HRESULT
hr;
hr = pFilter->EnumPins(&pEnum);
if (FAILED(hr)) {
return (IPin *)NULL;
}
while(pEnum->Next(1, &pPin, 0) == S_OK) {
PIN_DIRECTION PinDirThis;
pPin->QueryDirection(&PinDirThis); // 引数で指定した方向のピンなら break
if (PinDir == PinDirThis) {
bFound = TRUE;
break;
}
pPin->Release();
}
pEnum->Release();
return (bFound ? pPin : (IPin *)NULL);
// 初期化が終了するまで 1 秒待つ
}
/** 画像差分検出 */
BOOL CCameraManager::IsDiffDetected(){
double s = 0.0;
WaitForSingleObject(m_hMutex,INFINITE);
for (int i = 0; i < m_imageSize; i++) {
// 差分をとる
s = s + fabs(m_pBuffer_Cur[i] - m_pBuffer_Pre[i]);
}
ReleaseMutex(m_hMutex);
// s / サイズ > m_threshold(閾値) の場合はアラーム
return ( (s / m_imageSize) > m_threshold ? TRUE : FALSE );
}
/** 画像取得 */
BYTE *CCameraManager::GetImage(long *lSize ){
WaitForSingleObject(m_hMutex,INFINITE);
*lSize = m_imageSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
memcpy(m_pImage + sizeof(BITMAPFILEHEADER) +
sizeof(BITMAPINFOHEADER), m_pBuffer_Cur, sizeof(BYTE) * m_imageSize);
ReleaseMutex(m_hMutex);
return m_pImage;
処理の成功を意味する「S_OK」を戻り値とします.
}
FinalConnect メソッド
次に FinalConnect メソッドを実装します.このメソッドは,
/** 閾値取得 */
long CCameraManager::GetThreshold(){
return m_threshold;
}
クライアントアプリケーションから CAO プロバイダに接続し
たときに呼び出されます.コメントアウトを解除し,リスト 5
/** 閾値設定 */
void CCameraManager::SetThreshold( long threshold ){
m_threshold = threshold;
}
の②のように実装をおこなってください.ここでは,カメラ管
理クラスのインスタンスの生成をおこなった後,Initialize メソ
ッドを呼び出し,DirectShow の初期化をおこないます.
FinalDisconnect メソッド
FinalDisconnect メソッドは,クライアントアプリケーション
●StdAfx.h の編集
続いて,プリコンパイル済みヘッダファイル(StdAfx.h)の編集
が,CAO プロバイダとの接続を切断したときに呼び出されます.
をおこないます.本ファイル中に「各社追加部分はこれ以下に
FinalDisconncet メソッドをリスト 5 の③のように実装してくだ
記述する」とありますので,まずは,リスト 3 の①を追加して
さい.ここでは,カメラ管理オブジェクトの Finalize メソッド
下さい.①は,CameraManager.h ファイルをインクルードして
をコールし,DirectShow の終了処理をおこないます.
います.これで,カメラプロバイダから CCameraManager クラ
スが利用できるようになります.次に,リスト 3 の②に示すよ
うに,
CAOP_TIMER_INTERVAL マクロの定義を 0 から 10 に変
更してください.本マクロの詳細については後述します.
呼び出されるメソッドです.
今回の遠隔監視システムでは,
USB
カメラから定期的に画像を取得するために利用します.本メソ
ッ ド の 呼 び 出 し 周 期 は , StdAfx.h に 定 義 さ れ て い る
リスト3 StdAfx.h
// ========== 各社追加部分はこれ以下に記述する.==========
#include "CameraManager.h"
#define CAOP_TIMER_INTERVAL 10
OnTimer メソッド
OnTimer メソッドは,CAO プロバイダの実行中に一定周期で
CAOP_TIMER_INTERVAL マクロにミリ秒単位で設定します.
…①
…②
先ほど,
CAOP_TIMER_INTERVAL マクロの値を 10 としました
ので,OnTimer メソッドは 10 ミリ秒周期で呼び出されます.な
お,値が 0 のときは,OnTimer メソッドは呼び出されません.
OnTimer メソッドは,リスト 5 の④に示すように実装します.
●CaoProvControllerの実装
それではいよいよ,CAO プロバイダの各クラスを実装してい
このメソッドでは,まず,カメラ管理オブジェクトの Capture
きましょう.最初は,CaoProvController クラスの実装をおこな
IsDiffDetected メソッドで,画像に変化があったかどうかの判別
います.CaoProvController クラスは,CAO プロバイダのメイン
をおこないます.ここで,画像に変化が生じた場合は,メッセ
メソッドを呼び出し,USB カメラから画像を取得します.次に,
となるクラスです.USB カメラプロバイダでは,カメラ管理ク
ージを生成し,CaoEngine へとメッセージを送信します.メッ
ラスの初期化処理や終了処理などを実装します.
セージを受け取った CaoEngine は,クライアントアプリケーシ
CaoProvController.h の編集.
まずは,CaoProvController.h ファイルを開いて,実装するメソ
ッドのコメントアウトを解除します.リスト 4 の①,②のよう
ョンにイベントを通知します.
GetCameraManager
最後に,CaoProvFile クラスや CaoProvVariable クラスから,
に , FinalInitialize メ ソ ッ ド , FinalConnect メ ソ ッ ド ,
カメラ管理オブジェクトにアクセスできるように,
FinalDisconncet メソッドのコメントアウトを解除してください. GetCameraManagerメソッドをリスト5の⑤のように実装します.
次に,リスト 4 の④で,カメラ管理オブジェクトへのポイン
このメソッドでは,カメラ管理オブジェクトへのポインタを返
タとして,m_cameraManager を宣言します.カメラ管理クラス
り値とします.
は,CaoProvController クラス以外でも使用しますので,カメラ
管理オブジェクトのポインタを取得するためのメソッドとして,
リスト 4 の③に示す GetCameraManager メソッドを宣言します.
FinalInitialize メソッド
続いて,各メソッドの実装に移ります.CaoProvController.cpp
を開いてください.
まずは,FinalInitialize メソッド実装です.このメソッドは,
CAO プロバイダが生成されるときに呼び出されます.ソース
リスト4 CaoProvController.h
∼中略∼
protected:
HRESULT FinalInitialize();
// void FinalTerminate();
HRESULT FinalConnect();
HRESULT FinalDisconnect();
ファイル中のコメントアウトを解除し,
リスト 5 の①のように
∼中略∼
実装します.
ここでは,
特別な初期化処理はおこなわず,
単に,
// ========== 各社追加関数はこれ以下に記述する.==========
…①
…②
CCameraManager *GetCameraManager();
private:
// ========== 各社追加関数はこれ以下に記述する.==========
CCameraManager *m_cameraManager;
…③
return;
}
…④
∼中略∼
∼中略∼
// ========== 各社追加関数はこれ以下に記述する.==========
CCameraManager *CCaoProvController::GetCameraManager(){
return m_cameraManager;
}
リスト5 CaoProvController.cpp
…⑤
∼中略∼
HRESULT CCaoProvController::FinalInitialize()
{
return S_OK;
}
●CaoProvVariableの実装
続いて,CaoProvVariable クラスの実装をおこないます.
…①
変数として扱うための機能を提供するクラスです.ここでは,
∼中略∼
HRESULT CCaoProvController::FinalConnect()
{
// USB カメラから画像を取得するための初期化処理をおこなう.
HRESULT hr;
m_cameraManager = new CCameraManager();
hr = m_cameraManager->Initialize();
return hr;
}
画像の変化を検出するための感度を設定する機能を実装します.
CaoProvVariable.h の編集
まず,CaoProvVariable.h を開き,リスト 6 に示すように,
…②
変数として,カメラ管理オブジェクトへのポインタ
m_cameraManager を宣言します.
FinalInitialize
次に,FinalInitialize メソッドの実装をおこないます.
…③
リスト 7 のように実装してください.このメソッドは,引数と
して,親オブジェクトへのポインタを受け取ります.ここで,
void CCaoProvController::OnTimer()
{
HRESULT hr;
親オブジェクトの判定をおこない,親が CaoProvController だっ
…④
// 画像の変化を検出
if (m_cameraManager->IsDiffDetected()) {
SYSTEMTIME st;
char szData[32];
VARIANT vntData;
VARIANT vntNowTime;
CComPtr<CCaoProvMessage> pMess;
// メッセージを設定
wsprintf(szData, "画像が変化しました¥n");
CComBSTR bstrMessage(szData);
vntData.vt = VT_BSTR;
vntData.bstrVal = bstrMessage;
// 現在時刻を設定
GetLocalTime(&st);
vntNowTime.vt = VT_DATE;
double dDate = 0.0;
// SYSTEMTIME から double に変換する
SystemTimeToVariantTime(&st, &dDate);
vntNowTime.date = dDate;
// メッセージを生成/送信
hr = CreateMessage(&pMess, 0, &vntData, &vntNowTime);
if (SUCCEEDED(hr)) {
SendMessage(pMess, CAO_MSG_NORMAL │ CAO_MSG_OUTPUT_LOG);
}
}
このメソッドは,クライアントアプリケーション側で
CaoVariable を取得した際に呼び出されます.このメソッドを,
∼中略∼
// キャプチャ
hr = m_cameraManager->Capture();
if (FAILED(hr)) {
return;
}
FinalInitialize メソッド,FinalGetValue メソッド,FinalPutValue
メソッドのコメントアウトを解除してください.また,メンバ
∼中略∼
HRESULT CCaoProvController::FinalDisconnect()
{
// USB カメラの終了処理をおこなう.
m_cameraManager->Finalize();
return S_OK;
}
CaoProvVariable クラスは,CAO プロバイダ側で管理する情報を,
た場合は,①に示すように GetCameraManager メソッドを呼び
出し,カメラ管理オブジェクトへのポインタを取得します.
FinalGetValue
続いて,FinalGetValue メソッドの実装をおこないます.この
メソッドは,変数を取得する際に呼び出されるメソッドです.
ここでは,リスト 7 の③のように,カメラ管理オブジェクト
から,画像の変化を検出するための感度を取得し,VARIANT
型の引数として渡された pVal に値をセットします.
FinalPutValue
続いて,FinalPutValue メソッドの実装をおこないます.この
メソッドでは,クライアントアプリケーションから渡された,
画像の変化を検出するための感度の値を,カメラ管理オブジェ
クトに設定する機能を実装します.
ここでは,リスト 7 の④に示すように,クライアントアプリ
ケーションから受け取ったデータが,VT_I4(4 バイト整数型)で
あるかどうかを確認し,VT_I4 型であれば,カメラ管理オブジ
ェクトにその値を設定します.
リスト6 CaoProvVariable.h
∼中略∼
protected:
HRESULT FinalInitialize(PVOID pObj);
// void FinalTerminate();
…①
∼中略∼
∼中略∼
HRESULT FinalGetValue(/*[out, retval]*/ VARIANT *pVal);
HRESULT FinalPutValue(/*[in]*/ VARIANT newVal);
…②
∼中略∼
●CaoProvFileの実装
最後に,CaoProvFile クラスの実装をおこないます.このクラ
スは,先ほどの変数(CaoProvVariable)と同様,情報をファイルと
// ========== 各社追加関数はこれ以下に記述する.==========
して扱う場合に利用します.カメラプロバイダでは,カメラ画
private:
// ========== 各社追加関数はこれ以下に記述する.==========
CCameraManager *m_cameraManager;
像をバイナリデータとして取得する機能を実装します.
…③
∼中略∼
CaoProvFile.h の編集
まずは,
他のクラスと同様に,
CaoProvFile.h ファイルを開き,
リ ス ト 8 の ① , ② の よ う に , FinalInitialize メ ソ ッ ド と
FinalGetValue メソッドのコメントアウトを解除してください.
リスト7 CaoProvVariable.cpp
また,メンバ変数として,リスト 8 の③に示すように,カメラ
管理オブジェクトへのポインタm_cameraManagerを宣言します.
∼中略∼
FinalInitialize
次に,FinalInitialize メソッドの実装をおこないます.ここで
HRESULT CCaoProvVariable::FinalInitialize(PVOID pObj)
{
CCaoProvController* pCaopCtrl = NULL;
CCaoProvExtension* pCaopExp = NULL;
CCaoProvFile* pCaopFile = NULL;
CCaoProvRobot* pCaopRobot = NULL;
CCaoProvTask* pCaopTask = NULL;
// 親オブジェクトの判定
switch (m_ulParentType) {
case SYS_CLS_CONTROLLER:
// カメラ管理オブジェクトへのポインタを取得する
pCaopCtrl = (CCaoProvController*)pObj;
m_cameraManager = pCaopCtrl->GetCameraManager();
break;
case SYS_CLS_EXTENSION:
pCaopExp = (CCaoProvExtension*)pObj;
break;
case SYS_CLS_FILE:
pCaopFile = (CCaoProvFile*)pObj;
break;
case SYS_CLS_ROBOT:
pCaopRobot = (CCaoProvRobot*)pObj;
break;
case SYS_CLS_TASK:
pCaopTask = (CCaoProvTask*)pObj;
break;
}
return S_OK;
も,CaoProvVariable クラスと同様に,リスト 9 の①に示すよう
に,親オブジェクトが CaoProvController クラスだった場合は,
GetCameraManager メソッドを呼び出し,カメラ管理オブジェク
トへのポインタを取得します.
FinalGetValue
続いて,FinalGetValue メソッドの実装をおこないます.
…①
このメソッドでは,USB カメラが取得した画像データを取得
するための機能を実装します.
ここでは,リスト 9 の③に示すようにカメラ管理オブジェク
トの GetImage メソッドを呼び出し,カメラ画像のバイナリデー
タを取得します.その後,画像サイズと同じ大きさの
SAFEARRAY を用意し,画像データをコピーします.
リスト8 CaoProvFile.h
∼中略∼
…②
}
protected:
HRESULT FinalInitialize(PVOID pObj);
// void FinalTerminate();
…①
∼中略∼
∼中略∼
HRESULT CCaoProvVariable::FinalGetValue(VARIANT *pVal)
{
// カメラ管理クラスから感度を取得し戻り値とする
pVal->vt = VT_I4;
pVal->lVal = m_cameraManager->GetThreshold();
return S_OK;
}
HRESULT FinalGetValue(/*[out, retval]*/ VARIANT *pVal);
…③
// ========== 各社追加関数はこれ以下に記述する.==========
private:
// ========== 各社追加関数はこれ以下に記述する.==========
CCameraManager *m_cameraManager;
∼中略∼
HRESULT CCaoProvVariable::FinalPutValue(VARIANT newVal)
{
// カメラ管理クラスに感度を設定する
if( newVal.vt == VT_I4 ){
m_cameraManager->SetThreshold( newVal.lVal );
return S_OK;
} else {
return S_FALSE;
}
}
…②
∼中略∼
∼中略∼
リスト9 CaoProvFile.cpp
…④
∼中略∼
HRESULT CCaoProvFile::FinalInitialize(PVOID pObj)
…③
{
環境を選択することができます.ここでは,Visual Studio
CCaoProvController* pCaopCtrl = NULL;
CCaoProvFile* pCaopFile = NULL;
2003 .NET の Visual Basic .NET を利用します.
●プロジェクトの作成
プロジェクトを新規に作成し,CAO プロバイダを利用したク
// 親オブジェクトの判定
switch (m_ulParentType) {
case SYS_CLS_CONTROLLER:
// カメラ管理オブジェクトへのポインタを取得する
pCaopCtrl = (CCaoProvController*)pObj;
m_cameraManager = pCaopCtrl->GetCameraManager();
break;
case SYS_CLS_FILE:
pCaopFile = (CCaoProvFile*)pObj;
break;
}
…①
return S_OK;
…②
ライアントアプリケーションを作成するための環境設定をおこ
ないます.
→「新規作成」→「プロジェクト」から「Visual Basic プロジェ
クト」→「Windows アプリケーション」を選択して,新しいプ
ロジェクトを作成してください.
}
次に,メニューバーから「プロジェクト」→「参照の追加」
から COM タブを選択します.
コンポーネント名が
「CAO 1.0 タ
∼中略∼
イプライブラリ」とあるアイテムを選んで,OK ボタンを押し
HRESULT CCaoProvFile::FinalGetValue(VARIANT *pVal)
{
long lSize;
てください.
●GUIの作成
次はGUI の作成です.
図9 に示すように,
ピクチャボックス,
// カメラ管理クラスから画像データを取得する.
BYTE *buf = m_cameraManager->GetImage(&lSize);
SAFEARRAY* pSa;
SAFEARRAYBOUND bounds = {lSize , 0}; // Elemnts, LBound
// BYTE 型の SAFEARRAY を用意し画像データをコピーする
pSa = SafeArrayCreate(VT_UI1, 1, &bounds);
BYTE* pbstrArray;
SafeArrayAccessData(pSa, (void **)&pbstrArray);
for (long i= 0; i < lSize; i++) {
pbstrArray[i] = *buf;
buf++;
}
SafeArrayUnaccessData(pSa);
pVal->vt = VT_ARRAY │ VT_UI1;
pVal->parray = pSa;
Visual Studio .NET 2003 を起動し,メニューバーの「ファイル」
トラックバー,開始/終了ボタンを持つフォームを作成してく
ださい.また,フォームおよび各コントロールの Name プロパ
ティは,表 5 に示すように設定してください.
…③
return S_OK;
}
∼中略∼
表 5 GUI のフォーム/コントロール構成
フォーム名/
Name プロパティ
用途
frmMain
アプリケーションの
コントロール名
Form
メインウィンドウ
Button
btnStart
監視開始ボタン
Button
btnStop
監視終了ボタン
PictureBox
pctBox
画像表示領域
TrackBar
barThreshold
感度調節バー
●プロバイダのビルド
以上で,USB カメラプロバイダの実装がすべて完了しました.
メニューバーの「ビルド」→「アクティブな構成の設定」で,
「Win32 Release MinDependency」(リリース版)を選択し,メニ
ューバーの「ビルド」→「リビルド」を実行して,プロバイダ
のビルドをおこなってください.
3 遠隔監視クライアントの作成
前節で作成した USB カメラプロバイダを利用して,
遠隔監視
をおこなうクライアントアプリケーションを作成します.
以降,
作成するクライアントアプリケーションを,
「遠隔監視クライア
ント」と呼ぶことにします.
遠隔監視クライアントには以下の機能を実装します.
・
カメラの画像を表示する
・
カメラ画像が変化した場合に,ユーザに知らせる
・
画像変化の検出感度を変更する
ORiN のクライアントアプリケーションは,いくつかの開発
図9 フォームの作成
●CaoEngineの生成
それでは,遠隔監視クライアントの実装に移りましょう.
まずは,frmMain.vb のソースコードを開いてください.リス
ト 10 の①に示すように,Imports ステートメントで名前空間の
●画像の取得
USB カメラプロバイダから画像を取得する処理を実装しま
指定をおこなってください.次にメンバ変数の追加をおこない
す.リスト 10 に示す setPicture メソッドを実装してください.
ます.②で宣言しているメンバ変数は,カメラプロバイダを利
USB カメラプロバイダから画像を取得するには,⑦のように
用するために必要となるオブジェクトのための変数です.
m_filePicture の Value プロパティを取得するだけで OK です.
次に,フォームが生成されたときの処理を実装します.フォ
ーム上でダブルクリックすると frmMain_Load メソッドが生成
されるので,リスト 10 のように実装してください.
③では,CaoEngine を生成し,CaoWorkspace の取得をおこな
います.クライアントアプリケーションで ORiN を利用する場
合は,このように,CaoEngine と CaoWorkspace を必ず生成する
必要があります.
●プロバイダへの接続
USB カメラプロバイダへの接続処理を実装します.この処理
は,開始ボタンが押されたときにおこなわれるようにします.
フォーム上の開始ボタンをダブルクリックすると,
btnStart_Click メソッドが生成されます.
リスト 10 のように実装
してください.
④では,
まず CaoWorkspace の AddController メソッドで,
CAO
プロバイダへの接続をおこないます.このメソッドの引数は,
先頭からコントローラ名,プロバイダ名,マシン名,パラメー
タとなっています.そして戻り値として,CaoController オブジ
●イベントの受付
先ほど AddHandler で登録したイベントハンドラの実装をお
こないます.リスト 10 に示す m_ctrlCamera_OnMessage メソッ
ドを実装してください.CAO プロバイダがイベントを通知する
と,この登録したメソッドが呼び出されます.
ここでは,イベントを受け取ると,setPicture メソッドを呼び
出し,ピクチャボックスに画像を表示させます.
●感度の設定
画像変化の検出感度を設定する処理を実装します.この処理
は,トラックバーをスクロールさせたときに実行されるように
しましょう.フォーム上のトラックバーをダブルクリックする
と,barThreshold_Scroll メソッドが生成されるので,リスト 10
のように実装してください.
⑧では,トラックバーの現在値を CaoVariable の Value プロパ
ティに設定しています.これにより,USB カメラプロバイダ側
の CaoProvVariable に,トラックバーの値が渡されます.
ェクトを返します.
リスト10 frmMain.vb
クライアントアプリケーションが CAO プロバイダからのイ
ベントを取得するには,AddHandler キーワードを使用してイベ
ントハンドラを取得する必要があります.
さらに,生成した CaoController オブジェクトの AddFile メソ
ッドと AddVariable メソッドを呼び出し,CaoFile オブジェクト
と CaoVariable オブジェクトを生成します.
●プロバイダの解放
上で取得した CaoController や CaoFile を解放する処理を実装
します.
まず,CaoFile や,CaoVariable を解放するためには,リスト
10 の⑤に示すように,以下の手順でおこないます.
・
上位のオブジェクト(今回の場合は CaoController)のコレク
・
メモリを解放する
・
Nothing を代入する
ションから,削除する
CaoController の解放も基本的には同様ですが,イベントハン
ドラを登録している場合は,⑥のように RemoveHandler キーワ
ードを利用して,
登録したメソッドを削除する必要があります.
この解放処理をおこなうメソッドを releaseCAO とし,終了ボ
タンが押されたときに実行されるようにします.フォーム上の
終了ボタンをダブルクリックするとbtnStop_Click メソッドが生
成されるので,このメソッドから releaseCAO メソッドを呼び出
すようにしてください.
Imports System.IO
Imports System.Text
Imports CAOLib
…①
'遠隔監視アプリケーションメインクラス
Public Class frmMain
Inherits System.Windows.Forms.Form
∼中略∼ " Windows フォーム デザイナで生成されたコード "
' CAO エンジン
Private m_caoEng As CaoEngine
' CAO ワークスペース
Private m_caoWS As CaoWorkspace
' USB カメラの CAO コントローラ
Private WithEvents m_ctrlCamera As CaoController
' カメラ画像の CAO ファイル
Private m_filePicture As CaoFile
' カメラの感度設定 CAO 変数
Private m_varThreshold As CaoVariable
' 画像のバイナリデータ
Private m_bArray() As Byte
'アプリケーションの初期化をおこなう
Private Sub frmMain_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
Try
'CAO エンジンと CAO ワークスペースの作成
m_caoEng = New CaoEngine
m_caoWS = m_caoEng.Workspaces.Item(0)
btnStart.Enabled = True
btnStop.Enabled = False
Catch ex As Exception
MsgBox("初期化処理に失敗しました" & vbCrLf & ex.Message)
Me.Close()
End Try
End Sub
…②
…③
'カメラプロバイダに接続をおこない画像計測を開始する
Private Sub btnStart_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnStart.Click
Try
' USB カメラプロバイダへの接続
m_ctrlCamera = m_caoWS.AddController( _
"camera", "CaoProv.Samples.Camera", "", "")
' イベントハンドラの設定
AddHandler m_ctrlCamera.OnMessage, _
…④
AddressOf m_ctrlCamera_OnMessage
' CAO ファイルの取得
m_filePicture = m_ctrlCamera.AddFile("Picture")
' CAO 変数の取得
m_varThreshold = m_ctrlCamera.AddVariable("Threshold")
btnStart.Enabled = False
btnStop.Enabled = True
setPicture()
Catch ex As Exception
MsgBox("プロバイダにアクセスできません" & vbCrLf & ex.Message)
End Try
End Sub
End Sub
'画像計測を終了しカメラプロバイダのリソースを解放する
Private Sub btnStop_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnStop.Click
Try
releaseCAO()
btnStart.Enabled = True
btnStop.Enabled = False
Catch ex As Exception
MsgBox("プロバイダを解放できません" & vbCrLf & ex.Message)
End Try
End Sub
End Try
End Sub
'取得していた CAO のリソースを解放する
Private Sub releaseCAO()
Try
' CAO 変数の解放
If Not m_varThreshold Is Nothing Then
m_ctrlCamera.Variables.Remove(m_varThreshold.Index)
System.Runtime.InteropServices.Marshal. _
ReleaseComObject(m_varThreshold)
m_varThreshold = Nothing
End If
' CAO ファイルの解放
If Not m_filePicture Is Nothing Then
m_ctrlCamera.Files.Remove(m_filePicture.Index)
System.Runtime.InteropServices.Marshal. _
ReleaseComObject(m_filePicture)
m_filePicture = Nothing
End If
' CAO コントローラの解放
If Not m_ctrlCamera Is Nothing Then
' イベントハンドラの解放
RemoveHandler m_ctrlCamera.OnMessage, _
AddressOf m_ctrlCamera_OnMessage
m_caoWS.Controllers.Remove(m_ctrlCamera.Index)
System.Runtime.InteropServices.Marshal. _
ReleaseComObject(m_ctrlCamera)
m_ctrlCamera = Nothing
End If
Catch ex As Exception
Throw ex
End Try
End Sub
'カメラプロバイダからのイベントを受付け画像を表示する
Private Sub m_ctrlCamera_OnMessage(ByVal pICaoMess As CAOLib.CaoMessage)
Try
setPicture()
Catch ex As Exception
MsgBox("失敗しました" & vbCrLf & ex.Message)
releaseCAO()
btnStart.Enabled = True
btnStop.Enabled = False
End Try
End Sub
'カメラの検出感度を変更する
Private Sub barThreshold_Scroll(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles barThreshold.Scroll
Try
' 感度の設定
…⑧
m_varThreshold.Value = barThreshold.Value
Catch ex As Exception
End Class
4 動作の確認
作成した USB カメラプロバイダと遠隔監視クライアントの
動作確認をおこないます.
●USBカメラプロバイダとの接続
遠隔監視クライアントと USB カメラプロバイダ間の接続を
確認します.先ほど作成した遠隔監視クライアントのプロジェ
…⑤
クトが読み込まれた状態で,Visual Basic のメニューバーの「デ
バッグ」→「開始」を選択し,プログラムを起動してください.
開始ボタンを押下すると,カメラプロバイダへの接続がおこ
なわれ,続けて setPicture メソッドが呼び出されるので,図 10
に示すように,
ピクチャボックスに USB カメラから取得した画
像が表示されます.
アプリケーションの動作が重たくなるようであれば,USB カ
メ ラ プ ロ バ イ ダ の , リ ス ト 3(StdAfx.h) の ② に 示 す
…⑥
'カメラプロバイダから画像を取得しピクチャボックスに表示
Private Sub setPicture()
Try
' 画像データの取得
m_bArray = m_filePicture.Value
…⑦
' バイナリデータから MemoryStream オブジェクトを作成する
Dim mstreamCur As New MemoryStream(m_bArray)
' ストリームから Image オブジェクトを作成し,ピクチャボックスに表示
pctBox.Image = Image.FromStream(mstreamCur)
Catch ex As Exception
Throw ex
End Try
CAOP_TIMER_INTERVAL マクロの値を,100 などの大きな値
に変更し,試してみてください.
●イベント通知
遠隔監視クライアントの起動(開始ボタン押下)中に,カメラ
の前で手を振ったりしてみてください.USB カメラプロバイダ
側で画像が変化したことを検知して,クライアントにイベント
が通知され,表示画像が切り替わります.
●感度設定の確認
イベント通知のときと同様に,今度はトラックバーを左右に
スクロールさせてみてください.トラックバーが左にいくほど
画像変化の感度がよくなり,小さな変化でもイベントが発生す
るようになります.逆に,トラックバーを右にすると,感度が
悪くなり,画像が大きく変化しないと,イベントは発生しなく
なります.
●遠隔監視
ORiN では,DCOM(Distributed Component Object Model)や,
ORiN 独自のインターネット対応プロトコル CAP を利用するこ
とで,ネットワーク経由で簡単に CAO プロバイダにアクセス
したが,この拡張版の遠隔監視クライアントは Web サイトから
ダウンロードできますので,興味のある方はお試し下さい.
その他,図 11 に示すような拡張例が考えられます.
・
カメラを接続し,それらを一元的に監視する.
することができます.これらの機能を用いれば,ネットワーク
に接続された,別の PC 上に接続されている USB カメラからの
DCOM や CAP の技術を利用して,遠隔の複数台の USB
・
USB カメラプロバイダと,他の CAO プロバイダとを連携
させる.例えば,USB カメラプロバイダから異変が通知
8
情報を取得することができます .
された場合に,ブザーを鳴らしたり,ランプを点灯させた
具体的に,
クライアントアプリケーションからDCOMやCAP
り,
さらに,
警備ロボットに異常を知らせたりする,
など.
を利用するには,リスト 11 のようにします.CAO プロバイダ
に接続する際のAddController メソッドの引数に,
DCOM やCAP
・
取得した画像をデータベースに蓄積する.
の指定をおこなうだけで OK です.
・
USB カメラプロバイダを拡張し,より高度な画像認識処
理や,ストリーミング再生機能を実装する.
リスト11 DCOM,CAPを利用したプロバイダへの接続
' DCOM を利用して,USB カメラプロバイダへの接続
' HOSTNAME:CAO プロバイダの動作している PC のホスト名
m_ctrlCamera = m_caoWS.AddController( _
"camera", "CaoProv.Samples.Camera", "HOSTNAME", "")
' CAP プロバイダを利用して,USB カメラプロバイダへの接続
' HOSTNAME:Web サーバの動作している PC のホスト名
m_ctrlCamera = m_caoWS.AddController( _
"camera", "CaoProv.CAP", "", _
"Provider=CaoProv.Samples.Camera,Server=HOSTNAME")
ORiN を利用することの利点は,CAO プロバイダが用意され
ていれば,デバイスの詳細を知らなくても,ORiN の共通のイ
ンタフェースを用いて,アプリケーションを容易に作成できる
ようになることです.ORiN2 SDK には標準でいくつかの CAO
プロバイダが既に用意されていますので,これらを利用してア
プリケーションを作成あるいは拡張させることもできます.ま
た,複数の CAO プロバイダを,クライアント側で統合的に監
視,制御することができることもあげられます.
上記に示したシステム拡張案も,ORiN を利用することで,
実現が容易になります.
●まとめ
以上,駆け足で ORiN プログラミングの解説をおこなってき
ましたが,いかがだったでしょうか?ここで紹介した内容は,
まだ ORiN の基本的な部分だけです.本特集を機会に,少しで
も ORiN に興味を持っていただければ幸いです.
図10 実行中のクライアント画面
5 システム拡張の可能性
今回作成した遠隔監視システムはシンプルなものですが,本
システムをベースに様々な機能を拡張することによって,より
高度な機能を持ったシステムに応用することができます.例え
ば,遠隔監視クライアントの機能として,異常検知時のメール
送信機能,ログ機能などを付加することで,システムがより実
用的になります.紙面の都合上,紹介することはできませんで
8 DCOMやCAPを利用するには,別途,環境設定をおこなう必要が
あります.設定方法については,ORiN2 SDKに附属の「ORiN2プ
ログラミングガイド」を参照して下さい.
図 11 システムの拡張
© Copyright 2026 Paperzz