画像処理コンポーネントの作成 (Windows 10、OpenRTM-aist-2.0.0、OpenRTP-2.0.0、CMake-3.19.8、VS2019)

はじめに

このケーススタディでは、簡単な画像処理をコンポーネント化する方法を紹介します。既存のカメラコンポーネントと画像表示コンポーネントを利用し、カメラからの画像を左右(または上下)に反転させる処理部分をコンポーネントとして作成してカメラの画像を反転させ表示するシステムを作成します。

画像を反転する処理は簡単に実装することができますが、ここではより簡単に実装するために OpenCV ライブラリを利用し、汎用性の高い RTコンポーネントを作成します。

OpenCVとは

OpenCV (オープンシーブイ) とはかつてインテルが、現在はItseezが開発・公開しているオープンソースのコンピュータービジョン向けライブラリです。

Wikipediaより抜粋。

作成する RTコンポーネント

  • Flip コンポーネント: OpenCV ライブラリが提供する様々な画像処理関数のうち、cv::flip() 関数を用いて画像の反転を行う RTコンポーネント。

cv::flip 関数の RTコンポーネント化

入力された画像を左右または上下に反転し出力する RTコンポーネントを、OpenCV ライブラリの cv::flip 関数を利用して作成します。作成および実行環境は Windows上 の Visual Studio を想定しています。対象 OpenRTM-aist のバージョンは 1.1.2 です。

作成手順はおおよそ以下のようになります。

  • 動作環境・開発環境についての確認
  • OpenCV と cv::flip 関数についての確認
  • コンポーネントの仕様を決める
  • RTCBuilder を用いたソースコードのひな形の作成
  • アクティビティ処理の実装
  • コンポーネントの動作確認

cv::flip関数について

cv::flip 関数は、OpenCV で標準的に用いられている cv::Mat 型の画像データを垂直軸 (左右反転)、水平軸 (上下反転)、または両軸 (上下左右反転)に対して反転させます。関数プロトタイプと入出力の引数の意味は以下の通りです。

 void flip(const Mat& src, Mat& dst, int flipMode)

src 入力配列
dst 出力配
flipMode 配列の反転方法の指定内容:
 flipMode = 0: X軸周りでの反転(上下反転)
 flipMode > 0: Y軸周りでの反転(左右反転)
 flipMode < 0: 両軸周りでの反転(上下左右反転)

コンポーネントの仕様

これから作成するコンポーネントを Flip コンポーネントと呼ぶことにします。

このコンポーネントは画像データ型の入力ポート (InPort) と、反転処理した画像を出力するための出力ポート (OutPort) を持ちます。それぞれのポートの名前を 入力ポート(InPort)名: originalImage、出力ポート(OutPort)名: flippedImage とします。

OpenRTM-aist には OpenCV を使用したビジョン関連のコンポーネントがサンプルとして付属しています。これらのコンポーネントのデータポートは画像の入出力に以下のような CameraImage 型を使用しています。

   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;
     };

このFlipコンポーネントではこれらのサンプルコンポーネントとデータのやり取りができるよう同じく CameraImage型 を InPort と OutPort に使用することにします。

CameraImage型 は InterfaceDataTypes.idl で定義されており、C++であれば、InterfaceDataTypesSkel.h をインクルードすると使えるようになります。

また、画像を反転させる方向は、左右反転、上下反転、上下左右反転の3通りがあります。これを実行時に指定できるように、RTコンポーネントのコンフィギュレーション機能を使用して指定できるようにします。パラメーター名は flipMode という名前にします。

flipMode は cv::flip 関数の仕様に合わせて、型は int 型とし 上下反転、左右反転、上下左右反転それぞれに 0、1、-1 を割り当てることにします。

flipMode の各値での画像処理のイメージを下図に示します。

cvFlip_and_FlipRTC.png
Flipコンポーネントの flipMode 指定時の画像反転パターン

以上から Flip コンポーネントの仕様をまとめます。

コンポーネント名称 Flip
InPort
ポート名 originalImage
RTC::CameraImage
説明 入力画像
OutPort
ポート名 flippedImage
RTC::CameraImage
説明 反転された画像
Configuration
パラメーター名 flipMode
int
デフォルト値 0
制約 (0,-1, 1)
Widget radio
説明 反転モード
上下反転: 0
左右反転: 1
上下左右反転: -1

動作環境・開発環境

ここで動作環境および開発環境を確認しておきます。

OpenRTM-aist-1.1 以降では、コンポーネントのビルドに CMake を使用します。

Flipコンポーネントの雛型の生成

Flipコンポーネントの雛型の生成は、RTCBuilder を用いて行います。

RTCBuilderの起動

Eclipse では、各種作業を行うフォルダーを「ワークスペース」(Work Space)とよび、原則としてすべての生成物はこのフォルダの下に保存されます。 ワークスペースはアクセスできるフォルダーであれば、どこに作っても構いませんが、このチュートリアルでは以下のワークスペースを仮定します。

  • C:\workspace

まずは Eclipse を起動します。 Windows 10の場合はデスクトップの以下のショートカットをダブルクリックして起動します。

/ja/node/7151

最初にワークスペースの場所を尋ねられますので、上記のワークスペースを指定して [OK] をクリックしてください。

/ja/node/7151

すると、以下のようなWelcomeページが表示されます。
Welcomeページは必要ないので左上の [×] ボタンをクリックして閉じてください。

/ja/node/7151
Eclipseの初期起動時の画面

右上の [Open Perspective] ボタンをクリックしてください。

/ja/node/7151
パースペクティブの切り替え

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

/ja/node/7151
パースペクティブの選択

新規プロジェクトの作成

Flipコンポーネントを作成するために、RTCBuilder で新規プロジェクトを作成する必要があります。

左上の [Open New RTCBuilder Editor] のアイコンをクリックしてください。

/ja/node/7151
RTC Builder 用プロジェクトの作成

「プロジェクト名」欄に作成するプロジェクト名 (ここでは Flip) を入力して [終了] をクリックします。

/ja/node/7151

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

/ja/node/7151

生成したプロジェクト内には、デフォルト値が設定された RTC プロファイル XML(RTC.xml) が自動的に生成されます。

RTC プロファイルエディタの起動

RTC.xmlが生成された時点で、このプロジェクトに関連付けられているワークスペースとして RTCBuilder のエディタが開くはずです。

プロファイル情報入力とコードの生成

まず、いちばん左の「基本」タブを選択し、基本情報を入力します。先ほど決めた Flip コンポーネントの仕様(名前)の他に、概要やバージョン等を入力してください。ラベルが赤字の項目は必須項目です。その他はデフォルトで構いません。

  • モジュール名: Flip
  • モジュール概要: 任意(Flip image component)
  • バージョン: 任意(1.0.0)
  • ベンダ名: 任意
  • モジュールカテゴリ: 任意(ImageProcessing)
  • コンポーネント型: STATIC
  • アクティビティ型: PERIODIC
  • コンポーネント種類: DataFlowComponent
  • 最大インスタンス数: 1
  • 実行型: PeriodicExecutionContext
  • 実行周期: 1000.0


/ja/node/7151
基本情報の入力


次に、「アクティビティ」タブを選択し、使用するアクションコールバックを指定します。

Flipコンポーネントでは、onActivated()、onDeactivated()、onExecute()コールバックを使用します。下図のように①の onAtivated をクリック後に ②のラジオボタンにて [ON] にチェックを入れます。onDeactivated、onExecute についても同様の操作を行います。


/ja/node/7151
アクティビティコールバックの選択


さらに、「データポート」タブを選択し、データポートの情報を入力します。 先ほど決めた仕様を元に以下のように入力します。なお、変数名や表示位置はオプションなので、変更しなくて結構です。


  • InPort Profile:
    • ポート名: originalImage
    • データ型: RTC::CameraImage
    • 変数名: originalImage
    • 表示位置: left

  • OutPort Profile:
    • ポート名: flippedImage
    • データ型: RTC::CameraImage
    • 変数名: flippedImage
    • 表示位置: right


/ja/node/7151
データポート情報の入力


次に、「コンフィギュレーション」タブを選択し、先ほど決めた仕様を元に、Configuration の情報を入力します。制約条件および Widget とは、RTSystemEditor でコンポーネントのコンフィギュレーションパラメーターを表示する際に、スライダー、スピンボタン、ラジオボタンなど、GUIで値の変更を行うためのものです。

ここでは、flipMode が取りうる値は先ほど仕様を決めたときに、-1、0、1 の3つの値のみ取ることにしたので、ラジオボタンを使用することにします。


  • flipMode
    • 名称: flipMode
    • データ型: int
    • デフォルト値: 0
    • 制約条件: (0, -1, 1)
      • ※ (-1: 上下左右反転、 0: 上下反転、 1: 左右反転)
    • Widget: radio


/ja/node/7151
コンフィグレーション情報の入力


次にプログラミング言語の選択とコードの生成を行いますが、OpenRTM-aist 2.0と1.2でツールの仕様が変わっています。

まずは1.2.2以前のバージョンの手順について説明します。

「言語・環境」タブを選択し、プログラミング言語を選択します。ここでは、C++(言語)を選択します。なお、言語・環境はデフォルト等が設定されておらず、指定し忘れるとコード生成時にエラーになりますので、必ず言語の指定を行うようにしてください。

Language_0.png
プログラミング言語の選択


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


Generate_0.png
雛型の生成(Generate)


次に2.0以降のバージョンの手順について説明します。

「基本」タブを選択して、下にスクロールすると見える「言語」の項目でC++を選択します。

/ja/node/7151

最後にコード生成ボタンをクリックし、コンポーネントの雛型を生成します。

コード生成が完了したら、以下のようにFlipプロジェクトを右クリックして、「表示方法」->「システム・エクスプローラー」をクリックすることで、エクスプローラーでワークスペースのフォルダを開いてください。 Flipフォルダに各種ファイルが生成されているか確認してください。

/ja/node/7151

CMakeによるビルドに必要なファイルの生成

RTC Builder で生成したコードの中には CMake でビルドに必要な各種ファイルを生成するための CMakeLists.txt が含まれています。 CMake を利用することにより CMakeLists.txt から Visual Studio のプロジェクトファイル、ソリューションファイル、もしくは Makefile 等を自動生成できます。

CMakeList.txt の編集

Flipフォルダのsrc/CMakeLists.txtをメモ帳などで開いて編集します。

/ja/node/7151
CMakeLists.txtの編集

このコンポーネントでは OpenCV を利用していますので、OpenCV のヘッダのインクルードパス、ライブラリやライブラリサーチパスを設定する必要があります。OpenCV は CMake に対応しており、以下の2行を追加・変更するだけで OpenCV のライブラリがリンクされ使えるようになります。

  • src/CMakeLists.txt を修正する
    • エクスプローラで src/CMakeLists.txt をダブルクリックしてメモ帳で開く
  • find_package(OpenCV REQUIRED)を追加
  • 最初のtarget_link_libraries に ${OpenCV_LIBS} を追加
    • target_link_libraries は2ヶ所あり、上がDLL、下が実行ファイルのライブラリ指定です

 set(comp_srcs Flip.cpp )
 set(standalone_srcs FlipComp.cpp)
 
 find_package(OpenCV REQUIRED) # <- この行を追加
   :中略
 add_dependencies(${PROJECT_NAME} ALL_IDL_TGT)
 target_link_libraries(${PROJECT_NAME} ${OPENRTM_LIBRARIES} ${OpenCV_LIBS}) # <- OepnCV_LIBSを追加
   :中略
 add_executable(${PROJECT_NAME}Comp ${standalone_srcs}
   ${comp_srcs} ${comp_headers} ${ALL_IDL_SRCS})
 add_dependencies(${PROJECT_NAME}Comp ALL_IDL_TGT)
 target_link_libraries(${PROJECT_NAME}Comp ${OPENRTM_LIBRARIES} ${OpenCV_LIBS})  # <- OepnCV_LIBSを追加

CMake(cmake-gui)の操作

CMakeを利用してビルド環境のConfigureを行います。 まずはCMake(cmake-gui)を起動してください。Windows 10の場合は画面左下の「ここに入力して検索」にCMakeと入力して検索してください。

/ja/node/7151
/ja/node/7151
CMake GUIの起動とディレクトリーの指定

画面上部に以下のようなテキストボックスがありますので、それぞれソースコードの場所( CMakeList.txt がある場所) と、ビルドディレクトリーを指定します。

  • Where is the soruce code
  • Where to build the binaries

ソースコードの場所は Flip コンポーネントのソースが生成された場所で CMakeList.txt が存在するディレクトリーです。デフォルトでは <ワークスペースディレクトリー>/Flip になります。

FlipフォルダのCMakeLists.txtをcmake-guiにドラッグアンドドロップすると、Flipフォルダのパスが自動的に入力されます。

/ja/node/7151

ビルドディレクトリーとは、ビルドするためのプロジェクトファイルやオブジェクトファイル、バイナリを格納する場所のことです。場所は任意ですが、この場合 <ワークスペースディレクトリー>/Flip/build のように分かりやすい名前をつけたFlipのサブディレクトリーを指定することをお勧めします。

Where is the soruce code C:\workspace\Flip
Where to build the binaries C:\workspace\Flip\build

指定したら、下のConfigureボタンを押します。Create Directoryの画面が出たらYESをクリックしてください。

/ja/node/7151

すると下図のようなダイアログが表示されますので、生成したいプロジェクトの種類を指定します。 今回は Visual Studio 16 2019 とします。VS2017やVS2022 を利用している方はそれぞれ読み替えてください。項目にVisual Studio 2022が無い場合は、cmake-guiのバージョンが古いため最新のバージョンをインストールし直してください。

/ja/node/7151
生成するプロジェクトの種類の指定

ダイアログで [Finish] をクリックすると Configure が始まります。問題がなければ下部のログウインドウに「Configuring done」と表示されますので、続けて [Generate] ボタンをクリックします。「Generating done」と表示されればプロジェクトファイル・ソリューションファイル等の出力が完了します。

/ja/node/7151

「Open Project」ボタンを押すと、Visual Studio 2019が起動して先ほど指定した build ディレクトリーの中の Flip.sln を 開きます。

/ja/node/7151

なお、CMake は Configure の段階でキャッシュファイルを生成しますので、トラブルなどで設定を変更したり環境を変更した場合は [File] > [Delete Cache] でキャッシュを削除して Configure からやり直してください。

ヘッダ、ソースの編集

ヘッダ (include/Flip/Flip.h) およびソースコード (src/Flip.cpp) をそれぞれ編集します。 Visual Studio のソリューションエクスプローラから Flip.h、Flip.cpp をクリックすることで編集画面が開きます。

/ja/node/7151

アクティビティ処理の実装

Flip コンポーネントでは、InPort から受け取った画像を画像保存用バッファに保存し、その保存した画像を OpenCVのcv::flip() 関数にて変換します。その後、変換された画像を OutPort から送信します。


onActivated()、onExecute()、onDeactivated()での処理内容を下図に示します。

FlipRTC_State_0.png
アクティビティ処理の概要


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


FlipRTC.png
onExucete()での処理内容


ヘッダファイル (Flip.h) の編集

OpenCV のライブラリを使用するため、OpenCV のインクルードファイルをインクルードします。

 #include <rtm/DataInPort.h>
 #include <rtm/DataOutPort.h>
 
 #include <opencv2/opencv.hpp> #この行を追加
 
 
 // <rtc-template block="component_description">

反転した画像の保存用にメンバー変数を追加します。

 private:
   // <rtc-template block="private_attribute">
  
   // </rtc-template>
  
   // <rtc-template block="private_operation">
  
   // </rtc-template>
  cv::Mat m_imageBuff; #この行を追加
  cv::Mat m_flipImageBuff; #この行を追加

ソースファイル (Flip.cpp) の編集

下記のように、onActivated()、onDeactivated()、onExecute() を実装します。

 RTC::ReturnCode_t Flip::onActivated(RTC::UniqueId ec_id)
 {
 
        // OutPortの画面サイズを0に設定
        m_flippedImage.width = 0;
        m_flippedImage.height = 0;
 
        return RTC::RTC_OK;
 }

 RTC::ReturnCode_t Flip::onDeactivated(RTC::UniqueId ec_id)
 {
        if (!m_imageBuff.empty())
        {
            // 画像用メモリの解放
            m_imageBuff.release();
            m_flipImageBuff.release();
        }
 
        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;
 
                m_imageBuff.create(cv::Size(m_originalImage.width, m_originalImage.height), CV_8UC3);
                m_flipImageBuff.create(cv::Size(m_originalImage.width, m_originalImage.height), CV_8UC3);
 
             
            }
 
            // InPortの画像データをm_imageBuffにコピー
            memcpy(m_imageBuff.data, (void *)&(m_originalImage.pixels[0]), m_originalImage.pixels.length());
 
            // InPortからの画像データを反転する。 m_flipMode 0: X軸周り、1: Y軸周り、-1: 両方の軸周り
            cv::flip(m_imageBuff, m_flipImageBuff, m_flipMode);
 
            // 画像データのサイズ取得
            int len = m_flipImageBuff.channels() * m_flipImageBuff.cols * m_flipImageBuff.rows;
            m_flippedImage.pixels.length(len);
 
            // 反転した画像データをOutPortにコピー
            memcpy((void *)&(m_flippedImage.pixels[0]), m_flipImageBuff.data, len);
 
            // 反転した画像データをOutPortから出力する。
            m_flippedImageOut.write();
        }
 
      return RTC::RTC_OK;
 }

Visual Studioによるビルド

ビルドの実行

Visual Studioの「ビルド」→「ソリューションのビルド」を選択してビルドを行います。


/ja/node/7151
ビルドの実行


Flipコンポーネントの動作確認

ここでは、OpenRTM-aist-1.1 以降で同梱されるようになったカメラコンポーネント (OpenCVCameraComp)とビューアコンポーネント (CameraViewerComp)を接続し動作確認を行います。

まずはRTSystemEditorを起動します。 OpenRTPのパースペクティブを開く画面からRTSystemEditorを選択して開いてください。

/ja/node/7151
/ja/node/7151

NameServiceの起動

コンポーネントの参照を登録するためのネームサービスを起動します。


RTSystemEditorのネームサービスビュー上部のネームサービス起動ボタンを押してください。

/ja/node/7151

Flipコンポーネントの起動

Flip コンポーネントを起動します。

build/src/Debug (もしくはbuild/src/Release)フォルダの FlipComp.exe ファイルを実行して下さい。

/ja/node/7151

カメラコンポーネントとビューアコンポーネントの起動

USBカメラのキャプチャ画像を OutPort から出力する OpenCVCameraComp と、InPort で受け取った画像を画面に表示する CameraViewerComp を起動します。

これら2つのコンポーネントは、下記の手順にて起動できます。

  • Windows 10の場合は画面左下の「ここに入力して検索」に「C++_OpenCV-Examples」と入力して検索してください。
    /ja/node/7151
  • エクスプローラーが立ち上がるので、「OpenCVCameraComp.bat」と「CameraViewerComp.bat」をそれぞれクリックして実行します。
    /ja/node/7151

コンポーネントの接続

コンポーネントが起動すると、以下のようにネームサービスビューにFlip、CameraViewer、OpenCVCameraコンポーネントが表示されるため、左上の「Open New System Editor」ボタン (ONのボタン) をクリックしてエディタを起動後に、エディタにコンポーネントをドラッグアンドドロップします。

/ja/node/7151

下図のように、RTSystemEditorにて OpenCVCameraComp と Flip、CameraviewerComp コンポーネントを接続します。

/ja/node/7151
コンポーネントの接続

ポートの接続は、片側のポートからもう片側のポートにドラッグアンドドロップすることでコネクタが生成されます。

/ja/node/7151

コンポーネントのActivate

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


/ja/node/7151
コンポーネントのアクティブ化


動作確認

下図のようにコンフィギュレーションビューにてコンフィギュレーションを変更することができます。

/ja/node/7151

エディタ上のFlipコンポーネントをクリックして編集ボタンを押してください。

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


/ja/node/7151
コンフィギュレーションパラメーターの変更


コンポーネントを終了する場合は、「All Exit」ボタンを押すとエディタ上のコンポーネントが全て終了します。

/ja/node/7151

ダウンロード

最新バージョン : 2.0.1-RELESE

統計

Webサイト統計
ユーザ数:2160
プロジェクト統計
RTコンポーネント307
RTミドルウエア35
ツール22
文書・仕様書2

Choreonoid

モーションエディタ/シミュレータ

OpenHRP3

動力学シミュレータ

OpenRTP

統合開発プラットフォーム

産総研RTC集

産総研が提供するRTC集

TORK

東京オープンソースロボティクス協会

DAQ-Middleware

ネットワーク分散環境でデータ収集用ソフトウェアを容易に構築するためのソフトウェア・フレームワーク