UnityからWindows10のタッチキーボードを呼び出す

f:id:miso_engine:20190423175109p:plain
Windows10のTouchKeyboard

On Screen Keyboard (PC and Console) best practices - Unity Answers

上記記事のコードをコピペして呼び出すと出てくる。Windows10にはTouchKeyboardとOn-Screen-Keyboardの2種類のスクリーンキーボードがあるが、試したところOSKは不可能でTouchKeyboardのみ呼び出し可能だった。できるのは、キーボードの表示・非表示のみ。

Mac上のPython -> Unityでのローカルの映像転送にメモリマップトファイルを利用する

Macで映像転送と言えばSyphonですが、PythonSyphonできないぽかったのでメモリマップトファイルを利用して実装しました。メモリマップトファイルはメモリを映像のような大量のデータだとソケット通信とかでは速度が間に合わないので、これ一択ぽいです。メモリマップトファイルにバイト列として画像を置いて通信する仕組みです。

注意点としては、映像のフォーマットを送受信出来ないので、決めうちにする必要があります。今回は1200x1200のRGB画像を送る前提のサンプルコードを載せておきます。なおコードは元のプロジェクトから抜き出して書いているもので、テストしておりません。ライセンスはパブリックドメインです。

Unityは、Monoではなく.NET Coreでないとメモリマップトファイルが利用出来なかった気がします。Unity側ではRawImageにメモリマップトファイルから取り出したTextureを貼ってます。Textureは明示的にDestoryしないとメモリーリークするので気をつけて。

利用ライブラリ

Pythonサンプルコード

import os
import mmap

DATA_LENGTH = 4320000

fd = os.open('/tmp/mmappython', os.O_CREAT | os.O_TRUNC | os.O_RDWR)
assert os.write(fd, b'\x00' * DATA_LENGTH) == DATA_LENGTH

buf = mmap.mmap(fd, DATA_LENGTH, mmap.MAP_SHARED, mmap.PROT_WRITE)

buf.seek(0)
byte_data = b'\x00' * DATA_LENGTH
buf.write(byte_data)

buf.close()

Unityサンプルコード

using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.IO.MemoryMappedFiles;

using UnityEngine;
using UnityEngine.UI;

public class MmfManager : MonoBehaviour {
    private string filePath = "/tmp/mmappython";
    private const int dataLength = 4320000;
    private RawImage rawImage;

	private MemoryMappedFile mmf;
    private MemoryMappedViewStream stream;

    public void InitMemoryMappedFile()
    {
        if (File.Exists(filePath) == false)
        {
            byte[] bs = new byte[dataLength];
            using(FileStream fs = File.Open(filePath, FileMode.Create))
            {
                fs.Write(bs, 0, bs.Length);
            }
        }
        mmf = MemoryMappedFile.CreateFromFile(filePath, FileMode.Open);

        Debug.Log(filePath);

        stream = mmf.CreateViewStream();
        Debug.Log(stream.Capacity);
        Debug.Log(stream.Length);
    }

	void Start () {
        rawImage = GetComponent<RawImage>();
	}
	
	void Update () {
        stream.Seek(0, SeekOrigin.Begin);
        byte[] buffer = new byte[dataLength];
        int retVal = stream.Read(buffer, 0, dataLength);
        if (retVal == dataLength)
        {
            Texture oldTex = rawImage.texture;
            Texture2D tex = new Texture2D(1200, 1200, TextureFormat.RGB24, false);
            tex.LoadRawTextureData(buffer);
            tex.Apply();
            rawImage.texture = tex;
            Destroy(oldTex);
        }
    }

    void OnDestroy()
    {
        stream.Close();
        stream.Dispose();
        mmf.Dispose();
        stream = null;
        mmf = null;
    }
}

Intel RealSense D400シリーズを赤外線カメラとして使う

intel RealSense™ Depth Camera D435

intel RealSense™ Depth Camera D435

Kinect後継として指名されているIntelのRealSenseシリーズだが、距離をセンシングするIRステレオカメラ部は、単体の赤外線カメラとして利用可能だ。性能、値段、入手性のバランスが優れた赤外線カメラと言える。D415とD435の2種類あり、後者のほうが広角なのだが、センサからして違うので、どちらを選ぶかの参考になるように記事をまとめた。

赤外線カメラとしてのD400シリーズの仕様

  • D415とD435ではIRステレオカメラ部分が違う
    • D415はIRカットフィルムのない通常の可視光にピークを合わせたカメラ
    • D435は赤外線領域にピークを合わせているカメラ
  • 可視光カットフィルムを使うことでほぼ問題なく可視光カット可能
  • 画角が異なるため赤外線プロジェクターも異なる
  • Intel公式ではなくMouserにあったデータシートが良かった

f:id:miso_engine:20181126173607p:plain

librealsenseのPythonラッパーで赤外線カメラを使うコード

librealsenseはIntel公式のようで公式ではないらしいSDK。特に問題なく使えるが、コメントで書いた通り、カメラ側に設定を反映させるのに変なコツがいる。

# coding: utf-8

import pyrealsense2 as rs
import numpy as np
import cv2

# Stop Laser Emitter
context = rs.context()
sensor = context.sensors[0]
sensor.set_option(rs.option.emitter_enabled, 0.0)

# pipelineを一度start()しないと最初の接続時に設定が反映されない
pipeline = rs.pipeline()
pipeline.start()
pipeline.stop()

config = rs.config()
config.enable_stream(rs.stream.infrared, 1, 1280, 720, rs.format.y8, 30)

pipeline.start(config)
cv2.namedWindow('pysense', cv2.WINDOW_AUTOSIZE)

try:
    while True:

        frames = pipeline.wait_for_frames()
        ir_frame = frames.get_infrared_frame()
        if not ir_frame:
            continue

        ir_image = np.asanyarray(ir_frame.get_data())
        
        cv2.imshow('pysense', ir_image)
        k = cv2.waitKey(1)
        if k == 27:
            break
            
finally:
    pipeline.stop()
    cv2.destroyAllWindows()

f:id:miso_engine:20181126175749p:plain
D415の赤外線カメラ画像

バイイングガイド

赤外線カメラとして利用する場合、D435の方が、

  1. センサが赤外線にピークを合わせている
  2. D415よりも広角
  3. 1280x800で30fps出せる(D415は1280x720)

といった値段相応の機能性と使いやすさがあるため、ケチケチしたプロジェクトでない限りはD435がオススメだ。