RT컴포넌트 작성(OpenCV)

머릿말

여기에서는, OpenCV 라이브러리를 VC9에서 RT컴퍼넌트화하는 순서를 소개합니다.

OpenCV란

OpenCV(오픈씨브이)란 인텔이 개발·공개하고 있는 오픈 소스의 컴퓨터 비전을 위한 라이브러리입니다.

Wikipedia에서 발췌.

작성하는 RT컴퍼넌트

  • Flip 컴퍼넌트: OpenCV 라이브러리 중, cvFlip() 함수를 이용해 화상의 반전을 실시하는 RT컴포넌트.
  • ObjectTracking 컴포넌트: OpenCV 라이브러리를 사용해, 마우스로 선택한 대상물을 추적하는 컴포넌트. 추적중의 화상 표시, 추적 화상을 OutPort로부터 출력, 추적 대상의 이동량을 OutPort에서 출력 등의 기능을 가진다.

cvFlip함수에 대해서

OpenCV라이브러리의 RT컴포넌트화(Flip컴포넌트)

이 페이지에서는 OpenCV라이브러리 중, 화상을 반전 시키는 cvFlip()를 VC9에서 RT컴포넌트화 합니다.

이하는 작업의 흐름입니다.

  • cvFlip함수에 대해
  • 컴포넌트의 개요
  • 동작 환경・개발 환경
  • Flip컴포넌트 모형의 생성
  • 액티비티 처리의 구현
  • 컴포넌트의 동작 확인

cvFlip함수에 대해

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의 컨피그레이션 기능을 사용해서 flip_mode라는 이름의 파라메터로 지정합니다.

flip_mode는 반전하고 싶은 방향에 따라 이하와 같이 지정해 주십시오.

  • 상하 반전의 경우 : 0
  • 좌우 반전의 경우 : 1
  • 상하 좌우 반전의 경우 : -1


작성한 RTC의 사양은 이하와 같습니다.

  • InPort
    • 캡쳐된 화상의 데이터(CameraImage)
  • OutPort
    • 반전한 화상의 데이터(CameraImage)
  • Configuration
    • 반전 방법의 지정(int)

※ TCameraImage형이란, 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은 각각의 flip_mode에서의 화상처리 이미지입니다.


cvFlip_and_FlipRTC_ko.png
그림 1. Flip컴포넌트의 flip_mode의 지정 패턴


동작 환경・개발 환경

  • RTSystemEditor 1.0
  • RTCBuilder 1.0
  • 압축해제 툴(Lhaplus)
http://www.forest.impress.co.jp/lib/arc/archive/archiver/lhaplus.html

Flip컴포넌트 모형의 생성

Flip컴포넌트 모형의 생성은 RTCBuilder를 사용합니다.

RTCBuilder의 기동

eclipse를 기동하면 이하와 같은 Welcome페이지가 표시됩니다.

fig1-1EclipseInit_ko.png
그림 2. Eclipse의 초기 기동시의 화면


이 Welcome페이지를 좌측 상단의 「X」를 눌러 닫으면 이하의 페이지가 표시됩니다.

fig2-2PerspectiveSwitch_ko.png
그림 3. 퍼스펙티브의 변환


우측 상단의 「Open Perspective」버튼을 눌러 풀다운의 「Other…」버튼을 누릅니다.

fig2-3PerspectiveSelection_ko.png
그림 4. 퍼스펙티브 선택


「RTC Builder」를 선택하는 것으로 RTCBuilder가 기동합니다.

fig2-4RTCBuilderInit_ko.png
그림 5. RTC Builder 초기 기동시 화면


RTCBuilder 용 프로젝트 생성

우선, RT컴포넌트를 작성하기 위한 Eclipse프로젝트를 작성합니다. 화면 상부의 메뉴에서 [File]-[New]-[Project]를 선택합니다.

fig2-5CreateProject_ko.png
그림 6. RTC Builder 용 프로젝트 작성 1


표시된「New Project」화면에서, [Other]-[RTC Build]를 선택해,「Next」를 클릭.

fig2-6CreateProject2_ko.png
그림 7. RTC Builder 용 프로젝트 작성 2


「Project name」에 작성하는 프로젝트명을 입력하고 [Finish]를 클릭.

fig2-7CreteProject3_ko.PNG
그림 8. RTC Builder 용 프로젝트 작성 3


지정한 프로젝트 이름의 프로젝트가 생성되어 패키지 익스플로어에 추가됩니다.

fig2-8CreateProject4_ko.png
그림 9. RTC Builder 용 프로젝트 작성 4


생성한 프로젝트에는, 디폴트 값이 설정된 RTC 프로파일 XML(RTC.xml)가 자동적으로 생성됩니다.

RTC 프로파일 에디터 기동

RTC 프로파일 에디터를 열려면 , 툴바의「 Open New RtcBuilder Editor 」버튼을 클릭하던가, 도구모음의 [file]-[Open New Builder Editor] 를 선택합니다.

fig2-9ToolsBarOpenNewRtcBuilder_ko.png
그림 10. 툴바로부터 Open New RtcBuilder Editor



fig2-10FileMenuOpenNewBuilder_ko.png
그림 11. File 메뉴로부터 Open New Builder Editor


데이터 포트에서 사용하는 데이터 타입 정의 파일 소재의 설정

데이터 포트나 서비스 포트에서 사용하는 데이터형이 정의된 IDL파일이 놓인 위치를 미리 설정해 둘 필요가 있습니다.
※ 여기서의 설정 내용은 워크 스페이스를 변경하지 않는 한 유효하므로, 프로젝트마다 설정할 필요는 없습니다.
이하와 같은 순서로 데이터형이 정의되어 있는 IDL파일의 소재를 설정해 주십시오.

 1. 메뉴바에서 「Window」-「Preferences」-「RtcBuilder」순서로 들어가면 그림 12의 Data Type:IDL File Directories가 표시됩니다.
 2. 그림 12에서 [New]버튼을 클릭해 "IDL File Directories"를 입력합니다.
     OpenRTM-aist에서 정의되어 있는 데이터형의 IDL파일은 디폴트로는 이하의 경로에 인스톨됩니다.
     
      C:\Program Files\OpenRTM-aist\1.0\rtm\idl
 
 3. [OK]버튼을 클릭해 설정을 종료합니다.


RTCBuilder_datatype_setup_ko.png
그림 12. 데이터형 정의 파일의 소재 설정


컴포넌트의 프로파일 정보 입력과 코드의 생성

1. 「Basic」탭을 선택해 기본 정보를 입력합니다.


  • Module name: Flip
  • Module description: Flip image component
  • Module version: 1.0.0
  • Module vender: AIST
  • Module category: Category
  • Component type: STATIC
  • Component's activity type: PERIODIC
  • Component kind: DataFlowComponent
  • Number of maximum instance: 1
  • Execution type: PeriodicExecutionContext
  • Execution Rate: 0.0
  • Output Project: Flip


RTCBuilder_base_ko.png
그림 13. 기본 정보 입력


2. 「Activity」탭을 선택해 사용하는 액션 콜백을 지정합니다.

Flip컴포넌트는 onActivated(), onDeactivated(), onExecute() 콜백을 사용하기 때문에 그림 14와 같이 on_activated, on_deactivated, on_execute의 3개를 ON으로 설정합니다.


RTCBuilder_activity_ko.png
그림 14. 액티비티 콜백의 선택


3. 「Data Ports」탭을 선택해 데이터 포트의 정보를 입력합니다.


  • InPort Profile:
    • Port Name: originalImage
    • Data Type: CameraImage
    • Var Name: originalImage
    • Disp. Position: left
  • OutPort Profile:
    • Port Name: flippedImage
    • Data Type: CameraImage
    • Var Name: flippedImage
    • Disp. Position: right


RTCBuilder_dataport_ko.png
그림 15. 데이터 포트 정보 입력


4. 「Configuration」탭을 선택해 Configuration의 정보를 입력합니다.


  • flipMode
    • Name: flipMode
    • Type: int
    • Default Value: 1
    • Variable name: flip_mode
    • Constraint: (-1, 0, 1) ※ (-1: 상하 좌우 반전, 0: 상하 반전, 1: 좌우 반전)


RTCBuilder_config_ko.png
그림 16. 컨피그레이션 정보 입력


5. 「Language and Environment」탭을 선택해 프로그래밍 언어를 선택합니다.

여기에서는 C++(언어)를 선택합니다.


RTCBuilder_lang_ko.png
그림 17. 프로그래밍 언어 선택


6. 「Basic」탭에 있는 "Code Generation"버튼을 클릭해 컴포넌트의 모형을 생성합니다.


RTCBuilder_base2_ko.png
그림 18. 모형의 행성(Generate)


※ 생성되는 코드는 eclipse기동시에 지정한 워크 스페이스 폴더안에 생성됩니다. 현재의 워크 스페이스는 「File」-「Switch Workspace」에서 확인 가능합니다.

액티비티 처리의 구현

Flip컴포넌트에서는 InPort로 부터 받은 화상을 화상 저장용 버퍼에 저장해 그 저장한 화상을 OpenCV의 cvFlip()함수에서 변환합니다. 그 후, 변환된 화상을 OutPort에서 송신합니다.

onActivated(), onExecute(), onDeactivated()에서의 처리 내용을 그림 19에 표시합니다.。

FlipRTC_State_ko.png
그림 19. 액티비티 처리의 개요


onExecute()에서의 처리를 그림 20에 표시합니다.


FlipRTC_ko.png
그림 20. onExucete()에서의 처리내용


OpenCV용 유저 프로퍼티 시트의 복사

프로퍼티 시트란 컴파일에 필요한 여러가지의 옵션(인클루드 경로, 라이브러리 로드 경로, 라이브러리)이나 매크로를 기술한 VC의 설정 파일의 일종입니다. RTCBuilder나 rtc-template로 생성한 VC용 프로젝트에서는 VC의 프로퍼티 시트를 이용해 각종 옵션을 부여합니다. 또한, 유저가 추가로 옵션을 추가할 수 있도록 유저 설정의 프로퍼티 시트도 인클루드 하도록 되어 있습니다.
  • rtm_config.vsprop:OpenRTM에 관한 정보를 포함한 프로퍼티 시트. 인스톨되어 있는 OpenRTM-aist에 의존하는 파일이기 때문에 copyprops.bat을 사용해서 OpenRTM의 시스템 디렉토리에서 현재의 프로젝트로 복사합니다.
  • user_config.vsprops:유저 정의의 프로퍼티 시트. 디폴트로는 비어 있습니다. 사용 방법은 소스 코드:OpenRTM-aist/win32/OpenRTM-aist/example/USBCamera의 안에 들어있는 user_config.vsprops (OpenCV용의 설정)을 참고해 주십시오.

이하의 내용을 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="&quot;$(cv_root)\include\opencv&quot;"
     />
     <UserMacro
         Name="cv_libdir"
         Value="&quot;$(cv_root)\lib&quot;"
     />
     <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++로 빌드하기 위해 필요한 인클루드 경로나 링크하는 라이브러리 등이 기술되어 있는 파일입니다.

헤더 파일의 편집

  • OpenCV의 라이브러리를 사용하기 위해 OpenCV의 인클루드 파일을 인클루드 합니다.

 //OpenCV용 인클루드 파일
 #include<cv.h>
 #include<cxcore.h>
 #include<highgui.h>

  • 이 cvFlip컴포넌트는 화상 영역을 확보, Flip처리, 확보한 화상 영역의 해제 각각의 처리를 합니다. 이러한 처리는 각각 onActivated(), onDeactivated(), onExecute()의 콜백 함수에서 실행합니다.

   /***
    *
    * 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컴포넌트의 패키지

구현된 패키지를 아래의 링크에서 다운로드할 수 있습니다.

확장자가 "zip_"으로 되어있기 때문에 "zip"으로 리네임한 뒤 압축을 해재해 주십시오.

빌드의 실행

Flip_vc9.sln파일을 더블 클릭해 Visual C++ 2008을 기동합니다.

Visual C++ 2008의 기동후 그림 21와 같이 컴포넌트를 빌드합니다.


VC++_build_ko.png
''그림 21. 빌드


Flip컴포넌트의 기동 확인

여기에서는 「OpenCV용 RTC군(Win32용 인스톨러)」에서 인스톨한 USBCameraAqcuireComp 컴포넌트와 USBCameraMonitorCom 컴포넌트 그리고 이번에 작성한 Flip 컴포넌트를 접속해 동작을 확인합니다.

NameService의 기동

omniORB의 네임 서비스를 기동합니다.


[시작] > [모든 프로그램] > [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개의 컴포넌트는 이하의 순서로 기동시켜 주십시오.

[시작] > [모든 프로그램] > [OpenRTM-aist] > [components] > [C++] > [OpenCV] 의 순서로 「USBCameraAqcuireComp」와「USBCameraMonitorComp」를 각각 클릭해 실행합니다.

컴포넌트의 연결

그림 22와 같이 RTSystemEditor에서 USBCameraAqcuireComp, Flip, USBCameraMonitorComp 컴포넌트를 연결합니다.


RTSE_Connect.png
그림 22. 컴포넌트의 연결


컴포넌트의 Activate

RTSystemEditor의 상부에 있는 「ALL」이라는 아이콘을 클릭해 모든 컴포넌트를 액티베이트 합니다.

정상적으로 액티베이트된 경우 그림 23과 같이 녹색으로 컴포넌트가 표시됩니다.


RTSE_Activate.png
그림 23. 컴포넌트의 액티베이트


동작 확인

그림 24와 같이 컨피그레이션 뷰에서 컨피그레이션을 변경할 수 있습니다.

Flip 컴포넌트의 컨피그레이션 파라메터 「flipMode」을 「0」이나「-1」등으로 변경해 화상이 반전되는지 확인해 주십시오.


RTSE_Configuration.png
그림 24. 컨피그레이션 파라메터의 변경


다른 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상에서 기동되어 있는 네임 서버에의 접속


RTSE0.png
그림 25. 네임 서버에의 접속

그림 25의 상부에 있는 콘센트 마크의 버튼을 눌러 그림 26의 다이얼로그에서 다른 PC의 IP주소를 입력합니다.


RTSE1.png
그림 26. 네임 서버의 입력

컴포넌트의 연결

다른 PC상의 네임 서버에 등록되어 있는 USBCameraAcquire 컴포넌트와 localhost네임 서버상에 등록되어 있는 USBCameraMonitor 컴포넌트를 시스템 에디터 상에 드래그 앤 드롭합니다.
다음에 USBCameraAcquire의 OutPort와 USBCameraMonitor의 InPort를 그림 27과 같이 연결합니다.


RTSE2.png
그림 27. 포트의 연결

컴포넌트의 액티베이트

그림 28과 같이 USBCameraMonitor에서 마우스 오른쪽 버튼을 클릭해 "Activate"를 클릭합니다.


RTSE3.png
그림 28. 컴포넌트의 액티베이트

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

덤 (물체추적 컴포넌트)

OpenCV의 라이브러리를 이용하고, 물체 추적을 실시하는 컴퍼넌트입니다.

컴퍼넌트의 개요

InPort로부터의 화상 데이터를 표시해, 마우스로 선택된 오브젝트를 추적하는 컴퍼넌트.

OutPort에서는, 물체 추적 화상과 마우스로 선택한 위치로부터의 이동량을 출력한다.

화상의 사이즈와 명도, 채도는 configuration에서 변경 가능.

작성하는 RTC의 사양은 이하대로입니다.

  • InPort
    • 캡쳐 된 화상 데이터(TimedOctetSeq)
  • OutPort
    • 물체 추적 화상 데이터(TimedOctetSeq)
  • OutPort
    • 마우스로 선택한 오브젝트의 중심 위치의 이동량(TimedFloatSeq)
  • Configuration
    • 명도의 최대치(int) default: 256
    • 명도의 최소치(int) default: 10
    • 채도의 최소치(int) default: 30
    • 화상의 높이(int) default: 240
    • 화상의 폭(int) default: 320

RTCBuilder로의 프로파일 정보 입력 내용

기본 정보

  • Module name: ObjectTracking
  • Module description: Object tracking component
  • OutputProject: ObjectTracking

    데이터포트


  • InPort Profile:
    • Port Name: in_image
    • Data Type: TimedOctetSeq
    • Var Name: in_image
    • Disp. Position: left
  • OutPort Profile:
    • Port Name: tracing_image
    • Data Type: TimedOctetSeq
    • Var Name: tracking_image
    • Disp. Position: right
  • OutPort Profile:
    • Port Name: displacement
    • Data Type: TimedOctetSeq
    • Var Name: displacement
    • Disp. Position: right

컨피귤레이션 파라미터


  • brightness_max
    • Name: brightness_max
    • TYpe: int
    • Default Value: 256
    • 변수명: b_max

  • brightness_min
    • Name: brightness_min
    • TYpe: int
    • Default Value: 10
    • 변수명: b_min

  • saturation_min
    • Name: saturation_min
    • TYpe: int
    • Default Value: 30
    • 변수명: s_min

  • image_height
    • Name: image_height
    • TYpe: int
    • Default Value: 240
    • 변수명: img_height

  • image_width
    • Name: image_width
    • TYpe: int
    • Default Value: 320
    • 변수명: img_width

      ObjectTracking 컴퍼넌트의 원시 파일

 // -*- C++ -*-
 /*!
  * @file  ObjectTracking.cpp
  * @brief Object tracking component
  * @date $Date$
  *
  * $Id$
  */
 
 #include "ObjectTracking.h"
 
 #define HIST_RANGE_MAX 180.0
 #define HIST_RANGE_MIN 0.0
 
 // 입력 화상용 IplImage
 IplImage* g_image;
 
 // CamShift 트랙킹용 변수
 CvPoint g_origin;
 CvRect g_selection;  // 
 
 // 초기 추적 영역의 설정 판별 플래그치 (0: 설정 이루어, 1: 설정 있어)
 int g_select_object;
 
 // 트랙킹의 개시/정지용 플래그치 (0: 정지, -1: 개시, 1: 트랙킹중)
 int g_track_object;
 
 // 오브젝트 선택 판정용 플래그(0: 1이외 1: 선택된 직후)
 int g_selected_flag;
 
 // 선택된 범위의 중심 좌표
 float g_selected_x;
 float g_selected_y;
 
 
 // Module specification
 static const char* objecttracking_spec[] =
   {
     "implementation_id", "ObjectTracking",
     "type_name",         "ObjectTracking",
     "description",       "Object tracking component",
     "version",           "1.0.0",
     "vendor",            "AIST",
     "category",          "Category",
     "activity_type",     "PERIODIC",
     "kind",              "DataFlowComponent",
     "max_instance",      "1",
     "language",          "C++",
     "lang_type",         "compile",
     "exec_cxt.periodic.rate", "1.0",
     // Configuration variables
     "conf.default.brightness_max", "256",
     "conf.default.brightness_min", "10",
     "conf.default.saturation_min", "30",
     "conf.default.image_height", "240",
     "conf.default.image_width", "320",
     ""
   };
 
 /*!
  * @brief constructor
  * @param manager Maneger Object
  */
 ObjectTracking::ObjectTracking(RTC::Manager* manager)
   : RTC::DataFlowComponentBase(manager),
     m_in_imageIn("in_image", m_in_image),
     m_tracking_imageOut("tracing_image", m_tracking_image),
     m_displacementOut("displacement", m_displacement),
     dummy(0),
     m_hsv(0), m_hue(0), m_mask(0), m_backproject(0),
     m_hist(0), m_backproject_mode(0),m_hdims(16),
     m_init_flag(0)
 {
   // Registration: InPort/OutPort/Service
   // Set InPort buffers
   registerInPort("in_image", m_in_imageIn);
   
   // Set OutPort buffer
   registerOutPort("tracing_image", m_tracking_imageOut);
   registerOutPort("displacement", m_displacementOut);
 
   m_hranges_arr[0] = HIST_RANGE_MIN;
   m_hranges_arr[1] = HIST_RANGE_MAX;
   m_hranges = m_hranges_arr;
 }
 
 /*!
  * @brief destructor
  */
 ObjectTracking::~ObjectTracking()
 {
 }
 
 
 
 RTC::ReturnCode_t ObjectTracking::onInitialize()
 {
   // Bind variables and configuration variable
   bindParameter("brightness_max", m_b_max, "256");
   bindParameter("brightness_min", m_b_min, "10");
   bindParameter("saturation_min", m_s_min, "30");
   bindParameter("image_height", m_img_height, "240");
   bindParameter("image_width", m_img_width, "320");
   m_displacement.data.length(2);
   return RTC::RTC_OK;
 }
 
 
 RTC::ReturnCode_t ObjectTracking::onActivated(RTC::UniqueId ec_id)
 {
   m_init_flag = 0;
   // 윈도우를 생성한다
   cvNamedWindow( "ObjectTracking", 1 );
   // 마우스 조작시의 콜백 처리의 등록
   cvSetMouseCallback( "ObjectTracking", on_mouse, 0 );
   g_selected_flag = 0;
   g_selected_x = 0.0;;
   g_selected_y = 0.0;;
 
   return RTC::RTC_OK;
 }
 
 
 RTC::ReturnCode_t ObjectTracking::onDeactivated(RTC::UniqueId ec_id)
 {
   if (m_init_flag) {
     // 메모리를 해방한다
     cvReleaseImage(&g_image);
     cvReleaseImage(&m_hsv);
     cvReleaseImage(&m_hue);
     cvReleaseImage(&m_mask);
     cvReleaseImage(&m_backproject);
   }
   // 윈도우를 파기한다
   cvDestroyWindow("ObjectTracking");
   m_init_flag = 0;
   return RTC::RTC_OK;
 }
 
 
 RTC::ReturnCode_t ObjectTracking::onExecute(RTC::UniqueId ec_id)
 {
   if (m_in_imageIn.isNew()) {
     m_in_imageIn.read();
 
     if(!m_init_flag) allocateBuffers();
 
     memcpy(g_image->imageData,(void *)&(m_in_image.data[0]),m_in_image.data.length());
     cvShowImage("ObjectTracking", g_image);
 
     // 캡쳐 된 화상을 HSV표색계로 변환해 hsv에 격납
     cvCvtColor( g_image, m_hsv, CV_BGR2HSV );
 
     // g_track_object 플래그가 0 이하라면, 이하의 처리를 실시한다
     if( g_track_object )
       {
     cvInRangeS( m_hsv, cvScalar(HIST_RANGE_MIN,m_s_min,MIN(m_b_min,m_b_max),0),
             cvScalar(HIST_RANGE_MAX,256,MAX(m_b_min,m_b_max),0), m_mask );
     cvSplit( m_hsv, m_hue, 0, 0, 0 );
 
     if( g_track_object < 0 ) calcHistogram();
 
     // 백 프로젝션을 계산한다
     cvCalcBackProject( &m_hue, m_backproject, m_hist );
     // backProjection 가운데, 마스크가 1이라고 된 부분만 남긴다
     cvAnd( m_backproject, m_mask, m_backproject, 0 );
     // CamShift법에 따르는 영역 추적을 실행한다
     cvCamShift( m_backproject, m_track_window,
             cvTermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ),
             &m_track_comp, &m_track_box );
     m_track_window = m_track_comp.rect;
     
     if( m_backproject_mode )
       cvCvtColor( m_backproject, g_image, CV_GRAY2BGR );
     if( g_image->origin )
       m_track_box.angle = -m_track_box.angle;
     cvEllipseBox( g_image, m_track_box, CV_RGB(255,0,0), 3, CV_AA, 0 );
 
     // 마우스로 선택된 영역의 중심 좌표를 보존
     if (g_selected_flag) {
       g_selected_x = m_track_box.center.x;
       g_selected_y = m_track_box.center.y;
       g_selected_flag = 0;
     }
 
     // 마우스로 선택된 위치로부터의 이동량을 OutPort로부터 출력
     m_displacement.data[0] = m_track_box.center.x - g_selected_x;
     m_displacement.data[1] = -(m_track_box.center.y - g_selected_y);
     m_displacementOut.write();
       }
         
     // 마우스로 선택중의 초기 추적 영역의 색을 반전시킨다
     if( g_select_object && g_selection.width > 0 && g_selection.height > 0 )
       {
     cvSetImageROI( g_image, g_selection );
     cvXorS( g_image, cvScalarAll(255), g_image, 0 );
     cvResetImageROI( g_image );
       }
 
     // 화상을 표시한다
     cvShowImage( "ObjectTracking", g_image );
 
     // 화상을 OutPort로부터 출력한다
     int len = g_image->nChannels * g_image->width * g_image->height;
     m_tracking_image.data.length(len);
     memcpy((void *)&(m_tracking_image.data[0]),g_image->imageData,len);
     m_tracking_imageOut.write();
 
     // 키 입력을 기다려, 밀린 키에 의해서 처리를 분기 시킨다
     int c = cvWaitKey(10);
     // while 엔들레스 루프로부터 탈출(프로그램을 종료)
     if( (char) c == 27 ) {
       this->exit();
     }
   }
   return RTC::RTC_OK;
 }
 
 /*!
  * 모든 이미지용 메모리의 확보
  */
 void ObjectTracking::allocateBuffers() {
   g_image = cvCreateImage( cvSize(m_img_width,m_img_height),8, 3 );
   m_hsv = cvCreateImage( cvSize(m_img_width,m_img_height),8, 3 );
   m_hue = cvCreateImage( cvSize(m_img_width,m_img_height),8, 1 );
   m_mask = cvCreateImage( cvSize(m_img_width,m_img_height),8, 1 );
   m_backproject = cvCreateImage( cvSize(m_img_width,m_img_height),8, 1 );
   m_hist = cvCreateHist( 1, &m_hdims, CV_HIST_ARRAY, &m_hranges, 1 );
   m_init_flag = 1;
 }
 
 /*!
  * 히스토그램의 계산
  */
 void ObjectTracking::calcHistogram() {
   float max_val = 0.f;
   cvSetImageROI( m_hue, g_selection );
   cvSetImageROI( m_mask, g_selection );
   // 히스토그램을 계산해, 최대치를 요구한다
   cvCalcHist( &m_hue, m_hist, 0, m_mask );
   cvGetMinMaxHistValue( m_hist, 0, &max_val, 0, 0 );
   // 히스토그램의 세로축(빈도)을0-255의 다이나믹 레인지에 정규화
   cvConvertScale( m_hist->bins, m_hist->bins, max_val ? 255. / max_val : 0., 0 );
   // hue,mask 화상으로 설정된 ROI를 리셋트
   cvResetImageROI( m_hue );
   cvResetImageROI( m_mask );
   m_track_window = g_selection;
   // track_object를 트랙킹중으로 한다
   g_track_object = 1;
 }
 
 
 extern "C"
 {
  
   void ObjectTrackingInit(RTC::Manager* manager)
   {
     RTC::Properties profile(objecttracking_spec);
     manager->registerFactory(profile,
                              RTC::Create<ObjectTracking>,
                              RTC::Delete<ObjectTracking>);
   }
   
 
   //
   //    마우스 드러그에 의해서 초기 추적 영역을 지정한다
   //
   //    인수:
   //        event    : 마우스왼쪽 버튼 상태
   //        x        : 마우스가 현재 포인트 하고 있는 x좌표
   //        y        : 마우스가 현재 포인트 하고 있는 y좌표
   //        flags    : 본프로그램에서는 미사용
   //        param    : 본프로그램에서는 미사용
   //
   void on_mouse( int event, int x, int y, int flags, void* param )
   {
     // 화상이 취득되어 있지 않으면, 처리를 실시하지 않는다
     if( !g_image )
       return;
 
     // 원점의 위치에 따라 y의 값을 반전(화상의 반전은 아니다)
     if( g_image->origin )
       y = g_image->height - y;
 
     // 마우스의 왼쪽 버튼이 밀리고 있으면 이하의 처리를 실시한다
     if( g_select_object )
       {
     g_selection.x = MIN(x,g_origin.x);
     g_selection.y = MIN(y,g_origin.y);
     g_selection.width = g_selection.x + CV_IABS(x - g_origin.x);
     g_selection.height = g_selection.y + CV_IABS(y - g_origin.y);
         
     g_selection.x = MAX( g_selection.x, 0 );
     g_selection.y = MAX( g_selection.y, 0 );
     g_selection.width = MIN( g_selection.width, g_image->width );
     g_selection.height = MIN( g_selection.height, g_image->height );
     g_selection.width -= g_selection.x;
     g_selection.height -= g_selection.y;
       }
 
     // 마우스의 왼쪽 버튼 상태에 의해서 처리를 분기
     switch( event )
       {
       case CV_EVENT_LBUTTONDOWN:
     // 마우스의 왼쪽 버튼이 밀린 것이면,
     // 원점 및 선택된 영역을 설정
     g_origin = cvPoint(x,y);
     g_selection = cvRect(x,y,0,0);
     g_select_object = 1;
     break;
       case CV_EVENT_LBUTTONUP:
     // 마우스의 왼쪽 버튼이 떼어 놓아졌을 때, width와 height가 어느쪽이나 정이면,
     // g_track_object 플래그를 개시 플래그로 한다
     g_select_object = 0;
     if( g_selection.width > 0 && g_selection.height > 0 ) {
       g_track_object = -1;
       g_selected_flag = 1;
     }
     break;
       }
   }
 
 };

ObjectTracking 컴퍼넌트의 헤더 파일

 // -*- C++ -*-
 /*!
  * @file  ObjectTracking.h
  * @brief Object tracking component
  * @date  $Date$
  *
  * $Id$
  */
 
 #ifndef OBJECTTRACKING_H
 #define OBJECTTRACKING_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 <cv.h>
 #include <highgui.h>
 #include <stdio.h>
 #include <ctype.h>
 
 
 using namespace RTC;
 
 /*!
  * @class ObjectTracking
  * @brief Object tracking component
  *
  */
 class ObjectTracking
   : public RTC::DataFlowComponentBase
 {
  public:
   /*!
    * @brief constructor
    * @param manager Maneger Object
    */
   ObjectTracking(RTC::Manager* manager);
 
   /*!
    * @brief destructor
    */
   ~ObjectTracking();
 
   /*!
    *
    * 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);
 
 
   /*!
    *    입력된 1개의 색상치를 RGB로 변환한다
    *
    *    인수:
    *        hue        : HSV표색계에 있어서의 색상치 H
    *    반환값:
    *        CvScalar: RGB의 색정보가 BGR의 순서로 격납된 컨테이너
    */
   CvScalar hsv2rgb( float hue ) {
     int rgb[3], p, sector;
     static const int sector_data[][3]=
       {{0,2,1}, {1,2,0}, {1,0,2}, {2,0,1}, {2,1,0}, {0,1,2}};
     hue *= 0.033333333333333333333333333333333f;
     sector = cvFloor(hue);
     p = cvRound(255*(hue - sector));
     p ^= sector & 1 ? 255 : 0;
 
     rgb[sector_data[sector][0]] = 255;
     rgb[sector_data[sector][1]] = 0;
     rgb[sector_data[sector][2]] = p;
     
     return cvScalar(rgb[2], rgb[1], rgb[0],0);
   }
   
 
   /*!
    * 모든 이미지용 버퍼의 확보
    */
   void allocateBuffers();
 
   /*!
    * 히스토그램의 계산
    */
   void calcHistogram();
 
  protected:
   // Configuration variable declaration
   /*!
    * 
    * - Name:  b_max
    * - DefaultValue: 256
    * - 명도의 최대치
    */
   int m_b_max;
   /*!
    * 
    * - Name:  b_min
    * - DefaultValue: 10
    * - 명도의 최소치 
    */
   int m_b_min;
   /*!
    * 
    * - Name:  s_min
    * - DefaultValue: 30
    * - 채도의 최소치
    */
   int m_s_min;
   /*!
    * 
    * - Name:  m_img_height
    * - DefaultValue: 240
    * - 화상의 높이
    */
   int m_img_height;
   /*!
    * 
    * - Name:  m_img_width
    * - DefaultValue: 320
    * - 화상의 폭
    */
   int m_img_width;
 
   // DataInPort declaration
   TimedOctetSeq m_in_image;
   InPort<TimedOctetSeq> m_in_imageIn;
   
   // DataOutPort declaration
   TimedOctetSeq m_tracking_image;
   OutPort<TimedOctetSeq> m_tracking_imageOut;
 
   TimedFloatSeq m_displacement;
   OutPort<TimedFloatSeq> m_displacementOut;
 
  private:
   int dummy;
   IplImage* m_hsv;         // HSV표색계용 IplImage
   IplImage* m_hue;         // HSV표색계의 H채널용 IplImage
   IplImage* m_mask;        // 마스크 화상용 IplImage
IplImage* m_backproject; // 백 프로젝션 화상용 IplImage
 
   CvHistogram * m_hist; // 히스토그램 처리용 구조체
 
   // 처리 모드 선택용 플래그
   int m_backproject_mode; // 백 프로젝션 화상의 표시/비표시용 플래그치 (0: 비표시, 1: 표시)
 
   // CamShift 트랙킹용 변수
   CvRect m_track_window;
   CvBox2D m_track_box;
   CvConnectedComp m_track_comp;
 
   // 히스토그램용 변수
   int m_hdims;                // 히스토그램의 차원수
   float m_hranges_arr[2]; // 히스토그램의 레인지
   float* m_hranges;
 
   // 초기화 판정 플래그
   int m_init_flag;
 };
 
 
 
 extern "C"
 {
   void ObjectTrackingInit(RTC::Manager* manager);
   void on_mouse( int event, int x, int y, int flags, void* param );
 };
 
 #endif // OBJECTTRACKING_H

컴퍼넌트의 접속

그림 25는, USBCameraAcquire,Flip,ObjectTracking,SeqIn 컴퍼넌트의 접속예입니다.

우선, USBCameraAcquire 컴퍼넌트에서 USB 카메라의 화상을 취득합니다.

다음에, Flip 컴퍼넌트에서 좌우를 반전시킵니다.

반전시키고 있는 이유는, 물체 추적 컴퍼넌트의 출력을 죠이스틱으로서 사용하는 경우에, 화상이 거울과 같이 표시되고 있는 것이 조작하기 쉽기 때문입니다.

다음에, ObjectTracking 컴퍼넌트로, 미리 선택된 추적 대상물의 이동량을 OutPort(displacement)로부터 출력해, SeqIn 컴퍼넌트로 이동량을 표시합니다.


RTSystemEditor_connection.png
그림 25. 컴퍼넌트의 접속예


ObjectTracking 컴퍼넌트의 빌드가 끝난 패키지

빌드가 끝난 패키지를 아래와 같이로부터 다운로드할 수 있습니다.

확장자(extension)를"zip_"로 해 있기 때문에,"zip"에 rename 하고 나서 해동해 주세요.