OpenCV
TouchDesigner
More than 1 year has passed since last update.

この記事はTouchDesigner Advent以下略

TouchDesignerのPython環境には標準でOpenCVのcv2モジュールが入っています。
内部的には Blob Track TOP で使われているようなのですが、公開されている部分だけだとファイルの入出力を経由しないと使えません、、、

えっ… リアルタイムで使いたい… ので、普通にTOP渡しで自由に使えるようにしましょう!

できました!

td-imshow.png

ダウンロードはこちらから https://github.com/satoruhiga/TouchDesigner-OpenCV/releases

実際に使ってみる

今回はややこしい事をなるべく隠蔽したかったので OpenCV1 にコールバックを受けるDATを指定するとデータが飛んでくるようにしました。

↓ コールバックのDATの中身

import cv2

def onFrame(data):
    cv2.imshow('img', data)

これだけでOpenCVの画像プレビュー用のウィンドウが開きます。

あとは書籍やチュートリアルを黙々と試していくことで色々できますね!

cv2.calcOpticalFlowPyrLKをやってみた様子

以下色々とテッキーな事が書いてありますが、使う分には何も考えなくていいのもTouchDesignerの素晴しい所だと思いますので、興味のある方のみ読んでいただければ!


方針

現在TouchDesignerでは、TOPのピクセルデータにアクセスするのに CPlusPlus TOP のモジュールを書く必要があります。

そして CPlusPlus TOP のモジュールを書いてピクセルデータを取り出したら、今度はそれをどうにかしてPythonに渡す必要があります、、

色々探してみたのですが手っ取り早くC++からPythonへデータを渡す仕組みが見当たらなかったので、ややアホっぽいですが nanomsg を使うことにしました

nanomsgとは?

nanomsgは、TCP、UDP、スレッド間通信、プロセス間通信など様々なプロトコルや通信方式に対応した便利なソケットライブラリです。

C++、Pythonの両方で使えるのと、Windows環境でのプロセス間通信に対応していたので試してみることにしました。

CPlusPlus TOP用モジュールの実装

C:\Program Files\Derivative\TouchDesigner099\Samples\CPlusPlus\CPUMemoryTOP\ あたりにあるサンプルを見ながらC++を黙々と書いていきます。

getTOPDataInCPUMemory 関数でTOPのピクセルデータをメインメモリに読み出すのですが、その時のオプションとして OP_TOP_INPUT_DOWNLOAD_DELAYED を指定しないとひどく遅いのでそこだけ注意です。

    OP_TOPInputDownloadOptions options;
    options.downloadType = OP_TOP_INPUT_DOWNLOAD_DELAYED;
    options.cpuMemPixelType = RGBA8Fixed;
    options.verticalFlip = true;

    const uint8_t* src = (const uint8_t*)inputs->getTOPDataInCPUMemory(input, &options);

    if (!src) return;

送信側のソースコードは こちら

Pythonの受信側

それではPython側でメッセージを受け取る部分です!

nnpy というモジュールが調子よかったのですが、Windows環境でのビルドがすごい大変だったのでgithubにモジュールのバイナリも一緒に上げてあります。

ちなみに、Tipsとして ↓ のような感じのスクリプトを適当なタイミングで呼び出しておくと .toe と同階層にある python フォルダを動的にモジュールパスに追加できてひじょうに便利です

import os, sys

PATH = os.path.join(os.path.abspath('.'), 'python')
if not PATH in sys.path:
    sys.path.append(PATH)

Cookの制御

cook-dep.png

途中で言語をまたいだ通信が入っていたりで、内部的に結構ややこしい事になってしまっているのでそれぞれのスクリプトをどのタイミングで走らせればいいかも、だいぶこんがらがっています :disappointed_relieved:

TouchDesignerでは基本的に見えていない部分はCookをしない最適化がかかります。

今回のようにTOPに入力したものを外部のライブラリ経由で飛ばして~ というようなことをすると、オペレーターが見えなくなった時にCookが走ってくれない可能性大だったので Null CHOPCook TypeAlways にして、そこから順繰りに参照していくことで全体的にCookが止まらないような依存関係を組みました。(ちょっとやりすぎかもしれない)

また CPlusPlus TOP の仕様? で一番最初に強制的にCookをしないと処理が初まってくれなかったのでそこは Execute DATonStart を使って起動時にCookを走らせるようにしています。

まとめ

TouchDesignerではC++で独自オペレーターが作れるので工夫次第である程度踏み込んだ所でもユーザーレベルでどうにかできる事が多々あります。

現在099のExprementalではSOPもC++で拡張できるようになっているので、Pythonではパフォーマンス的に厳しい所などがあればどんどんC++で補って便利にしていきたいですね!

それでは!:raised_hand: