ダウンロード
最新バージョン : 2.1.0-RELESE
| 2.1.0-RELESE | ダウンロードページ |
OpenRTM@Github
OpenRTM-aist GitHubサイト
ROS
Robot Operating System
Choreonoid
モーションエディタ/シミュレータ
DAQ-Middleware
ネットワーク分散環境でデータ収集用ソフトウェアを容易に構築するためのソフトウェア・フレームワーク
産総研が提供するRTC集
東京オープンソースロボティクス協会
| 2.1.0-RELESE | ダウンロードページ |
OpenRTM-aist GitHubサイト
Robot Operating System
モーションエディタ/シミュレータ
ネットワーク分散環境でデータ収集用ソフトウェアを容易に構築するためのソフトウェア・フレームワーク
産総研が提供するRTC集
東京オープンソースロボティクス協会
はじめに
ここでは、OpenCVライブラリをVC9にてRTコンポーネント化する手順を紹介します。
また、今回作成したRTコンポーネントと既存のコンポーネントの組み合わせにより、画像処理を行うシステムの作成方法を紹介します。
OpenCVとは
OpenCV(おーぷんしーぶい)とはインテルが開発・公開しているオープンソースのコンピュータビジョン向けライブラリです。
Wikipediaより抜粋。
作成するRTコンポーネント
OpenCVライブリのRTコンポーネント化(Flipコンポーネント)
ここでは、OpenCVライブラリのうち、画像の反転を行うcvFlip()をVC9にてRTコンポーネント化します。
以下は、作業の流れです。
cvFlip関数について
cvFlip関数は、2次元配列を垂直、水平、または両軸で反転します。
コンポーネントの概要
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コンポーネントの雛型の生成
Flipコンポーネントの雛型の生成は、RTCBuilderを用いて行います。
RTCBuilderの起動
新規ワークスペースを指定してeclipseを起動すると、以下のようなWelcomeページが表示されます。
このWelcomeページを左上の「X」により閉じると以下のページが表示されます。
右上の「Open Perspective」ボタンを押下し、プルダウンの「Other…」ボタンを押下します。
「RTC Builder」を選択することで、RTCBuilderが起動します。
RTCBuilder 用プロジェクトの作成
まず最初に,RT コンポーネントを作成するための Eclipse プロジェクトを作成します。 画面上部のメニューから[ファイル]-[新規]-[プロジェクト]を選択します。
表示された「新規プロジェクト」画面において,「その他」-「 RTC ビルダ」を選択し、「次へ」をクリック.
「プロジェクト名」欄に作成するプロジェクト名を入力して「終了」をクリック。
指定した名称のプロジェクトが生成され、パッケージエクスプローラ内に追加されます。
生成したプロジェクト内には、デフォルト値が設定された RTC プロファイル XML(RTC.xml) が自動的に生成されます。
RTC プロファイルエディタの起動
RTC プロファイルエディタを開くには、ツールバーの「 Open New RtcBuilder Editor 」ボタンを押下するか、メニューバーの [file]-[Open New Builder Editor] を選択します。
コンポーネントのプロファイル情報入力とコードの生成
1. 「基本」タブを選択し、基本情報を入力します。
-モジュール名: Flip
-Output Project: Flip
2. 「アクティビティ」タブを選択し、使用するアクションコールバックを指定します。
Flipコンポーネントでは、onActivated(),onDeactivated(),onExecute()コールバックを使用します。 図14のように①のonAtivatedをクリック後に②のラジオボタンにて"on"にチェックを入れます。onDeactivated,onExecuteについても同様の手順を行います。
3. 「データポート」タブを選択し、データポートの情報を入力します。
-InPort Profile:
-OutPort Profile:
4. 「コンフィギュレーション」タブを選択し、Configurationの情報を入力します。
ラジオボタンでコンフィギュレーションの変更を行います。
-flipMode
5. 「言語・環境」タブを選択し、プログラミング言語を選択します。
今回は、C++(言語)を選択します。
6. 「基本」タブにある"コード生成"ボタンをクリックし、コンポーネントの雛型を生成します。
※ 生成されるコード群は、eclipse起動時に指定したワークスペースフォルダの中に生成されます。現在のワークスペースは、「ファイル(F)」 > 「ワークスペースの切り替え(W)...」で確認することができます。
アクティビティ処理の実装
Flipコンポーネントでは、InPortから受け取った画像を画像保存用バッファに保存し、その保存した画像をOpenCVのcvFlip()関数にて変換します。その後、変換された画像をOutPortから送信します。
onActivated(),onExecute(),onDeactivated()での処理内容を図19に示します。
onExecute()での処理を図20に示します。
OpenCV用ユーザープロパティシートのコピー
プロパティシートとは、コンパイルに必要な種々のオプション(インクルードパス、ライブラリロードバス、ライブラリ)やマクロを記述したVCの設定ファイルの一種です。 RTCBuilderやrtc-templateで生成したVC用のプロジェクトでは、VCのプロパティシートを使用して各種オプションを与えています。また、ユーザが追加でオプションを追加できるように、ユーザ定義のプロパティシートもインクルードするようになっています。以下の内容をuser_config.vspropsというファイル名で保存し、Flipフォルダにコピーしてください。
もしくは、下記よりvspropsファイルをダウンロードし、Flipフォルダに保存してください。
user_config.vsprops
※ 既に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の実行
copyprops.batというファイルを実行することで、rtm_config.vspropsというファイルがコピーされます。
rtm_config.vspropsファイルは、RTコンポーネントをVC++でビルドするために必要なインクルードパスやリンクするライブラリ等が記述されたファイルです。
ヘッダファイルの編集
/*** * * 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);ソースファイルの編集
下記のように、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コンポーネントのパッケージ
実装済みのパッケージを下記からダウンロードできます。
拡張子を"zip_"としてますので、"zip"にリネームしてから解凍して下さい。
ビルドの実行
Flip_vc9.slnファイルをダブルクリックし、Visual C++ 2008を起動します。
Visual C++ 2008の起動後、図21のようにし、コンポーネントのビルドを行います。
Flipコンポーネントの動作確認
ここでは、「OpenCV用RTC群(Win32用インストーラ)」にてインストールしたUSBCameraAqcuireCompコンポーネントと、USBCameraMonitorComコンポーネント、それと、今回作成したFlipコンポーネントを接続し動作確認を行います。
NameServiceの起動
omniORBのネームサービスを起動します。
[スタート] > [すべてのプログラム(P)] > [OpenRTM-aist] > [C++] > [tools] の順に辿り、「Start Naming Service」をクリックして下さい。
&color(RED){※ 「Star Naming Service」をクリックしてもomniNamesが起動されない場合は、フルコンピュータ名が14文字以内に設定されているかを確認してください。
rtc.confの作成
RTコンポーネントでは、ネームサーバーのアドレスやネームサーバーへの登録フォーマットなどの情報をrtc.confというファイルで指定する必要があります。
下記の内容をrtc.confというファイル名で保存し、Flip\FlipComp\Debug(もしくは、Release)フォルダに置いて下さい。
※ Eclipse起動時にworkspaceをデフォルトのままにしていた場合、Flipフォルダのパスは、
C:\Documents and Settings\<ログインユーザー名>\workspace となります。
corba.nameservers: localhost naming.formats: %n.rtc corba.endpoints: 192.168.100.2: # 自分のPCのIPアドレスを記述します。 # ※ コロン(:)を忘れないようにして下さい。Flipコンポーネントの起動
Flipコンポーネントを起動します。
先程rtc.confファイルを置いたフォルダにある、FlipComp.exeファイルを実行して下さい。
USBCameraAqcuire,USBCameraMonitorコンポーネントの起動
USBカメラのキャプチャ画像をOutPortから出力するUSBCameraAqcuireCompコンポーネントと、InPortで受け取った画像を画面に表示するUSBCameraMonitorCompコンポーネントを起動します。
これら2つのコンポーネントは、下記の手順にて起動できます。
[スタート] > [すべてのプログラム(P)] > [OpenRTM-aist] > [components] > [C++] > [OpenCV] の順に辿り、「USBCameraAqcuireComp」と「USBCameraMonitorComp」をそれぞれクリックして実行します。
コンポーネントの接続
図22のように、RTSystemEditorにてUSBCameraAqcuireComp,Flip,USBCameraMonitorCompコンポーネントを接続します。
コンポーネントのActivate
RTSystemEditorの上部にあります「ALL」というアイコンをクリックし、全てのコンポーネントをアクティベートします。
正常にアクティベートされた場合、図23のように黄緑色でコンポーネントが表示されます。
動作確認
図24のようにコンフィギュレーションビューにてコンフィギュレーションを変更することができます。
Flipコンポーネントのコンフィギュレーションパラメータ「flipMode」を「0」や「-1」などに変更し、画像の反転が行われるかを確認して下さい。
異なるPC間で動作するRTCの接続
異なるPC間で動作するRTコンポーネントを接続します。
rtc.confの編集
使用しているPCにネットワークインターフェースが複数存在する場合、以下のように"corba.endpoints" を設定して下さい。
# rtc.conf corba.nameservers: 192.168.100.10 naming.formats: %h.host_cxt/%n.rtc corba.endpoints: 192.168.100.10: # 自分のPCのIPアドレスを記述します。 # ※ コロン(:)を忘れないようにして下さい。コンポーネントの起動
USBCameraMonitorCompコンポーネントを起動してください。
[スタート] > [全てのプログラム] > [OpenRTM-aist] > [components] > [c++] > [OpenCV] とたどり、"USBCameraMonitorComp.exe"をクリックします。
異なるPC上で起動されているネームサーバーへの接続
図25の上部にあるコンセントマークのボタンを押下し、図26のダイアログにて異なるPCのIPアドレスを入力します。
コンポーネントの接続
異なるPC上のネームサーバーに登録されているUSBCameraAcquireコンポーネントと、localhostネームサーバー上 に登録されているUSBCameraMonitorコンポーネントをシステムエディタ上にドラッグ&ドロップします。
次にUSBCameraAcquireのOutPortとUSBCameraMonitorのInPortを図27のように接続します。
コンポーネントのアクティベート
図28のように、USBCameraMonitorを右クリックし、"Activate"をクリックします。
USBCameraMonitorコンポーネントの画面上に画像が表示されれば成功です。
Flipコンポーネントのソース・ヘッダファイル
Flipコンポーネントのソースファイル
// -*- 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>); } };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