NtKinectDLL: Dynamic Linking Library with NtKinect

How to Compile


2017.08.19: created by
Japanese English
目次へ

前提条件

次のソフトウェアがインストールされていることを前提条件とします。インストールのパスが異なる場合は適宜読み替えて下さい。


プログラムのDLL化

今まで説明してきたのはKinect V2の機能を使う DLL ファイルの作り方でした。 利便性を考えて、NtKinect の機能をフルにDLL化したライブラリを作成しておきます。

NtKinectを利用して OpenCV や Kinect V2 を使う DLL ファイルを作成してみましょう。 Visual Studio Proefssional 2017 では C++ で DLL を作成するプロジェクトのテンプレートが用意されています。

  1. ファイル -> 新規作成 -> プロジェクト-> Visual C++ ->Windows -> Win32 -> Win32コンソールアプリケーション を選択します。
  2. OK -> 次へ を選択して「アプリケーションの設定」へ

  3. 「アプリケーションの設定」で「アプリケーションの種類」を「DLL」に, 追加のオプションの「シンボルのエクスポート」をチェックします。 Visual Studio 2015 Professional のように、ここに 「Security Development Lifecycle(SDL)のチェック」の項目があった場合は、チェックをはずしておきます。
  4. Visual Studio のウィンドウの上部メニューの "x86" を "x64" に変更して、64bitアプリケーションを作るように設定します。また、実行が高速になるように "Debug" を "Release" に変更します。
  5. 関数の宣言をヘッダファイルに記述します。
  6. 変数、関数、クラスの記述例が既に挿入されていますので、それを参考に記述します。 宣言の先頭につける "大文字のプロジェクト名_API" (この場合だと "NTKINECTDLL_API" になります) はここで定義されています。

  7. 関数は"プロジェクト名.cpp"に記述します。
  8. 変数、関数、クラスの記述例が既に挿入されていますので、それを参考に記述します。 例からわかるように、宣言の先頭に "大文字のプロジェクト名_API" (この場合だと "NTKINECTDLL_API" になります) を記述する必要があります。 これは NtKinectDLL.h の中で定義されているマクロで、 DLL から export したり import したりする場合を区別せずに記述するために使います。

  9. 「アプリケーションの構成」を "Release"にしてコンパイルします(ビルドするだけです。実行はしません)。 プロジェクト直下のフォルダ NtKinectDLL/x64/Release に.lib ファイルと .dll ファイルが生成されます。

ダイナミック・リンキング・ライブラリ NtKinectDLL のコンパイル手順

NtKinect の機能の大部分を利用できるDLL ライブラリを作成します。 この DLLライブラリは NtKinect のほとんどの関数を呼び出せるようにするのが目標です。

  1. ファイル -> 新規作成 -> プロジェクト-> Visual C++ ->Windows -> Win32 -> Win32コンソールアプリケーション を選択します。
  2. 名前はここでは NtKinectDLL とします。ソリューション名も自動的に NtKinectDLL となります。 OK -> 次へ を選択して「アプリケーションの設定」へ




  3. 「アプリケーションの設定」で「アプリケーションの種類」を「DLL」に, 追加のオプションの「シンボルのエクスポート」をチェックします。 Visual Studio 2015 Professional のように、ここに 「Security Development Lifecycle(SDL)のチェック」の項目があった場合は、チェックをはずしておきます。



  4. Visual Studio のソリューションエクスプローラーは次のように表示されているはずです。



  5. Visual Studio のウィンドウの上部メニューの "x86" を "x64" に変更して、64bitアプリケーションを作るように設定します。また、実行が高速になるように実行モードを "Debug" を "Release" に変更しておきます



  6. プロジェクトのプロパティからインクルードファイルやライブラリに関する設定を行う。
    1. ソリューションエクスプローラでプロジェクト名の上で右ドラッグして「プロパティ」を選択します。



    2. 構成:「すべての構成」, プラットフォーム 「アクティブ(x64)」の状態で設定を行います。こうすることによってDebugおよびReleaseのどちらの設定ができます。もちろん、別々に設定しても構いません。
    3. インクルードファイルの場所を追加します。
    4. 「構成プロパティ」 -> 「C/C++」 -> 全般 -> 追加のインクルードディレクトリ

        $(KINECTSDK20_DIR)inc
        C:\opencv\include
        D:\opencv\include



    5. ライブラリの場所を追加します。
    6. 「構成プロパティ」 -> 「リンカー」 -> 全般 -> 追加のライブラリディレクトリ

        $(KINECTSDK20_DIR)Lib\x64
        C:\opencv\lib
        D:\opencv\lib



    7. リンクするライブラリを追加します。
    8. 「構成プロパティ」 -> 「リンカー」 -> 全般 -> 入力

        Kinect20.lib
        Kinect20.Face.lib
        Kinect20.VisualGestureBuilder.lib
        opencv_world330.lib



    9. 「適用」をクリックしてから「OK」をクリックします。
  7. (重要)プロジェクトのヘッダーファイルに NtKinect.h ( this site, github ) を追加します。
  8. 上記のリンクから NtKinect.h をダウンロードして下さい。 dllmain.cpp などプロジェクトのソースが置かれているフォルダ(この例だと NtKinectDLL/NtKinectDLL)に NtKinect.h を配置してから、 「ソリューションエクスプローラ」の「ヘッダーファイル」の上で右クリックで 「追加」 -> 「既存の項目」 -> NtKinect.h を選択します。










  9. プロジェクトのヘッダーファイルに WaveFile.h を少し変更したもの を追加します。
  10. Microsoft が配布している AudioCaptureRaw-Console C++ Sample の WaveFile.h を少し変更したものをプロジェクトに加えます。 上記のリンクから WaveFile.h をダウンロードして下さい。 dllmain.cpp などプロジェクトのソースが置かれているフォルダ(この例だと NtKinectDLL/NtKinectDLL)に WaveFile.h を配置してから、 「ソリューションエクスプローラ」の「ヘッダーファイル」の上で右クリックで 「追加」 -> 「既存の項目」 -> WaveFile.h を選択します。










  11. 宣言をヘッダファイルに記述します。ヘッダファイルの名前は"プロジェクト名.h"で、この場合は "NtKinectDLL.h" になります。
  12. 緑文字の部分がプロジェクトを作成した時から定義されているDLLのimport/exportに関する部分です。 NtKinectDLL.hはこのプロジェクト内ではexport用の宣言となり、他のプロジェクトに読み込まれたときは import用の宣言となります。

    NtKinectDLL.h
    /*
    * Copyright (c) 2017 Yoshihisa Nitta
    * Released under the MIT license
    * http://opensource.org/licenses/mit-license.php
    */
    
    /*
    * NtKinectDLL.h version 1.2.6: 2017/11/08
    * http://nw.tsuda.ac.jp/lec/kinect2/NtKinectDLL
    *
    * requires:
    *    NtKinect version 1.8.2 and later
    */
    
    #ifdef NTKINECTDLL_EXPORTS
    #define NTKINECTDLL_API __declspec(dllexport)
    #else
    #define NTKINECTDLL_API __declspec(dllimport)
    #endif
    
    namespace NtKinectDLL {
      extern "C" {
        NTKINECTDLL_API void* getKinect(void);
        NTKINECTDLL_API void stopKinect(void* ptr);
    
        // OpenCV
        NTKINECTDLL_API void imshow(void* ptr);
        NTKINECTDLL_API void imshowBlack(void* ptr);
    
        // CoordinateMapper
        /*
          NTKINECTDLL_API void mapCameraPointToColorSpace(void* ptr,void* sv,void* cv);
          NTKINECTDLL_API void mapCameraPointToDepthSpace(void* ptr,void* sv,void* dv);
          NTKINECTDLL_API void mapDepthPointToColorSpace(void* ptr,void* dv,UINT16 depth,void* cv);
          NTKINECTDLL_API void mapDepthPointToCameraSpace(void* ptr,void* dv,UINT16 depth,void* sv);
        */
        NTKINECTDLL_API void mapCameraPointToColorSpace(void* ptr, void* sv, void* cv, int n);
        NTKINECTDLL_API void mapCameraPointToDepthSpace(void* ptr, void* sv, void* dv, int n);
        NTKINECTDLL_API void mapDepthPointToColorSpace(void* ptr, void* dv, void* dth, void* cv, int n);
        NTKINECTDLL_API void mapDepthPointToCameraSpace(void* ptr, void* dv, void* dth, void* sv, int n);
    
        // Multi Thread
        NTKINECTDLL_API void acquire(void* ptr);
        NTKINECTDLL_API void release(void* ptr);
    
        // Audio
        NTKINECTDLL_API void setAudio(void* ptr, bool flag);
        NTKINECTDLL_API float getBeamAngle(void* ptr);
        NTKINECTDLL_API float getBeamAngleConfidence(void* ptr);
        NTKINECTDLL_API unsigned __int64 getAudioTrackingId(void* ptr);
        NTKINECTDLL_API void openAudio(void* ptr, wchar_t* filename);
        NTKINECTDLL_API void closeAudio(void* ptr);
        NTKINECTDLL_API bool isOpenedAudio(void* ptr);
    
        // RGB
        NTKINECTDLL_API void setRGB(void* ptr);
        NTKINECTDLL_API int getRGB(void* ptr, void* data);
    
        // Depth
        NTKINECTDLL_API void setDepth(void* ptr);
        NTKINECTDLL_API int getDepth(void* ptr, void* data);
    
        // Infrared
        NTKINECTDLL_API void setInfrared(void* ptr);
        NTKINECTDLL_API int getInfrared(void* ptr, void* data);
    
        // BodyIndex
        NTKINECTDLL_API void setBodyIndex(void* ptr);
        NTKINECTDLL_API int getBodyIndex(void* ptr, void* data);
    
        // Skeleton
        NTKINECTDLL_API void setSkeleton(void* ptr);
        NTKINECTDLL_API int getSkeleton(void* ptr, void* skelton, void* state, void* id, void* tid);
        NTKINECTDLL_API int handState(void* ptr, int id, bool isLeft);
    
        // Face
        NTKINECTDLL_API void setFace(void* ptr, bool flag);
        NTKINECTDLL_API int getFace(void* ptr, float* point, float* rect, float* direction, int* property, void* tid);
    
        // HDFace
        NTKINECTDLL_API void setHDFace(void* ptr);
        NTKINECTDLL_API int getHDFace(void* ptr, float* point, void* tid, int *status);
    
        // Gesture
        NTKINECTDLL_API void setGestureFile(void* ptr, wchar_t* filename);
        NTKINECTDLL_API int setGestureId(void* ptr, wchar_t* name, int id); // id: non-zero
        NTKINECTDLL_API void setGesture(void* ptr);
        NTKINECTDLL_API int getDiscreteGesture(void* ptr, int* gid, float* confidence, void* tid);
        NTKINECTDLL_API int getContinuousGesture(void* ptr, int* gid, float* progress, void* tid);
        NTKINECTDLL_API int getGidMapSize();
    
        // Video
        NTKINECTDLL_API void openVideo(void* ptr, wchar_t* filename);
        NTKINECTDLL_API void writeVideo(void* ptr);
        NTKINECTDLL_API void closeVideo(void* ptr);
      }
    
      //Gesture
      std::unordered_map<std::string, int> gidMap;
    }
    
  13. 関数は"プロジェクト名.cpp"に記述します。この例だと NtKinectDLL.cpp になります。
  14. 関数宣言の先頭に "NTKINECTDLL_API" を記述する必要があります。 これは NtKinectDLL.h の中で定義されているマクロで、DLLからのexport/import を容易にするものです。

    DLLの中ではオブジェクトはヒープに確保する必要があります。 そのため void* getKinect()関数では NtKinectを new してそのポインタを(void *)にキャストして返しています。

    DLLの関数を実行するときは、ヒープ上のNtKinectオブジェクトのポインタを渡してもらい、 (void *)型のポインタから (NtKinect *)型のポインタに変更してNtKinect の機能を利用します。 下の例では関数中では kinect 変数は (NtKinect *)型のポインタになるので、 たとえば rgbImage というメンバ変数へのアクセスは (*kinect).rgbImage と記述します。

    rgb画像を表示する imshow() 関数では、 カメラで取得した画像を1/16に縮小してその上に関節を赤で描画しcv::imshow()で表示しています。 ウィンドウの内容を正しく表示させるためにはcv::waitKey(1)を呼び出す必要があります。

    NtKinectDLL.cpp
    /*
     * Copyright (c) 2017 Yoshihisa Nitta
     * Released under the MIT license
     * http://opensource.org/licenses/mit-license.php
     */
    
    /*
     * NtKinectDLL.h version 1.2.6: 2017/11/08
     * http://nw.tsuda.ac.jp/lec/kinect2/NtKinectDLL
     *
     * requires:
     *    NtKinect version 1.8.2 and after
     */
    
    #include "stdafx.h"
    #include <unordered_map>
    #ifndef NTKINECTDLL_EXPORTS
    #define NTKINECTDLL_EXPORTS   // cheap trick to avoid DLL Compiling Bug of "Visual Studio 2017 Update 2"
    #endif
    #include "NtKinectDLL.h"
    
    #define USE_AUDIO
    #define USE_FACE
    #define USE_GESTURE
    #define USE_THREAD
    #include "NtKinect.h"
    
    using namespace std;
    
    namespace NtKinectDLL {
      string wchar2string(wchar_t* name) {
        int len = WideCharToMultiByte(CP_UTF8, NULL, name, -1, NULL, 0, NULL, NULL) + 1;
        char* nameBuffer = new char[len];
        memset(nameBuffer, '\0', len);
        WideCharToMultiByte(CP_UTF8, NULL, name, -1, nameBuffer, len, NULL, NULL);
        string s(nameBuffer);
        return s;
      }
    
      NTKINECTDLL_API void* getKinect(void) {
        NtKinect* kinect = new NtKinect();
        return static_cast<void*>(kinect);
      }
      NTKINECTDLL_API void stopKinect(void* ptr) {
        cv::destroyAllWindows();
        NtKinect* kinect = static_cast<NtKinect*>(ptr);
        delete kinect;
      }
    
      // OpenCV
      NTKINECTDLL_API void imshow(void* ptr) {
        NtKinect* kinect = static_cast<NtKinect*>(ptr);
        int scale = 4;
        cv::Mat img((*kinect).rgbImage);
        cv::resize(img, img, cv::Size(img.cols / scale, img.rows / scale), 0, 0);
        for (auto& person : (*kinect).skeleton) {
          for (auto& joint : person) {
    	if (joint.TrackingState == TrackingState_NotTracked) continue;
    	ColorSpacePoint cp;
    	(*kinect).coordinateMapper->MapCameraPointToColorSpace(joint.Position, &cp);
    	cv::rectangle(img, cv::Rect((int)cp.X / scale - 2, (int)cp.Y / scale - 2, 4, 4), cv::Scalar(0, 0, 255), 2);
          }
        }
        for (auto r : (*kinect).faceRect) {
          cv::Rect r2(r.x / scale, r.y / scale, r.width / scale, r.height / scale);
          cv::rectangle(img, r2, cv::Scalar(255, 255, 0), 2);
        }
        cv::imshow("face", img);
        cv::waitKey(1);
      }
    
      vector<cv::Rect> savedRect;
      NTKINECTDLL_API void imshowBlack(void* ptr) {
        NtKinect* kinect = static_cast<NtKinect*>(ptr);
        int scale = 4;
        cv::Mat img((*kinect).rgbImage);
        cv::resize(img, img, cv::Size(img.cols / scale, img.rows / scale), 0, 0);
        if ((*kinect).faceRect.size() == 0) {
          for (auto& r : savedRect) {
    	(*kinect).faceRect.push_back(r);
          }
        }
        else {
          savedRect.clear();
          for (auto& r : (*kinect).faceRect) {
    	savedRect.push_back(r);
          }
        }
        for (auto r : (*kinect).faceRect) {
          cv::Rect r2(r.x / scale, r.y / scale, r.width / scale, r.height / scale);
          cv::rectangle(img, r2, cv::Scalar(0, 0, 0), -1);
        }
        for (auto& person : (*kinect).skeleton) {
          for (auto& joint : person) {
    	if (joint.TrackingState == TrackingState_NotTracked) continue;
    	ColorSpacePoint cp;
    	(*kinect).coordinateMapper->MapCameraPointToColorSpace(joint.Position, &cp);
    	cv::rectangle(img, cv::Rect((int)cp.X / scale - 2, (int)cp.Y / scale - 2, 4, 4), cv::Scalar(0, 0, 255), 2);
          }
        }
        for (auto r : (*kinect).faceRect) {
          cv::Rect r2(r.x / scale, r.y / scale, r.width / scale, r.height / scale);
          cv::rectangle(img, r2, cv::Scalar(255, 255, 0), 2);
        }
        cv::imshow("face", img);
        cv::waitKey(1);
      }
    
      // CoordinateMapper
      /*
        NTKINECTDLL_API void mapCameraPointToColorSpace(void* ptr,void* sv,void* cv) {
        NtKinect* kinect = static_cast<NtKinect*>(ptr);
        CameraSpacePoint sp; sp.X = ((float*)sv)[0]; sp.Y = ((float*)sv)[1]; sp.Z = ((float*)sv)[2];
        ColorSpacePoint cp;
        (*kinect).coordinateMapper->MapCameraPointToColorSpace(sp,&cp);
        ((float*)cv)[0] = cp.X; ((float*)cv)[1] = cp.Y;
        }
        NTKINECTDLL_API void mapCameraPointToDepthSpace(void* ptr,void* sv,void* dv) {
        NtKinect* kinect = static_cast<NtKinect*>(ptr);
        CameraSpacePoint sp; sp.X = ((float*)sv)[0]; sp.Y = ((float*)sv)[1]; sp.Z = ((float*)sv)[2];
        DepthSpacePoint dp;
        (*kinect).coordinateMapper->MapCameraPointToDepthSpace(sp,&dp);
        ((float*)dv)[0] = dp.X; ((float*)dv)[1] = dp.Y;
        }
        NTKINECTDLL_API void mapDepthPointToColorSpace(void* ptr,void* dv,UINT16 depth,void* cv) {
        NtKinect* kinect = static_cast<NtKinect*>(ptr);
        DepthSpacePoint dp; dp.X = ((float*)dv)[0]; dp.Y = ((float*)dv)[1];
        ColorSpacePoint cp;
        (*kinect).coordinateMapper->MapDepthPointToColorSpace(dp,depth,&cp);
        ((float*)cv)[0] = cp.X; ((float*)cv)[1] = cp.Y;
        }
        NTKINECTDLL_API void mapDepthPointToCameraSpace(void* ptr,void* dv,UINT16 depth,void* sv) {
        NtKinect* kinect = static_cast<NtKinect*>(ptr);
        DepthSpacePoint dp; dp.X = ((float*)dv)[0]; dp.Y = ((float*)dv)[1];
        CameraSpacePoint sp;
        (*kinect).coordinateMapper->MapDepthPointToCameraSpace(dp,depth,&sp);
        ((float*)sv)[0] = sp.X; ((float*)sv)[1] = sp.Y; ((float*)sv)[2] = sp.Z;
        }
      */
      NTKINECTDLL_API void mapCameraPointToColorSpace(void* ptr, void* sv, void* cv, int n) {
        NtKinect* kinect = static_cast<NtKinect*>(ptr);
        float* sa = (float*)sv;
        float* ca = (float*)cv;
        for (int i = 0; i<n; i++) {
          CameraSpacePoint sp; sp.X = *sa++; sp.Y = *sa++; sp.Z = *sa++;
          ColorSpacePoint cp;
          (*kinect).coordinateMapper->MapCameraPointToColorSpace(sp, &cp);
          *ca++ = cp.X; *ca++ = cp.Y;
        }
      }
      NTKINECTDLL_API void mapCameraPointToDepthSpace(void* ptr, void* sv, void* dv, int n) {
        NtKinect* kinect = static_cast<NtKinect*>(ptr);
        float* sa = (float*)sv;
        float* da = (float*)dv;
        for (int i = 0; i<n; i++) {
          CameraSpacePoint sp; sp.X = *sa++; sp.Y = *sa++; sp.Z = *sa++;
          DepthSpacePoint dp;
          (*kinect).coordinateMapper->MapCameraPointToDepthSpace(sp, &dp);
          *da++ = dp.X; *da++ = dp.Y;
        }
      }
      NTKINECTDLL_API void mapDepthPointToColorSpace(void* ptr, void* dv, void* dth, void* cv, int n) {
        NtKinect* kinect = static_cast<NtKinect*>(ptr);
        float* da = (float*)dv;
        UINT16* dth_addr = (UINT16*)dth;
        float* ca = (float*)cv;
        for (int i = 0; i<n; i++) {
          DepthSpacePoint dp; dp.X = *da++; dp.Y = *da++;
          ColorSpacePoint cp;
          (*kinect).coordinateMapper->MapDepthPointToColorSpace(dp, *dth_addr++, &cp);
          *ca++ = cp.X; *ca++ = cp.Y;
        }
      }
      NTKINECTDLL_API void mapDepthPointToCameraSpace(void* ptr, void* dv, void* dth, void* sv, int n) {
        NtKinect* kinect = static_cast<NtKinect*>(ptr);
        float* da = (float*)dv;
        UINT16* dth_addr = (UINT16*)dth;
        float* sa = (float*)sv;
        for (int i = 0; i<n; i++) {
          DepthSpacePoint dp; dp.X = *da++; dp.Y = *da++;
          CameraSpacePoint sp;
          (*kinect).coordinateMapper->MapDepthPointToCameraSpace(dp, *dth_addr++, &sp);
          *sa++ = sp.X; *sa++ = sp.Y; *sa++ = sp.Z;
        }
      }
    
      // Multi Thread
      NTKINECTDLL_API void acquire(void* ptr) { (*static_cast<NtKinect*>(ptr)).acquire(); }
      NTKINECTDLL_API void release(void* ptr) { (*static_cast<NtKinect*>(ptr)).release(); }
    
      // Audio
      NTKINECTDLL_API void setAudio(void* ptr, bool flag) { (*static_cast<NtKinect*>(ptr)).setAudio(flag); }
      NTKINECTDLL_API float getBeamAngle(void* ptr) { return (*static_cast<NtKinect*>(ptr)).beamAngle; }
      NTKINECTDLL_API float getBeamAngleConfidence(void* ptr) { return (*static_cast<NtKinect*>(ptr)).beamAngleConfidence; }
      NTKINECTDLL_API unsigned __int64 getAudioTrackingId(void* ptr) { return (*static_cast<NtKinect*>(ptr)).audioTrackingId; }
      NTKINECTDLL_API void openAudio(void* ptr, wchar_t* filename) {
        NtKinect* kinect = static_cast<NtKinect*>(ptr);
        (*kinect).openAudio(wchar2string(filename));
      }
      NTKINECTDLL_API void closeAudio(void* ptr) { (*static_cast<NtKinect*>(ptr)).closeAudio(); }
      NTKINECTDLL_API bool isOpenedAudio(void* ptr) { return (*static_cast<NtKinect*>(ptr)).isOpenedAudio(); }
    
      // RGB
      NTKINECTDLL_API void setRGB(void* ptr) {
        NtKinect* kinect = static_cast<NtKinect*>(ptr);
        (*kinect).setRGB();
      }
      NTKINECTDLL_API int getRGB(void* ptr, void* data) {
        NtKinect* kinect = static_cast<NtKinect*>(ptr);
        char* idx = (char*)data;
        for (int y = 0; y<(*kinect).rgbImage.rows; y++) {
          for (int x = 0; x<(*kinect).rgbImage.cols; x++) {
    	cv::Vec4b& pxl = (*kinect).rgbImage.at<cv::Vec4b>(y, x);
    	*idx++ = pxl[2]; // Red
    	*idx++ = pxl[1]; // Green
    	*idx++ = pxl[0]; // Blue
    	*idx++ = pxl[3]; // Alpha
          }
        }
        return (int)(idx - (char*)data);
      }
    
      // Depth
      NTKINECTDLL_API void setDepth(void* ptr) { (*static_cast<NtKinect*>(ptr)).setDepth(); }
      NTKINECTDLL_API int getDepth(void* ptr, void* data) {
        NtKinect* kinect = static_cast<NtKinect*>(ptr);
        UINT16* idx = (UINT16*)data;
        for (int y = 0; y<(*kinect).depthImage.rows; y++) {
          for (int x = 0; x<(*kinect).depthImage.cols; x++) {
    	*idx++ = (*kinect).depthImage.at<UINT16>(y, x);
          }
        }
        return (int)(idx - (UINT16*)data);
      }
    
      // Infrared
      NTKINECTDLL_API void setInfrared(void* ptr) { (*static_cast<NtKinect*>(ptr)).setInfrared(); }
      NTKINECTDLL_API int getInfrared(void* ptr, void* data) {
        NtKinect* kinect = static_cast<NtKinect*>(ptr);
        UINT16* idx = (UINT16*)data;
        for (int y = 0; y<(*kinect).infraredImage.rows; y++) {
          for (int x = 0; x<(*kinect).infraredImage.cols; x++) {
    	*idx++ = (*kinect).infraredImage.at<UINT16>(y, x);
          }
        }
        return (int)(idx - (UINT16*)data);
      }
    
      // bodyIndex
      NTKINECTDLL_API void setBodyIndex(void* ptr) { (*static_cast<NtKinect*>(ptr)).setBodyIndex(); }
      NTKINECTDLL_API int getBodyIndex(void* ptr, void* data) {
        NtKinect* kinect = static_cast<NtKinect*>(ptr);
        char* idx = (char*)data;
        for (int y = 0; y<(*kinect).bodyIndexImage.rows; y++) {
          for (int x = 0; x<(*kinect).bodyIndexImage.cols; x++) {
    	*idx++ = (*kinect).bodyIndexImage.at<char>(y, x);
          }
        }
        return (int)(idx - (char*)data);
      }
    
      // Skeleton
      NTKINECTDLL_API void setSkeleton(void* ptr) { (*static_cast<NtKinect*>(ptr)).setSkeleton(); }
      NTKINECTDLL_API int getSkeleton(void* ptr, void* skel, void* skelState, void* skelId, void* skelTrackingId) {
        NtKinect* kinect = static_cast<NtKinect*>(ptr);
        float* skeleton = (float*)skel;
        int* state = (int*)skelState;
        int* id = (int*)skelId;
        UINT64* trackingId = (UINT64*)skelTrackingId;
        int idx = 0, jt = 0, st = 0;
        for (auto& person : (*kinect).skeleton) {
          for (auto& joint : person) {
    	skeleton[jt++] = joint.Position.X;
    	skeleton[jt++] = joint.Position.Y;
    	skeleton[jt++] = joint.Position.Z;
    	state[st++] = joint.TrackingState;
          }
          id[idx] = (*kinect).skeletonId[idx];
          trackingId[idx] = (*kinect).skeletonTrackingId[idx];
          idx++;
        }
        return idx;
      }
      NTKINECTDLL_API int handState(void* ptr, int id, bool isLeft) { return (*static_cast<NtKinect*>(ptr)).handState(id, isLeft).first; }
    
      // Face
      NTKINECTDLL_API void setFace(void* ptr, bool isColorSpace) { (*static_cast<NtKinect*>(ptr)).setFace(isColorSpace); }
      NTKINECTDLL_API int getFace(void* ptr, float* point, float* rect, float* direction, int* property, void* tid) {
        NtKinect* kinect = static_cast<NtKinect*>(ptr);
        float* p = point;
        for (auto& face : (*kinect).facePoint) {
          for (auto& pt : face) {
    	*p++ = pt.X;
    	*p++ = pt.Y;
          }
        }
        int np = (int)(p - point) / 2;
        p = rect;
        for (auto& r : (*kinect).faceRect) {
          *p++ = (float)r.x;
          *p++ = (float)r.y;
          *p++ = (float)r.width;
          *p++ = (float)r.height;
        }
        int nr = (int)(p - rect) / 4;
        p = direction;
        for (auto& d : (*kinect).faceDirection) {
          *p++ = d[0];
          *p++ = d[1];
          *p++ = d[2];
        }
        int nd = (int)(p - direction) / 3;
        int* a = (int*)property;
        for (auto& face : (*kinect).faceProperty) {
          for (auto& prop : face) {
    	*a++ = prop;
          }
        }
        int npr = (int)(a - property);
        UINT64* q = (UINT64*)tid;
        for (auto& t : (*kinect).faceTrackingId) {
          *q++ = t;
        }
        int nt = (int)(q - (UINT64*)tid);
        return min(nt, min(min(npr, nd), min(nr, np)));
      }
    
      // HDFace
      NTKINECTDLL_API void setHDFace(void* ptr) { (*static_cast<NtKinect*>(ptr)).setHDFace(); }
      NTKINECTDLL_API int getHDFace(void* ptr, float* point, void* tid, int* status) {
        NtKinect* kinect = static_cast<NtKinect*>(ptr);
        float *p = (float*)point;
        for (auto& person : (*kinect).hdfaceVertices) {
          for (auto& cp : person) {
    	*p++ = cp.X;
    	*p++ = cp.Y;
    	*p++ = cp.Z;
          }
        }
        UINT64 *q = (UINT64*)tid;
        for (auto& t : (*kinect).hdfaceTrackingId) {
          *q++ = t;
        }
        int* r = (int*)status;
        for (auto& s : (*kinect).hdfaceStatus) {
          *r++ = s.first;
          *r++ = s.second;
        }
        return (int)(*kinect).hdfaceVertices.size();
      }
    
      // Gesture
      NTKINECTDLL_API void setGestureFile(void* ptr, wchar_t* filename) {
        NtKinect* kinect = static_cast<NtKinect*>(ptr);
        wstring fname(filename);
        (*kinect).setGestureFile(fname);
      }
    
      NTKINECTDLL_API int setGestureId(void* ptr, wchar_t* name, int id) {
        int len = WideCharToMultiByte(CP_UTF8, NULL, name, -1, NULL, 0, NULL, NULL) + 1;
        char* nameBuffer = new char[len];
        memset(nameBuffer, '\0', len);
        WideCharToMultiByte(CP_UTF8, NULL, name, -1, nameBuffer, len, NULL, NULL);
        string s(nameBuffer);
        gidMap[s] = id;
    
        return id;
      }
    
      NTKINECTDLL_API void setGesture(void* ptr) { (*static_cast<NtKinect*>(ptr)).setGesture(); }
    
      NTKINECTDLL_API int getDiscreteGesture(void* ptr, int* gid, float* confidence, void *tid) {
        NtKinect* kinect = static_cast<NtKinect*>(ptr);
        UINT64* trackingId = (UINT64*)tid;
        for (int i = 0; i<(*kinect).discreteGesture.size(); i++) {
          auto g = (*kinect).discreteGesture[i];
          string gname = (*kinect).gesture2string(g.first);
          gid[i] = gidMap[gname];
          confidence[i] = g.second;
          trackingId[i] = (*kinect).discreteGestureTrackingId[i];
        }
        return (int)(*kinect).discreteGesture.size();
      }
    
      NTKINECTDLL_API int getContinuousGesture(void* ptr, int* gid, float* progress, void *tid) {
        NtKinect* kinect = static_cast<NtKinect*>(ptr);
        UINT64* trackingId = (UINT64*)tid;
        for (int i = 0; i<(*kinect).continuousGesture.size(); i++) {
          auto g = (*kinect).continuousGesture[i];
          string gname = (*kinect).gesture2string(g.first);
          gid[i] = gidMap[gname];
          progress[i] = g.second;
          trackingId[i] = (*kinect).continuousGestureTrackingId[i];
        }
        return (int)(*kinect).continuousGesture.size();
      }
      NTKINECTDLL_API int getGidMapSize() {
        return (int)gidMap.size();
      }
    
      // Video
      cv::VideoWriter *videoWriter = nullptr;
      cv::Size videoSize;
      bool videoOnSave = false;
    
      NTKINECTDLL_API void openVideo(void* ptr, wchar_t* filename) {
        NtKinect *kinect = static_cast<NtKinect*>(ptr);
        string fname = wchar2string(filename);
        if (videoOnSave) {
          std::cerr << "cannot open two video files simultaneously" << std::endl;
          return;
        }
        videoSize = cv::Size(1920 / 4, 1080 / 4);
        // rename CV_FOURCC_MACRO as cv::VideoWriter::fourcc (in case of opencv3 and later)
        videoWriter = new cv::VideoWriter(fname, CV_FOURCC_MACRO('X', 'V', 'I', 'D'), 30.0, videoSize);
        if (!(*videoWriter).isOpened()) {
          std::cerr << "cannot open video file" << std::endl;
          return;
        }
        videoOnSave = true;
      }
      NTKINECTDLL_API void writeVideo(void* ptr) {
        NtKinect *kinect = static_cast<NtKinect*>(ptr);
        cv::Mat img;
        if (videoOnSave) {
          cv::resize((*kinect).rgbImage, img, videoSize, 0, 0);
          // rename CV_BGRA2BGR as cv::COLOR_BGRA2BGR (in case of opencv3 and later)
          cv::cvtColor(img, img, CV_BGRA2BGR);
          (*videoWriter) << img;
        }
      }
      NTKINECTDLL_API void closeVideo(void* ptr) {
        if (videoOnSave) {
          (*videoWriter).release();
          delete videoWriter;
          videoWriter = nullptr;
          videoOnSave = false;
        }
      }
    }
    
  15. 「アプリケーションの構成」を "Release"にしてコンパイルします。 メニューからBuild -> プロジェクトの Rebuild を選びます。 フォルダ x64/Release に NtKinectDLL.lib および NtKinectDLL.dll が生成されます。
  16. [注意] ダイナミックリンクライブラリを作りたいので、ここではコンパイル、すなわちビルドするだけです。 このプロジェクトではプログラム本体を作成してはいないので、実行しようとすると (意味のない)エラーが発生します。

    [注意2] .lib ファイルと .dll ファイルが生成されるのは プロジェクト直下のフォルダ (プロジェクト名)/x64/Release です。 ソースファイルが置かれているフォルダの下の (プロジェクト名)/NtKinectDLL/x64/Release ではありません。

  17. サンプルのプロジェクトはこちら NtKinectDLL.zip
  18. 上記のzipファイルには必ずしも最新の NtKinect.h が含まれていない場合があるので、 こちらから最新版をダウンロードして 差し替えてお使い下さい。



http://nw.tsuda.ac.jp/