チュートリアル25

ムービーの色位置のトラッキング


色のトラッキング(追跡)

マトリクスの内容を分析するには多くの方法があります。チュートリアルのこの章では、イメージの色情報に注目した非常にシンプルな1つの方法をご紹介します。ここでは、どのようにしてイメージの中の特定の色(あるいは色範囲)を見つけるか、そして、ビデオの1つのフレームから次のフレームへ進む間に起こるその色の位置の変化をどのようにしてトラッキング(追跡)するかという問題を考えます。これは、ビデオの中でのある物体の運動についての情報を得たり、身体的な動作をトラッキングしたりする場合に役立ちます。より一般的に言えば、このテクニックはデータのマトリクスの中で特定の数値(または数値の範囲)の位置を見つけるために役立てることができます。


jit.findboundsオブジェクト

イメージの中の特定の色を見つけるために使用するオブジェクトとして、jit.findboundsと呼ばれるものがあります。ここではビデオの中の色をトラッキングしますから−もうお解りのように−4プレーンで2次元のcharデータ型マトリクスを分析しますが、jit.findboundsオブジェクトはどんなデータ型、どんなプレーン数のマトリクスに対してでも使用することができます。

jit.findboundsの動作は次のように行われます。jit.findboundsのminとmaxというアトリビュートを使って、各々のプレーンで探そうとする値の最小値と最大値を指定します。jit.findboundsオブジェクトは、マトリクスを受け取ると、そのマトリクス全体を見渡して個々のプレーンに指定された範囲に入る値を探します。そして、jit.findboundsは、指定された値が見つかった範囲を示すセルインデックスを出力します。実際には、値が見つかった範囲の境界のインデックスを出力します。2Dマトリクスの場合、境界領域は矩形になるので、jit.findboundsオブジェクトは指定された値が見つかった領域の左上と右下のセルのインデックスを出力します。

・Jitter Tutorialフォルダの25jColorTracking.patというチュートリアルパッチを開いて下さい。

この例では、jit.qt.movieオブジェクトによって、赤いボールが動き回るムービー(実際にはアニメーション)を再生しています。これは、明らかにほとんどのビデオで見られるものより単純なシチュエーションですが、jit.findboundsオブジェクトがどのように動作するかを見るためには、わかりやすい状況を設定してくれます。jit.findboundsオブジェクトのmin及びmaxアトリビュートを初期化するためにアーギュメントがあらかじめ書き込んである点に注意して下さい。


最小値と最大値は4つのプレーンのそれぞれについて指定されています

これらのアトリビュートに対しては4つのアーギュメント−jit.findboundsオブジェクトが受け取るマトリクスの4つのプレーンそれぞれについて1つの値−があります。minアトリビュートは個々のプレーンにおいて許容する最小値を、maxアトリビュートはその最大値を設定します。このアーギュメントによって jit.findboundsオブジェクトは、アルファプレーンについては0〜1、赤のプレーンについては0.75〜1、緑と青のプレーンについては0〜0.1の間にある、あらゆる値を探します。マトリクスのデータはchar型であるため、探索したい値は0〜1の小数で指定しなければなりません。(charの値がどのように色の表現に用いられるかについてはチュートリアル5、6の説明を参照して下さい。)ここでは赤いボールの位置をトラッキングしたいので、jit.findboundsオブジェクトに対して赤のブレーンが非常に大きな値を持ち、緑と青のプレーンが非常に低い値を持つセルを探すように命じました。(アルファプレーンはどんな値であっても構いません。)

・toggleをクリックしてmetroをスタートさせて下さい。赤いボールが動き回っているのに合わせて、jit.findboundsオブジェクトはボールに外接する長方形のセルインデックスを出力します。metroをストップさせ、jit.findboundsが出力した数値を検証して下さい。こんな感じになっていると思います。


jit.findboundsオブジェクトは指定した色が現れた領域を出力します。

jit.findboundsオブジェクトは、同じセルの全てのプレーンで目標値を発見できた領域を出力します。この図の場合、jit.findboundsオブジェクトは求められる値を、列120〜159、及び行50〜89の範囲内で発見しています。赤いボールの直径はちょうど40ピクセルですからうまく合致しています。このセルインデックスは、ビデオのこのフレームでボールが位置する場所を40×40の正方形のセル領域として示しています。

jit.findboundsオブジェクトの最初の2つのアウトレットからの出力が2つの値から成るリストである点に注意して下さい。最初のアウトレットは値が見つかった領域の最初のセルインデックスを各次元ごとに、2番目のアウトレットは領域の最後のセルインデックスを各次元ごとに出力しています。(ここで扱っているのは2Dマトリクスですから、各々のリストは2つの値しか持っていません。これらの値を個別に見るために、ここではunpackオブジェクトを使っています。)

ビデオフレーム内のボールの位置を表わす1つの点が必要な場合、jit.findboundsオブジェクトが出力する矩形領域の中心点を求めてこれをボールの「位置」と考えることができます。exprオブジェクトはこの操作を行っています。次元ごとに最初のセルと最後のセルの差を取り、2つの値の中心点を見つけるためにこれを2で割って最初のセルインデックスの値に加えることにより、「位置」を表わす1つの点を求めています。


矩形の中心点の計算

垂直次元の値を求めるために、実際には垂直座標を239から引いていることに注意して下さい。これは、セルインデックスが上から下へ数えられるのに対し、ここでは下から上へという対象の「高さ」を考えたいからです。(これはまたusliderオブジェクトの動作にも関係します。ここでは垂直座標をusliderを用いて表示するつもりですので、座標を下から上へと増加するように表わす必要があります。)

「位置」の計算結果をhsliderusliderに送ってボールの中心点がうまくトラッキングできている様子を示し、この座標値をナンバーボックスオブジェクトに表示しています。さらに、座標値を0〜1の範囲にスケーリングし、このボールの水平及び垂直位置が、すぐにでもMaxパッチの他の部分の動作やアトリビュートの加工に利用できる可能性があることを示しています。例えば、垂直位置によってビデオやMSPのボリュームをコントロールする、あるいは水平座標によってイメージの回転を行うといったことが考えられます。


パッチの他の部分での利用のために位置座標を0〜1の範囲にスケールしています


複雑なイメージにおけるカラートラッキング

はっきりとした白い背景の中のくっきりとした赤いボールというシンプルな例ではすべてが完璧にうまくいきました。しかし、「実世界」のビデオでの1つの物体のトラッキングはかなり厳しいものがあります。ここで、起きるであろういくつかの問題点とそれを解決するためのトリックについて述べておきましょう。

・赤いボールのムービーが停止していることを確認して下さい。そして、patcher bballtrackingオブジェクトをダブルクリックして、A More Detailed Example の内容を見て下さい。[bballtracking] サブパッチの左上隅にあるStart/Stopと表示されたtoggleをクリックして、ビデオをスタートさせて下さい。

このムービーには赤いシャツ、緑のパンツ、黄色と青のボールという鮮明な色を持った対象物があります。これはカラートラッキングに使える可能性を秘めています。しかし、このボールのトラッキングを行うためには、前の例に比べてちょっと難しい要素がいくつかあります。

まず第一に、ビデオの最上部のわずかなスキャンライン(マトリクスの最初の数行)には、実際に分析の対象としないゴミ(不要な情報)が含まれています。このゴミは、このビデオの不完全なデジタル化による不幸な産物です。このような不完全さは普通に見られるもので、分析処理を面倒なものにします。第二に、イメージが高い彩度を持っていないため、必要とされるほど色の違いが明確でないという点です。第三に、4秒間のクリップの最後ではボールが完全にフレームから消えてしまうという点です。(jit.findboundsオブジェクトは、探している値の存在を見つけることができない場合、最初と最後のセルインデックスとして-1を出力します。)第四に、フレームの中でボールの位置を見つけるために黄色をトラッキングしようと考える場合、ボールが黄色一色ではないことを認識している必要があるという点です。ボールのテクスチャ(表面の模様)やライティング(照明)によって、実際には「黄色味がかった範囲」として見えます。このため、この範囲を注意深く識別してjit.findboundsオブジェクトに設定する必要があります。

これらの問題点を解決してみましょう。チュートリアル14では、いくつかのJitterオブジェクトによってマトリクス全体ではなく、見たい部分の「ソース」矩形領域を表示することができました。チュートリアル14で、jit.matrixオブジェクトのsrcdimstart、srcdimend、そしてusesrcrectアトリビュートについて説明し、またjit.qt.movieオブジェクトにはそれに相当するsrcrect、usesrcrectというアトリビュートがあることに言及しました。jit.qt.movieオブジェクトのこれらのアトリビュートを使ってビデオイメージをトリミングし、必要のない部分を取り除くことにしましょう。

・Crop source Imageと表示されたメッセージボックスをクリックして下さい。これによって、私たちが必要とする新しいソース矩形領域のセルインデックスがjit.qt.movieオブジェクトに送られ、マトリクス全体に代わってそのソース矩形領域を使用するようオブジェクトに指示します。この領域が行4から始まり(これで、マトリクスの5番目の行から始めることになります)、イメージの最初にあるゴミをトリミングしている点に注意して下さい。さらに、ボールの最初のバウンドがちょうど左下隅で行われるため、ソースイメージの左側の20ピクセルもトリミングしています。これで、ビデオの分析したい部分に焦点を当てることができました。

・次に他の問題を考えてみましょう。ウィンドウの右下隅にあるSetupと表示された小さなpresetオブジェクトをクリックして下さい。これによって全てのユーザインターフェイスオブジェクトを望ましい設定にセットします。

ここでは、jit.qt.movieオブジェクトのloopアトリビュートを2の「往復再生」に設定し、ループの終了点を2160(54番目のフレームが表示される瞬間)に設定しています。このため、ムービーはフレーム0からフレーム53まで進み、逆戻りします。ムービーはちょうどボールが最初に舗道にバウンドする瞬間まで再生され、その後逆方向に進みます。

さらに、jit.brcosaオブジェクト(チュートリアル7に詳しい説明があります)にいくつかの値を送ってオブジェクトのbrightness、contrast、saturationアトリビュートを適した値に設定しています。この設定はイメージとして見るためには必ずしもベストなものではありませんが、色の違いをより明白にし、色の値をより小さな範囲に押し込めることによってjit.findboundsオブジェクトがよりトラッキングを行いやすいようにしています。

加えて、(パッチの中程にある)jit.matrixオブジェクトのusesrcdimアトリビュートをオンにしているため、オブジェクトはjit.findboundsオブジェクトの出力によってソース矩形領域を決定します。Show Tracked Region と表示されたjit.pwindowにトラッキングされた領域が表示されるのを見ることができます。


jit.findboundsオブジェクトの出力を、jit.matrixオブジェクトの
srcdimstartとsrcdimendアトリビュートの設定として使っています

ボールの下地の黄色は赤と緑の値をほぼ同等に持っているので、jit.findboundsオブジェクトのmin及びmaxアトリビュートには赤と緑のプレーンの値が高く、青のプレーンの値が低いセルを探すように設定しています。jit.brcosaの設定、及びjit.findboundsのmin、maxアトリビュートをの設定を注意深く行うことによって、ボールの黄色い部分に対する非常に信頼性の高いトラッキング結果が得られるように処理しているのがお判りになると思います。

注記:ここでは実際に言及しなかった非常に重要な項目の1つは、ビデオの特定の色を効果的にトラッキングするためにjit.findboundsオブジェクトのmin及びmaxアトリビュートをどのように設定したらよいかということです。これにはある程度の試行錯誤を伴う調整が必要ですが、チュートリアル10で紹介した suckahオブジェクトを使うことによって特定のピクセルの色についていくつかの非常に明確な情報を得ることができます。分析しようとするビデオを表示するjit.pwindowの上にsuckahオブジェクトを重ね、トラッキングを行いたい色の上をクリックして、その時のsuckahオブジェクトの出力を利用してそのセルのRGB情報を得ることができます。(suckahオブジェクトから出力される値は0〜255の範囲にありますが、これを255.0で割ることによって0〜1の範囲に直すことができます。)



オブジェクトの位置情報を利用する

このようにして、少なくともこの特定の状況においては、ビデオ内の1つの物体をトラッキングするうえでの問題点をなんとか克服することができました。しかし、これを成し遂げた後、私たちが得たこの報を使って何をしたらよいでしょうか?ここでは、オブジェクトの位置情報を使ってサウンドをコントロールする2つの方法をご紹介します。それは、MIDIノート、あるいはMSPトーンの演奏を行うことです。どちらの例も音楽的に非常に洗練されているとは言えませんが、位置情報をサウンド情報にマッピングする際の基本的な問題を示すのに役立つに違いありません。

ここでは、このパッチの中のUse Tracking Infoと表示された部分に置かれた2つのサブパッチに位置情報を送っています。packオブジェクトを使ってjit.findboundsオブジェクトの全ての出力を4つの要素からなる1つのリストにまとめ、gateオブジェクトを使ってその情報をpatcher playnotesサブパッチ(MIDI ノートの演奏)、patcher playtonesサブパッチ(MSPトーンの演奏)、またはどちらでもない(サウンドを鳴らさない)状態のいずれかにルーティングしています。


位置情報を2つのサブパッチのうちの1つに送ります

ノート:チュートリアルにあるMIDIまたはMSPを含む例を動作させるためには、あなたがお持ちの機器を正しく設定しておく必要があります。MIDIを使った例では、OMSがインストールされていて、Maxの仮想MIDIポートa にマルチティンバーシンセサイザ・キーボードが接続されていることを前提としています。MSPを使った例では、MSPがインストールされていて、DSPステータスウィンドウの中の適切な出力デバイスをセットするためのドライバを持っていることが前提となります。

機器の設定についてのより詳しい情報はMax Getting Started マニュアルの"Setup"セクション、Max Tutorials and Topics マニュアルの"Introduction"セクション、MSPマニュアルの"Audio I/O"セクションを参照して下さい。


ノートの演奏

・Use Tracking Infoと表示されたubumenuの中のメニューアイテム 1 = Play MIDI Notes を選択して下さい。patcher playtonesオブジェクトをダブルクリックして、[playnotes]サブパッチの内容を見て下さい。何の音も演奏されない場合(そして、ムービーが再生されたままであることが確認できた場合)は、 noteout a オブジェクトをダブルクリックしてデバイスダイアログボックスの他のMIDIシンセサイザを選択してみて下さい。


[playnotes]サブパッチの内容


[playnotes]サブパッチでは、最初の例の中で使用したものと同様なマッピングの式を使っています。最初の例の場合は、ボールの位置座標を計算してその情報を有用な範囲に置くというものでした。ここでは、水平位置を計算し、それを16で割って、0〜19までの範囲にあるような値を得ています。また、重複した数値(すなわち、繰り返されたノート)を無視するためにchangeオブジェクトを使い、その後tableオブジェクトから演奏するノートを探し出すようにしています。

注記:バスケットボールプレイヤの動きは、特定の音階とは何の関係もありません。そのため、ナマの位置データをMIDIキーナンバとして使った場合には無調のインプロヴィゼーションになります。(そうすることが決して間違っているわけではありません!)ピッチの選択に調性的な意味合いを持たせたい場合、ボールの水平方向の運動によって生成された数値を、ルックアップテーブル(tableオブジェクト)に格納した音階の音を探すためインデックスナンバとして使うことができます。tableの内容を見たい(或いは、変えたい)場合には、tableオブジェクトをダブルクリックして、グラフィックエディタウィンドウを開いて下さい。


ボールの垂直位置(0〜119の範囲にマップしてあります)は、ベロシティ値を決めるために使っています。 makenoteオブジェクトはノートに持続時間(200ミリ秒)を割当て、MIDIノートオフメッセージを出力するよう気をつけています。音楽の最も根底となるパルス(毎秒20パルス)はムービーを再生する metroの速さによって決定されていますが、changeオブジェクトが繰り返しの音を削除するため、全てのパルスにおいてMIDIノートが鳴らされるとは限りません。

・[playnotes]サブパッチウィンドウを閉じて下さい。Crop and Flip source Imageと表示されたメッセージボックスをクリックして下さい。これは、jit.qt.movieオブジェクトにイメージを水平方向に反転するための新しいソース矩形領域を送ります。これによって[playnote]サブパッチの音楽効果の音の高低が逆転します。


トーンの演奏

・Use tracking Infoと表示されらubumenuから、メニューアイテム 2 = Play MSP Tones を選択して下さい。patcher playtonesオブジェクトをダブルクリックして、[play tones]サブパッチの内容を見て下さい。


色の位置をMSPオシレータの周波数コントロール情報として使います

ここでは、バスケットボールの水平及び垂直位置座標をMSPオシレータの周波数値として使っています。これらの値を計算する方程式はいくぶん恣意的なものですが、2つの座標値を同じ周波数領域にマップするよう工夫されています。水平座標はオーディオの左チャンネルのオシレータをコントロールするために用いられ、垂直座標は右チャンネルのオシレータの周波数をコントロールするために用いられています。

受信されるメッセージの存在自体をMSPオーディオをオンにする(サウンドレベルを徐々に上げる)ために使っていて、メッセージが200ミリ秒以上受信されない場合にはサウンドをフェイドアウトさせ、オーディオをオフにします。


最初のメッセージによってオーディオがスタートされフェードインされます;
メッセージが201ミリ秒以上受信されないとフェイドアウトされオーディオがオフになります


・[playtones]サブパッチウィンドウを閉じて下さい。Crop Source Image及びCrop and Flip Source Image と表示されたメッセージボックスをクリックしてビデオイメージを垂直方向に反転し、MSPオシレータに対する効果の違いを聞いて下さい。


さらに多くの情報を引き出す

このチュートリアルでは、色領域の位置情報を直接サウンドシンセシスやMIDI演奏のパラメータ制御に使うといった非常に簡単な実装例をお見せしました。少し手の込んだMaxプログラミングを用いることによって、物体の動きについての情報をより多く引き出すことができる可能性があります。

例えば、1つのビデオフレームでのオブジェクトの位置を前のフレームでの位置と比較し、ピタゴラスの定理を用いてオブジェクトのフレーム間の移動距離を計算して速度を割り出す、さらにその動きの傾斜(Δy/Δx)を計算し、(三角関数アークタンジェントを使って)移動角を割り出す、ある速度と前の速度を比較して、加速度を計算する、等々のことが可能です。1つのフレームでのオブジェクトの見かけ上の大きさを次のフレームのものと比較して、z軸(奥行き方向)上にあるカメラに近づく、或いは遠ざかるといった動きについてのおよその推測をすることさえ可能です。


まとめ

jit.findboundsオブジェクトはマトリクスの各プレーンで特定の範囲内にある値を探し、各プレーンで指定された範囲内の値を見つけることができたマトリクス上の領域を出力します。これは、どのようなな数値データの範囲を、どのような型のマトリクス状で見つけようとする場合でも役立ちます。特に、4プレーンマトリクスで特定の色の位置を見つけるために使用することができるので、これをビデオで物体の動きをトラッキング(追跡)するために用いることができます。

jit.qt.movieオブジェクトのsrcrectアトリビュートによるビデオイメージのトリミングは、ソースイメージの必要な部分に焦点をあてるための手助けとなります。jit.brcosaオブジェクトは、ソースビデオのカラー値の調整をするために役立ちますが、これによって特定な色あるいは色の範囲の分離、探索がしやすくなります。

jit.findboundsオブジェクトの出力を使って物体の位置をトラッキングすることができ、さらにこの出力からオブジェクトの動きについての他の情報、例えば速さ、方向等を計算することができます。このような取り出した情報を使って、MIDI演奏、MSPシンセシス、あるいは他のJitterオブジェクトに関するパラメータをコントロールすることができます。