HoloLens RS4 PreviewのResearch modeで各種センサーのデータを可視化する

# はじめに
[HoloLensForCV](https://github.com/Microsoft/HoloLensForCV)の[feature/api_updatesブランチ](https://github.com/Microsoft/HoloLensForCV/tree/feature/api_updates)に含まれているサンプルコードを書き換えながら各種センサーのデータを可視化してみる。

実行結果はこんな感じになる。
<img src="https://qiita-image-store.s3.amazonaws.com/0/162000/84b19973-60ac-4bf7-4136-4de215629519.jpeg" width="45%">

<img src="https://qiita-image-store.s3.amazonaws.com/0/162000/ad5ba7d6-8b1e-125e-39b1-12d73e5d69b4.jpeg" width="45%">

<img src="https://qiita-image-store.s3.amazonaws.com/0/162000/0c863825-6d59-3706-3025-cf396c6c17d1.jpeg" width="45%">

<img src="https://qiita-image-store.s3.amazonaws.com/0/162000/03d37a99-c3a0-85ff-274d-ed99334b9610.jpeg" width="45%">

# Research mode について
[HoloLens RS4 Preview](https://docs.microsoft.com/ja-jp/windows/mixed-reality/hololens-rs4-preview)のページによると、Research modeを有効にすることで、8種類のセンサーデータにアクセスできる。

- The four environment tracking cameras（4つの環境認識カメラ）
- Two versions of an IR-reflectivity stream（赤外線反射データの2つのバージョン）
- Two versions of the depth mapping camera data（深度カメラデータの2つのバージョン）
  - High-frequency (30 fps) near-depth sensing (commonly used in hand tracking)
  - Lower-frequency (1 fps) far-depth sensing (currently used by spatial mapping)

HoloLensに搭載されているセンサー系ハードウェアについては[こちら](https://www.buildinsider.net/small/hololens/001)を参照。

実際に[SensorType.h](https://github.com/Microsoft/HoloLensForCV/blob/feature/api_updates/Shared/HoloLensForCV/SensorType.h)のソースコードを見てみると、Research Mode Sensorsとして8種類が定義されている。

- 環境認識カメラ
  - VisibleLightLeftLeft
  - VisibleLightLeftFront
  - VisibleLightRightFront
  - VisibleLightRightRight
- 赤外線反射
  - ShortThrowToFReflectivity
  - LongThrowToFReflectivity
- 深度カメラ
  - ShortThrowToFDepth
  - LongThrowToFDepth

```cpp
/**
 * /Shared/HoloLensForCV/SensorType.h
 */
#pragma once

#define ENABLE_HOLOLENS_RESEARCH_MODE_SENSORS 1

namespace HoloLensForCV
{
    public enum class SensorType : int32_t
    {
        Undefined = -1,
        PhotoVideo = 0,

#if ENABLE_HOLOLENS_RESEARCH_MODE_SENSORS
        ShortThrowToFDepth,
        ShortThrowToFReflectivity,
        LongThrowToFDepth,
        LongThrowToFReflectivity,
        VisibleLightLeftLeft,
        VisibleLightLeftFront,
        VisibleLightRightFront,
        VisibleLightRightRight,
#endif /* ENABLE_HOLOLENS_RESEARCH_MODE_SENSORS */

        NumberOfSensorTypes
    };

    struct SensorTypeHash
    {
        size_t operator()(const SensorType& sensorType) const
        {
            return std::hash<int32_t>()((int32_t)sensorType);
        }
    };
}
```

# 検証環境
- Windows 10 Pro
- Visual Studio 2017 (Version 15.4.2 and 15.6.6)
- HoloLens RS4 Preview

# サンプルプロジェクトの取得
[HoloLensForCV](https://github.com/Microsoft/HoloLensForCV)の[feature/api_updatesブランチ](https://github.com/Microsoft/HoloLensForCV/tree/feature/api_updates)をcloneする。```
$ git clone -b feature/api_updates https://github.com/Microsoft/HoloLensForCV.git 
```

# サンプルプロジェクトを動かしてみる
[Hololensの深度センサーデータを取得するサンプルを動かす(HoloLens RS4 Preview)](https://qiita.com/decchi/items/ae438a8bbf1784a05af9)を参照。
サンプルコードではShortThrowToFReflectivity（近距離赤外線）を使っているので、こんな感じになるはず。
<img src="https://qiita-image-store.s3.amazonaws.com/0/162000/84b19973-60ac-4bf7-4136-4de215629519.jpeg">

# サンプルコードを書き換えてみる
[AppMain.cpp](https://github.com/Microsoft/HoloLensForCV/blob/feature/api_updates/Tools/Streamer/AppMain.cpp)の116行目～132行目は以下のようなコードになっている。使用するセンサーによってこの部分を書き換える。

```cpp
#if ENABLE_HOLOLENS_RESEARCH_MODE_SENSORS
        else
        {
            latestCameraPreviewFrame =
                _holoLensMediaFrameSourceGroup->GetLatestSensorFrame(
                    HoloLensForCV::SensorType::ShortThrowToFReflectivity);

            cameraPreviewExpectedBitmapPixelFormat =
                Windows::Graphics::Imaging::BitmapPixelFormat::Gray8;

            cameraPreviewTextureFormat =
                DXGI_FORMAT_R8_UNORM;

            cameraPreviewPixelStride =
                1;
        }
#endif /* ENABLE_HOLOLENS_RESEARCH_MODE_SENSORS */
```
[AppMain.cpp](https://github.com/Microsoft/HoloLensForCV/blob/feature/api_updates/Tools/Streamer/AppMain.cpp)の250行目～262行目は以下のようなコードになっている。使用するセンサーの種類がenabledSensorTypesに含まれている必要がある。

```cpp
#if ENABLE_HOLOLENS_RESEARCH_MODE_SENSORS
        enabledSensorTypes.emplace_back(
            HoloLensForCV::SensorType::ShortThrowToFReflectivity);

        enabledSensorTypes.emplace_back(
            HoloLensForCV::SensorType::ShortThrowToFDepth);

        enabledSensorTypes.emplace_back(
            HoloLensForCV::SensorType::VisibleLightLeftFront);

        enabledSensorTypes.emplace_back(
            HoloLensForCV::SensorType::VisibleLightRightFront);
#else
```

## ShortThrowToFDepth（近距離深度）を使う場合
1ピクセルあたり16bitのデータになるため、SensorTypeだけでなく、PixelFormat、TextureFormat、PixelStrideの変更が必要。

```cpp
#if ENABLE_HOLOLENS_RESEARCH_MODE_SENSORS
        else
        {
			latestCameraPreviewFrame =
				_holoLensMediaFrameSourceGroup->GetLatestSensorFrame(
					HoloLensForCV::SensorType::ShortThrowToFDepth);

            cameraPreviewExpectedBitmapPixelFormat =
                Windows::Graphics::Imaging::BitmapPixelFormat::Gray16;

            cameraPreviewTextureFormat =
                DXGI_FORMAT_R8G8_UNORM;

            cameraPreviewPixelStride =
                2;
        }
#endif /* ENABLE_HOLOLENS_RESEARCH_MODE_SENSORS */
```

実行結果はこんな感じになるはず。
![20180412_03_ShortThrowToFDepth.jpg](https://qiita-image-store.s3.amazonaws.com/0/162000/0c863825-6d59-3706-3025-cf396c6c17d1.jpeg)

## LongThrowToFDepth（遠距離深度）を使う場合
SensorType以外はShortThrowToFDepthと同じ設定。

```cpp
#if ENABLE_HOLOLENS_RESEARCH_MODE_SENSORS
        else
        {
            latestCameraPreviewFrame =
				_holoLensMediaFrameSourceGroup->GetLatestSensorFrame(
					HoloLensForCV::SensorType::LongThrowToFDepth);

            cameraPreviewExpectedBitmapPixelFormat =
                Windows::Graphics::Imaging::BitmapPixelFormat::Gray16;

            cameraPreviewTextureFormat =
                DXGI_FORMAT_R8G8_UNORM;

            cameraPreviewPixelStride =
                2;
        }
#endif /* ENABLE_HOLOLENS_RESEARCH_MODE_SENSORS */
```
また、enabledSensorTypesに追記が必要。

```cpp
#if ENABLE_HOLOLENS_RESEARCH_MODE_SENSORS
        enabledSensorTypes.emplace_back(
            HoloLensForCV::SensorType::ShortThrowToFReflectivity);

        enabledSensorTypes.emplace_back(
            HoloLensForCV::SensorType::ShortThrowToFDepth);

        enabledSensorTypes.emplace_back(
            HoloLensForCV::SensorType::LongThrowToFDepth);

        enabledSensorTypes.emplace_back(
            HoloLensForCV::SensorType::VisibleLightLeftFront);

        enabledSensorTypes.emplace_back(
            HoloLensForCV::SensorType::VisibleLightRightFront);
#else
```

実行結果はこんな感じになるはず。
![20180412_04_LongThrowToFDepth.jpg](https://qiita-image-store.s3.amazonaws.com/0/162000/03d37a99-c3a0-85ff-274d-ed99334b9610.jpeg)

## LongThrowToFReflectivity（遠距離赤外線）を使う場合
SensorType以外はShortThrowToFReflectivityと同じ設定。

```cpp
#if ENABLE_HOLOLENS_RESEARCH_MODE_SENSORS
        else
        {
            latestCameraPreviewFrame =
				_holoLensMediaFrameSourceGroup->GetLatestSensorFrame(
					HoloLensForCV::SensorType::LongThrowToFReflectivity);

            cameraPreviewExpectedBitmapPixelFormat =
                Windows::Graphics::Imaging::BitmapPixelFormat::Gray8;

            cameraPreviewTextureFormat =
                DXGI_FORMAT_R8_UNORM;

            cameraPreviewPixelStride =
                1;
        }
#endif /* ENABLE_HOLOLENS_RESEARCH_MODE_SENSORS */
```
また、enabledSensorTypesに追記が必要。

```cpp
#if ENABLE_HOLOLENS_RESEARCH_MODE_SENSORS
        enabledSensorTypes.emplace_back(
            HoloLensForCV::SensorType::ShortThrowToFReflectivity);

        enabledSensorTypes.emplace_back(
            HoloLensForCV::SensorType::LongThrowToFReflectivity);

        enabledSensorTypes.emplace_back(
            HoloLensForCV::SensorType::ShortThrowToFDepth);

        enabledSensorTypes.emplace_back(
            HoloLensForCV::SensorType::LongThrowToFDepth);

        enabledSensorTypes.emplace_back(
            HoloLensForCV::SensorType::VisibleLightLeftFront);

        enabledSensorTypes.emplace_back(
            HoloLensForCV::SensorType::VisibleLightRightFront);
#else
```

実行結果はこんな感じになるはず。
<img src="https://qiita-image-store.s3.amazonaws.com/0/162000/ad5ba7d6-8b1e-125e-39b1-12d73e5d69b4.jpeg">

## 環境認識カメラを使う場合
1ピクセルあたり32bitのカラー画像になるため、SensorType以外はPhotoVideoと同じ設定。

```cpp
#if ENABLE_HOLOLENS_RESEARCH_MODE_SENSORS
        else
        {
            latestCameraPreviewFrame =
                _holoLensMediaFrameSourceGroup->GetLatestSensorFrame(
                    HoloLensForCV::SensorType::VisibleLightLeftFront);

            cameraPreviewExpectedBitmapPixelFormat =
                Windows::Graphics::Imaging::BitmapPixelFormat::Bgra8;

            cameraPreviewTextureFormat =
                DXGI_FORMAT_B8G8R8A8_UNORM;

            cameraPreviewPixelStride =
                4;
        }
#endif /* ENABLE_HOLOLENS_RESEARCH_MODE_SENSORS */
```
また、VisibleLightLeftLeftやVisibleLightRightRightを使う場合はenabledSensorTypesに追記が必要。

```cpp
#if ENABLE_HOLOLENS_RESEARCH_MODE_SENSORS
        enabledSensorTypes.emplace_back(
            HoloLensForCV::SensorType::ShortThrowToFReflectivity);

        enabledSensorTypes.emplace_back(
            HoloLensForCV::SensorType::LongThrowToFReflectivity);

        enabledSensorTypes.emplace_back(
            HoloLensForCV::SensorType::ShortThrowToFDepth);

        enabledSensorTypes.emplace_back(
            HoloLensForCV::SensorType::LongThrowToFDepth);

        enabledSensorTypes.emplace_back(
            HoloLensForCV::SensorType::VisibleLightLeftFront);

        enabledSensorTypes.emplace_back(
            HoloLensForCV::SensorType::VisibleLightRightFront);

        enabledSensorTypes.emplace_back(
            HoloLensForCV::SensorType::VisibleLightLeftLeft);

        enabledSensorTypes.emplace_back(
            HoloLensForCV::SensorType::VisibleLightRightRight);
#else
```

# まとめ
サンプルコードを書き換えてHoloLensに搭載されている各種センサーのデータを可視化した。
Depthを可視化する時に距離を考慮した可視化ができていないので何とかしたい。