ここでは、OpenCV ライブラリを VC9 にて RTコンポーネント化する手順を紹介します。
OpenCV とはインテルが開発・公開しているオープンソースのコンピュータービジョン向けライブラリです。
Wikipedia より抜粋。
ここでは、OpenCV ライブラリのうち、画像の反転を行う cvFlip() を VC9 にて RTコンポーネント化します。
以下は、作業の流れです。
cvFlip 関数は、2次元配列を垂直、水平、または両軸で反転します。
void cvFlip(IplImage* src, IplImage* dst=NULL, int flip_mode=0); #define cvMirror cvFlip src 入力配列 dst 出力配列。もし dst = NULL であれば、src が上書きされます。 flip_mode 配列の反転方法の指定内容: flip_mode = 0: X軸周りでの反転(上下反転) flip_mode > 0: Y軸周りでの反転(左右反転) flip_mode < 0: 両軸周りでの反転(上下左右反転)
InPort からの入力画像を反転し OutPort から出力するコンポーネント。
反転の対象軸は、RTC のコンフィギュレーション機能を使用して flipMode という名前のパラメーターで指定します。
flipMode は、反転したい方向に応じて下記のように指定してください。
作成する RTC の仕様は以下のとおりです。
※ CameraImage型は、OpenRTM-aist の InterfaceDataTypes.idl にて下記のように定義されているデータ型です。
struct CameraImage
{
/// Time stamp.
Time tm;
/// Image pixel width.
unsigned short width;
/// Image pixel height.
unsigned short height;
/// Bits per pixel.
unsigned short bpp;
/// Image format (e.g. bitmap, jpeg, etc.).
string format;
/// Scale factor for images, such as disparity maps,
/// where the integer pixel value should be divided
/// by this factor to get the real pixel value.
double fDiv;
/// Raw pixel data.
sequence<octet> pixels;
};
図1は、それぞれの flipMode での画像処理のイメージ図です。

Flip コンポーネントの雛型の生成は、RTCBuilder を用いて行います。
新規ワークスペースを指定して Eclipse を起動すると、以下のような「ようこそ」画面が表示されます。

この「ようこそ」画面左上の「X」をクリックして画面を閉じると、以下の画面が表示されます。 右上の [Open Perspective] ボタンをクリックし、プルダウンの「Other…」を選択します。

「RTC Builder」を選択し、[OK] ボタンをクリックします。

RTCBuilder が起動します。

まず最初に,RT コンポーネントを作成するための Eclipse プロジェクトを作成します。 画面上部のメニューから [ファイル] > [新規] > [プロジェクト] を選択します。

表示された「新規プロジェクト」画面において、[その他] > [RTC ビルダ] を選択し、[次へ] をクリックします。

「プロジェクト名」欄に作成するプロジェクト名を入力して [完了] をクリックします。

指定した名称のプロジェクトが生成され、パッケージエクスプローラー内に追加されます。

生成したプロジェクト内には、デフォルト値が設定された RTC プロファイル XML(RTC.xml) が自動的に生成されます。
RTC プロファイルエディタを開くには、ツールバーの「 [Open New RtcBuilder Editor] ボタンをクリックするか、メニューから [ファイル] > [Open New Builder Editor] を選択します。


1. 「基本」タブを選択し、基本情報を入力します。

2. 「アクティビティ」タブを選択し、使用するアクションコールバックを指定します。
Flip コンポーネントでは、onActivated()、onDeactivated()、onExecute()コ ールバックを使用します。 図14のように①の onAtivated をクリック後に ②のラジオボタンの [ON] にチェックを入れます。onDeactivated、onExecute についても同様の操作を行います。

3. 「データポート」タブを選択し、データポートの情報を入力します。

4. 「コンフィギュレーション」タブを選択し、Configuration の情報を入力します。
ラジオボタンでコンフィギュレーションの変更を行います。

5. 「言語・環境」タブを選択し、プログラミング言語を選択します。
今回は、C++(言語)を選択します。

6. 「基本」タブにある [コード生成] ボタンをクリックし、コンポーネントの雛型を生成します。

※ 生成されるコード群は、Eclipse 起動時に指定したワークスペースフォルダーの中に生成されます。現在のワークスペースは、[ファイル] > [ワークスペースの切り替え] で確認することができます。
Flip コンポーネントでは、InPort から受け取った画像を画像保存用バッファに保存し、その保存した画像を OpenCV の cvFlip() 関数にて変換します。その後、変換された画像を OutPort から送信します。
onActivated()、onExecute()、onDeactivated() での処理内容を図19に示します。

onExecute() での処理を図20に示します。

以下の内容を user_config.vsprops というファイル名で保存し、Flip フォルダーにコピーしてください。
もしくは、下記より vsprops ファイルをダウンロードし、Flip フォルダーに保存してください。
※ 既に Flip フォルダーには user_config.vsprops ファイルが存在していますが、上書きして構いません。
<?xml version="1.0" encoding="shift_jis"?>
<VisualStudioPropertySheet
ProjectType="Visual C++"
Version="8.00"
Name="OpenCV21"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="$(cv_includes)"
/>
<Tool
Name="VCLinkerTool"
AdditionalLibraryDirectories="$(cv_libdir)"
/>
<UserMacro
Name="user_lib"
Value="$(cv_lib)"
/>
<UserMacro
Name="user_libd"
Value="$(cv_libd)"
/>
<UserMacro
Name="cv_root"
Value="C:\OpenCV2.1"
/>
<UserMacro
Name="cv_includes"
Value=""$(cv_root)\include\opencv""
/>
<UserMacro
Name="cv_libdir"
Value=""$(cv_root)\lib""
/>
<UserMacro
Name="cv_bin"
Value="$(cv_root)\bin"
/>
<UserMacro
Name="cv_lib"
Value="cv210.lib cvaux210.lib highgui210.lib cxcore210.lib"
/>
<UserMacro
Name="cv_libd"
Value="cv210d.lib cvaux210d.lib highgui210d.lib cxcore210d.lib"
/>
</VisualStudioPropertySheet>copyprops.batというファイルを実行することで、rtm_config.vspropsというファイルがコピーされます。
rtm_config.vspropsファイルは、RTコンポーネントをVC++でビルドするために必要なインクルードパスやリンクするライブラリ等が記述されたファイルです。
//OpenCV 用インクルードファイルのインクルード #include<cv.h> #include<cxcore.h> #include<highgui.h>
/***
*
* The activated action (Active state entry action)
* former rtc_active_entry()
*
* @param ec_id target ExecutionContext Id
*
* @return RTC::ReturnCode_t
*
*
*/
virtual RTC::ReturnCode_t onActivated(RTC::UniqueId ec_id);
/***
*
* The deactivated action (Active state exit action)
* former rtc_active_exit()
*
* @param ec_id target ExecutionContext Id
*
* @return RTC::ReturnCode_t
*
*
*/
virtual RTC::ReturnCode_t onDeactivated(RTC::UniqueId ec_id);
/***
*
* The execution action that is invoked periodically
* former rtc_active_do()
*
* @param ec_id target ExecutionContext Id
*
* @return RTC::ReturnCode_t
*
*
*/
virtual RTC::ReturnCode_t onExecute(RTC::UniqueId ec_id);IplImage* m_imageBuff; IplImage* m_flipImageBuff;
下記のように、onActivated()、onDeactivated()、onExecute() を実装します。
RTC::ReturnCode_t Flip::onActivated(RTC::UniqueId ec_id)
{
// イメージ用メモリーの初期化
m_imageBuff = NULL;
m_flipImageBuff = NULL;
// OutPort の画面サイズの初期化
m_flippedImage.width = 0;
m_flippedImage.height = 0;
return RTC::RTC_OK;
}
RTC::ReturnCode_t Flip::onDeactivated(RTC::UniqueId ec_id)
{
if(m_imageBuff != NULL)
{
// イメージ用メモリーの解放
cvReleaseImage(&m_imageBuff);
cvReleaseImage(&m_flipImageBuff);
}
return RTC::RTC_OK;
}
RTC::ReturnCode_t Flip::onExecute(RTC::UniqueId ec_id)
{
// 新しいデータのチェック
if (m_originalImageIn.isNew()) {
// InPort データの読み込み
m_originalImageIn.read();
// InPort と OutPort の画面サイズ処理およびイメージ用メモリーの確保
if( m_originalImage.width != m_flippedImage.width || m_originalImage.height != m_flippedImage.height)
{
m_flippedImage.width = m_originalImage.width;
m_flippedImage.height = m_originalImage.height;
// InPort のイメージサイズが変更された場合
if(m_imageBuff != NULL)
{
cvReleaseImage(&m_imageBuff);
cvReleaseImage(&m_flipImageBuff);
}
// イメージ用メモリーの確保
m_imageBuff = cvCreateImage(cvSize(m_originalImage.width, m_originalImage.height), IPL_DEPTH_8U, 3);
m_flipImageBuff = cvCreateImage(cvSize(m_originalImage.width, m_originalImage.height), IPL_DEPTH_8U, 3);
}
// InPort の画像データを IplImage の imageData にコピー
memcpy(m_imageBuff->imageData,(void *)&(m_originalImage.pixels[0]),m_originalImage.pixels.length());
// InPort からの画像データを反転する。 m_flipMode 0: X軸周り, 1: Y軸周り, -1: 両方の軸周り
cvFlip(m_imageBuff, m_flipImageBuff, m_flipMode);
// 画像データのサイズ取得
int len = m_flipImageBuff->nChannels * m_flipImageBuff->width * m_flipImageBuff->height;
m_flippedImage.pixels.length(len);
// 反転した画像データを OutPort にコピー
memcpy((void *)&(m_flippedImage.pixels[0]),m_flipImageBuff->imageData,len);
// 反転した画像データを OutPort から出力する。
m_flippedImageOut.write();
}
return RTC::RTC_OK;
}Flip_vc9.sln ファイルをダブルクリックし、Visual C++ 2008 を起動します。
Visual C++ 2008 の起動後、図21のようにし、コンポーネントのビルドを行います。

ここでは、「OpenCV用RTC群 (Win32用インストーラ)」にてインストールした USBCameraAqcuireComp コンポーネントと、USBCameraMonitorCom コンポーネント、それと、今回作成した Flip コンポーネントを接続し動作確認を行います。
omniORB のネームサービスを起動します。
[スタート] > [すべてのプログラム] > [OpenRTM-aist] > [C++] > [tools] の順に辿り、「Start Naming Service」をクリックしてください。
&color(RED){※ 「Star Naming Service」をクリックしても omniNames が起動されない場合は、フルコンピューター名が14文字以内に設定されているかを確認してください。
RTコンポーネントでは、ネームサーバーのアドレスやネームサーバーへの登録フォーマットなどの情報を rtc.conf というファイルで指定する必要があります。
下記の内容を rtc.conf というファイル名で保存し、Flip\FlipComp\Debug(もしくは、Release)フォルダーに置いて下さい。
※ Eclipse 起動時に workspace をデフォルトのままにしていた場合、Flip フォルダーのパスは、
C:\Documents and Settings\<ログインユーザー名>\workspace となります。
corba.nameservers: localhost naming.formats: %n.rtc
Flip コンポーネントを起動します。
先程 rtc.conf ファイルを置いたフォルダーにある、FlipComp.exe ファイルを実行して下さい。
USB カメラのキャプチャ画像を OutPort から出力する USBCameraAqcuireComp コンポーネントと、InPort で受け取った画像を画面に表示する USBCameraMonitorComp コンポーネントを起動します。
これら2つのコンポーネントは、下記の手順にて起動できます。
[スタート] > [すべてのプログラム] > [OpenRTM-aist] > [components] > [C++] > [OpenCV] を選択し、「USBCameraAqcuireComp」と「USBCameraMonitorComp」をそれぞれクリックして実行します。
図22のように、RTSystemEditor にて USBCameraAqcuireComp、Flip、USBCameraMonitorComp コンポーネントを接続します。

RTSystemEditor の上部にあります「ALL」というアイコンをクリックし、全てのコンポーネントをアクティベートします。
正常にアクティベートされた場合、図23のように黄緑色でコンポーネントが表示されます。

図24のようにコンフィギュレーションビューにてコンフィギュレーションを変更することができます。
Flip コンポーネントのコンフィギュレーションパラメーター「flipMode」を「0」や「-1」などに変更し、画像の反転が行われるかを確認してください。

// -*- C++ -*-
/*!
* @file Flip.cpp
* @brief Flip image component
* @date $Date$
*
* $Id$
*/
#include "Flip.h"
// Module specification
static const char* flip_spec[] =
{
"implementation_id", "Flip",
"type_name", "Flip",
"description", "Flip image component",
"version", "1.0.0",
"vendor", "AIST",
"category", "Category",
"activity_type", "PERIODIC",
"kind", "DataFlowComponent",
"max_instance", "1",
"language", "C++",
"lang_type", "compile",
// Configuration variables
"conf.default.flipMode", "1",
// Widget
"conf.__widget__.flipMode", "radio",
// Constraints
"conf.__constraints__.flip_mode", "(-1,0,1)",
""
};
/*!
* @brief constructor
* @param manager Maneger Object
*/
Flip::Flip(RTC::Manager* manager)
: RTC::DataFlowComponentBase(manager),
m_originalImageIn("originalImage", m_originalImage),
m_flippedImageOut("flippedImage", m_flippedImage)
{
}
/*!
* @brief destructor
*/
Flip::~Flip()
{
}
RTC::ReturnCode_t Flip::onInitialize()
{
// Registration: InPort/OutPort/Service
// Set InPort buffers
addInPort("originalImage", m_originalImageIn);
// Set OutPort buffer
addOutPort("flippedImage", m_flippedImageOut);
// Bind variables and configuration variable
bindParameter("flipMode", m_flipMode, "1");
return RTC::RTC_OK;
}
RTC::ReturnCode_t Flip::onActivated(RTC::UniqueId ec_id)
{
// イメージ用メモリーの初期化
m_imageBuff = NULL;
m_flipImageBuff = NULL;
// OutPort の画面サイズの初期化
m_flippedImage.width = 0;
m_flippedImage.height = 0;
return RTC::RTC_OK;
}
RTC::ReturnCode_t Flip::onDeactivated(RTC::UniqueId ec_id)
{
if(m_imageBuff != NULL)
{
// イメージ用メモリーの解放
cvReleaseImage(&m_imageBuff);
cvReleaseImage(&m_flipImageBuff);
}
return RTC::RTC_OK;
}
RTC::ReturnCode_t Flip::onExecute(RTC::UniqueId ec_id)
{
// 新しいデータのチェック
if (m_originalImageIn.isNew()) {
// InPort データの読み込み
m_originalImageIn.read();
// InPort と OutPort の画面サイズ処理およびイメージ用メモリーの確保
if( m_originalImage.width != m_flippedImage.width || m_originalImage.height != m_flippedImage.height)
{
m_flippedImage.width = m_originalImage.width;
m_flippedImage.height = m_originalImage.height;
// InPort のイメージサイズが変更された場合
if(m_imageBuff != NULL)
{
cvReleaseImage(&m_imageBuff);
cvReleaseImage(&m_flipImageBuff);
}
// イメージ用メモリーの確保
m_imageBuff = cvCreateImage(cvSize(m_originalImage.width, m_originalImage.height), IPL_DEPTH_8U, 3);
m_flipImageBuff = cvCreateImage(cvSize(m_originalImage.width, m_originalImage.height), IPL_DEPTH_8U, 3);
}
// InPort の画像データを IplImage の imageData にコピー
memcpy(m_imageBuff->imageData,(void *)&(m_originalImage.pixels[0]),m_originalImage.pixels.length());
// InPort からの画像データを反転する。 m_flipMode 0: X軸周り, 1: Y軸周り, -1: 両方の軸周り
cvFlip(m_imageBuff, m_flipImageBuff, m_flipMode);
// 画像データのサイズ取得
int len = m_flipImageBuff->nChannels * m_flipImageBuff->width * m_flipImageBuff->height;
m_flippedImage.pixels.length(len);
// 反転した画像データを OutPortにコピー
memcpy((void *)&(m_flippedImage.pixels[0]),m_flipImageBuff->imageData,len);
// 反転した画像データを OutPortから出力する。
m_flippedImageOut.write();
}
return RTC::RTC_OK;
}
extern "C"
{
void FlipInit(RTC::Manager* manager)
{
coil::Properties profile(flip_spec);
manager->registerFactory(profile,
RTC::Create<Flip>,
RTC::Delete<Flip>);
}
}; // -*- C++ -*-
/*!
* @file Flip.h
* @brief Flip image component
* @date $Date$
*
* $Id$
*/
#ifndef FLIP_H
#define FLIP_H
#include <rtm/Manager.h>
#include <rtm/DataFlowComponentBase.h>
#include <rtm/CorbaPort.h>
#include <rtm/DataInPort.h>
#include <rtm/DataOutPort.h>
#include <rtm/idl/BasicDataTypeSkel.h>
#include <rtm/idl/ExtendedDataTypesSkel.h>
#include <rtm/idl/InterfaceDataTypesSkel.h>
//OpenCV 用インクルードファイルのインクルード
#include<cv.h>
#include<cxcore.h>
#include<highgui.h>
using namespace RTC;
/*!
* @class Flip
* @brief Flip image component
*
*/
class Flip
: public RTC::DataFlowComponentBase
{
public:
/*!
* @brief constructor
* @param manager Maneger Object
*/
Flip(RTC::Manager* manager);
/*!
* @brief destructor
*/
~Flip();
/***
*
* The initialize action (on CREATED->ALIVE transition)
* formaer rtc_init_entry()
*
* @return RTC::ReturnCode_t
*
*
*/
virtual RTC::ReturnCode_t onInitialize();
/***
*
* The activated action (Active state entry action)
* former rtc_active_entry()
*
* @param ec_id target ExecutionContext Id
*
* @return RTC::ReturnCode_t
*
*
*/
virtual RTC::ReturnCode_t onActivated(RTC::UniqueId ec_id);
/***
*
* The deactivated action (Active state exit action)
* former rtc_active_exit()
*
* @param ec_id target ExecutionContext Id
*
* @return RTC::ReturnCode_t
*
*
*/
virtual RTC::ReturnCode_t onDeactivated(RTC::UniqueId ec_id);
/***
*
* The execution action that is invoked periodically
* former rtc_active_do()
*
* @param ec_id target ExecutionContext Id
*
* @return RTC::ReturnCode_t
*
*
*/
virtual RTC::ReturnCode_t onExecute(RTC::UniqueId ec_id);
protected:
// Configuration variable declaration
/*!
*
* - Name: flipMode
* - DefaultValue: 1
*/
int m_flipMode;
// DataInPort declaration
CameraImage m_originalImage;
/*!
*/
InPort<CameraImage> m_originalImageIn;
// DataOutPort declaration
CameraImage m_flippedImage;
/*!
*/
OutPort<CameraImage> m_flippedImageOut;
private:
// 処理画像用バッファ
IplImage* m_imageBuff;
IplImage* m_flipImageBuff;
};
extern "C"
{
DLL_EXPORT void FlipInit(RTC::Manager* manager);
};
#endif // FLIP_Hビルド済みパッケージを下記からダウンロードできます。
拡張子を"zip_"としてますので、"zip"にリネームしてから解凍してください。