UnityのカメラからC++やPythonへ映像を転送する方法

Unityのカメラから他プロセスへ映像を転送する方法として、以下のような一般的なプロセス間通信が考えられる。

  • MMAP
  • ソケット通信
  • RTSP

この記事ではこれらの方法を解説する。ただしRTSPはGStreamerのインストール方法ができなかったのでやっていない。

MMAP

MMAPはメモリ上にファイル等をマッピングし、表面上はファイルのやり取りではあるが、実際にはメモリ上でやり取りを行うプロセス間通信である。例えば書き込み側がIMGというファイルに画像を書き込み、読み込み側がIMGというファイルを読み込むことで、画像を読み込むことができる。これをMMAPを使用するとメモリ上でやり取りができ、高速な通信が可能となる。

送信側

コードは以下の通り。mmfというMemoryMappedFileにPNGエンコードした画像を書き込んでいる。MemoryMappedFileを作成する際のtag名は後ほど使う。

        accessor = mmf.CreateViewAccessor();
        RenderTexture.active = cam.targetTexture;

        tex.ReadPixels(new Rect(0, 0, tex.width, tex.height), 0, 0);
        tex.Apply();

        byte[] bytes = tex.EncodeToPNG();
        accessor.WriteArray<byte>(0, bytes, 0, bytes.Length);
        accessor.Dispose();

スクリプト全文は以下。実際に使用する際は、そのままスクリプトを使用すればOK。

Linon_SDK/camera_mmap.cs at main · wooolwooolwoool/Linon_SDK · GitHub

受信側

受信側のPythonコードは以下の通り。tagnameは送信側と合わせる。

class MMAPCamera():
    def __init__(self, tagname):        
        self.mm = mmap.mmap(-1, 1024 * 1024 * 50, tagname)
        
    def read(self):
        self.mm.seek(0)     
        mode = self.mm.read()
        ByteToImg = Image.open(io.BytesIO(mode))
        return ByteToImg

コード全文は以下。

Linon_SDK/camera.py at main · wooolwooolwoool/Linon_SDK · GitHub

ソケット通信

ソケット通信ではデータをUDPTCPで送信する。MMAPと違いネットワークを使用するため低速にはなってしまうものの、対向がネットワーク上にあればよいので別PC間での通信も可能となる。

送信側

送信側は以下の通り。先ほどデータを書き込んでいたのを、UDPで送信しているという違いだけである。あとソケット通信は低速なので、JPGエンコードにしてQualityを調整できるようにしてある。

        byte[] bytes = tex.EncodeToJPG(quality);
        udpClientSend.Send(bytes, bytes.Length);

スクリプト全体は以下の通り。

Linon_SDK/camere_udp.cs at main · wooolwooolwoool/Linon_SDK · GitHub

受信側

受信側のC++コードは以下の通り。受信データをOpenCVでデコードすればOK。

udp0.udp_recv(data, buf_size);
std::vector<uchar> buf(data, data+buf_size);
im = cv::imdecode(cv::Mat(buf), -1);

コード全体は以下の通り。ORB SLAM3に適当に組み込んだもの。

Linon_SDK/mono_inertial_euroc.cc at main · wooolwooolwoool/Linon_SDK · GitHub