今回は、Webカメラ(USBカメラ)を使ってProcessing上で動体検知/動体追跡の実験を行ってみます。前回の「Processing Webカメラ/カラートラッキング」に似たプログラムですが、特定の色を追いかけるのではなく、画面上で動いている物体を検知し、その動きの方向に合わせて物体の座標値を取得します。逆に、動いている物体が画面内に見当たらない場合は、なにも検知しないことになります。
*Windowsの場合、そのままの設定ではこのVideoライブラリを使用することができません。WinVDIG 1.0.1をインストールする必要があります。
各ピクセルの色の取得:
・カメラ画像における、前回の画面と今回の画面の各ピクセルの色を比較します。
・320×240の画面サイズであれば76800個のピクセルをfor()を使って繰り返しの比較処理をさせることになります。
・各ピクセルの色を抽出するには、pixels[i]で順番にひとつずつピクセルを取り出します。
・pixels[i]は、画面内のi番目のピクセルの色の値を返します。
・さらに、その一つのピクセルをRGBの3色に分解し、それぞれの値を取得します。
・3色のそれぞれの値を取得するには、red()、green()、blue()を用います。
・red(pixels[i])と書けば、そのピクセルの赤の値を取得できます(緑、青についても同様に処理)。
色の比較:
前回と今回の画面内のピクセルを比較するためには、一旦前回の全ピクセルの色情報を配列に代入して記憶させておきます。そして、記憶させておいた前回の色情報と今回の色情報を各ピクセルごとに比較します。
・色を比較するには、「前回の赤の値」から「今回の赤の値」を差し引きします(最終的に、絶対値abs()を使うので逆でも大丈夫です)。
・各色の値は0〜255までの段階があるので、その数値の差となります。緑や青についても同様に値の差を求めておきます。
・各色において、ある一定以上の差があるときに、画面内に「動作」があったと見なします。
・多少細かなノイズなどが含まれるので、差についてはある程度の許容値を設けておきます。例えば、±20以内の差であればノイズと見なし「動作なし」と判断し、それ以上の差があるときにだけ「動作あり」と見なすことにします。
平均値で座標を求める:
上記の方法で、設定した許容値を超えるピクセルがあったときに、そのピクセルの画面内でのXY座標値を調べておきます。今回の方法では、許容値を超えるピクセル(変化があったピクセル)のXY座標と個数から平均値を求め、その値をXとYの座標値として利用することにします。
例えば、X座標値100に10個、101に12個、102に8個あるときは、(100*10+101*12+102*8)/(10+12+8)=100.9333となり、この値を平均値としてX座標値にします。
(緑の部分が変化のあったピクセル、赤い正方形の位置がそれらの平均座標値、左上に許容値表示)
「変化があったピクセルを緑で表示し座標値を求めるプログラム」:
以下のプログラムでは、見やすくするために、変化があったピクセルを緑color(0,255,0)で塗りつぶすことにします。そして、それらのピクセルの平均座標値を求めて、赤い正方形を動かすことにします。
光や明るさの状況に合わせて許容値を調整できるプログラムにしておきます。
左右の矢印キーで色の許容値(変数:tolerance)を調節できるようにします(「←」:-1、「→」:+1)。
「c」キーを押せば、カメラセッティング画面に切り替わります(手動露出や手動コントラストなどに切り替えた方が認識しやすくなります)。
[プログラムを表示]
「Pongをプレイ」
次に、応用として「Pong」のパドルをモーショントラッキングで動かすサンプルをつくってみます。
動作によって変化があったピクセルの位置が画面内の左側あるいは右側を判別し、左右のパドルを個別に動かせるようにします。画面の端から50ピクセル幅のエリアで動作検知します(画面中央付近では反応しません)。
(モーショントラッキングで「Pong」をプレイする)
プレイしやすいように、カメラ映像は左右反転(鏡像)しています。
左右矢印キーで許容値を調整します(画面には許容値は表示されません)。
画面上部に点数を表示。
「c」キーでカメラセッティング。
「スペース」キーで点数をリセット。
[プログラムを表示]
関連:
Webカメラ:
「Processing Video (Webカメラ)」--Webカメラの使い方/映像にフィルタをかけて表示。
「Arduino+Processing マトリクスLED+Webカメラ」--Webカメラ映像をマトリクスLEDに映す。
「Processing Webカメラを光センサとして使う」--点光源で画面内に線を描く。
「Processing Webカメラ/定点記録画像」--Webカメラ映像を0.5秒おきに画像保存(JPEG)する。
「Processing Webカメラ/カラートラッキング」--Webカメラを使い、色を手がかりに物体を追いかける。
11/29/2008
11/26/2008
Processing Webカメラ/カラートラッキング
今回はProcessingとWebカメラ(USBカメラ)を使い、色を手がかりとして画面内で動く物体の座標値を取得してみます。例えば、カメラに向かって動かした赤いボールの座標値を検出し、XY座標をArduinoへシリアル通信すれば、ボールの動きに応じてサーボなどを動かすことができます。
最初に物体の色を記憶させ、その色に近いピクセルを画面内から抜き出します。抜き出されたピクセルのXY座標値を調べ、中点や平均値を使って最終的なXY座標を導き出します。必ずしも単一の色面を背景にする必要はないのですが、色を手がかりとするので、対象とする物体と背景の色の差がある方が検出しやすくなります。
尚、Webカメラを使った画像認識や動体検知などのプログラムとしてFile>Examples>Libraries>Video(Capture)の中に「BrightnessTracking」や「FrameDifferencing」などのサンプルがあります。また、ライブラリとしては「JMyron」があります(「JMyron」のサンプルでは「Myron_CameraAsMouse」があります)。
Webカメラ(USBカメラ)を使用するには、ProcessingのVideoライブラリをインポートします。Webカメラの基本的な使い方は「Processing Video (Webカメラ)」や色抽出する方法として「Processing Webカメラを光センサとして使う」を参照して下さい。
*Windowsの場合、そのままの設定ではこのVideoライブラリを使用することができません。WinVDIG 1.0.1をインストールする必要があります。
「Processing上の画面」
(手に握った物体の動きに合わせて赤い円が動く)
今回の設定として:
・キャプチャする映像のサイズ(幅:w、高さ:h)を320×240(4:3)にします。
(処理速度が遅くなる場合は160×120などの小さいサイズに変更して下さい。)
・最初に、画面内の対象となる物体をマウスでクリックし、そのピクセルの色を記憶しておきます。
(背景とはできる限り異なる色の物体を選ぶ方が認識しやすくなります。)
・物体の動きに合わせて、画面上の図形(赤い円)が動くプログラムにします。
プログラムの手順としては:
・video.pixels[]で、カメラ映像内の各ピクセル(320×240=76800ピクセル)を全て読み込みます。
・対象となる物体の色(特定の1ピクセル分の色)をpixels[]で取り出します。
・各ピクセルをred()、green()、blue()でRGBに分解します。
・各ピクセルの色と物体の色を各RGB色ごとに比較します。
・比較した各RGB色が設定した許容値(tolerance)以内であるかを判別します。
・許容値以内のピクセルがある場合、そのピクセルの座標値を調べます。
・選択された複数のピクセルの座標を統合して、最終的にXY座標を導き出します。
・導かれた座標を図形(赤い円)の座標に代入し、物体に合わせて図形(赤い円)が動くようにします。
「選択したピクセルの色をRGBに分解し判別する」:
ひとつのピクセルであるpixels[i]には、color(R,G,B)の3つの値が含まれています(アルファ値/透明度も含めれば4つになりますが、今回はRGB値だけを扱います)。各RGB色に分解するには、red(pixels[i])、green(pixels[i])、blue(pixels[i])というようにred()、green()、blue()を用いてpixels[i]を括ります。得られる値はそれぞれ0.0~255.0の小数値になります。色を特定化しても光の反射などによって多少色が変化するので、特定化する色にある程度の許容値を与えておきます。例えば、赤の値が80の場合、許容値を10にすることで70~90の値であれば同等の色と見なすことにします。許容値が小さすぎれば、色が限定されすぎるので取りこぼしがでてきます。逆に許容値が大きすぎれば、他の色を混同してしまうので、状況に応じて調整できるようにプログラムすることにします。
「pixels[i]をXY座標に変換する方法」:
画面幅をw=320、高さをh=240とします。横一列には320個のピクセルが並んでおり、さらに320個のピクセルが240行並んでいます。つまり一つの画面内には、合計で76800個のピクセルがあります。
pixels[i]のiには、画面左上の0番目のピクセルから画面右下の76799番目のピクセルまでの連続した数値が入ります。例えば、画面上の(120,40)というXY座標は、画面幅をwとした場合、120+40*w=12920なので12920番目のピクセルであり、pixels[12920]になります。逆に、この12920番目のピクセルを画面上のX座標とY座標に変換するには、x=i%w、y=i/w(つまり、x=12920%320、y=12920/320)となります。「%」は割り算の余りを求める式で、「/」は割り算ですが整数(int)で割っているので小数点以下は切り捨てられます(四捨五入なし)。
マウスの座標値(mouseX,mouseY)であれば、pixels[mouseX+mouseY*w]になります。
上記の方法で選ばれたピクセル(物体の色のピクセル)は複数個あるので、それらのピクセルを座標値に置き換えるには幾つかの方法があります。
ひとつは:
画面内において最も右端にあるピクセルのX座標と左端にあるピクセルのX座標、ならびに上端にあるピクセルのY座標と下端にあるピクセルのY座標を調べ、右端と左端の中点をX座標、上端と下端の中点をY座標とみなす方法です。弱点としては、近似色がノイズとして画面上にある場合、そのピクセルも拾ってしまうことです。ノイズを除去するプログラムや予め画面全体にぼかしをかけることである程度回避できます。
もうひとつは:
選択したピクセル(物体の色のピクセル)が多く分布している箇所を調べ、ピクセルの分布数と位置から平均値を割り出す方法です。この場合、多少のノイズがあっても大きなずれは発生しなくなります。
その他の方法も考えられますが、今回は上記二つの方法で実験してみたいと思います。
「操作手順」:
プログラムが開始したら、画面上で対象となる物体をクリックして物体の色を記憶させます。画面左上に、10ピクセル角の矩形でその色が表示されます。直径20ピクセルの赤い円が、物体の移動に合わせて動きます(物体を追跡します)。
左右の矢印キーで色の許容値(変数:tolerance)を調節できるようにします(「←」:-1、「→」:+1)。
変化する数値をPFontを用いて表示するので、Tools>Create Font...をクリックし「Monaco-10.vlw」を取り込んでおいて下さい(「Processing 文字と画像」を参照)。
また、「c」キーを押せば、カメラセッティング画面に切り替わります(手動露出や手動コントラストなどに切り替えた方が認識しやすくなります)。
画面上に許容値を含めた物体の色がある場合は、「detected」という文字が表示されます。もし、近似色がない場合は「none」が表示され、赤い円は前回の位置に留まります。再度近似色が画面内に現れれば、赤い円はその位置に移動します。
「左右端、上下端の中点を座標値にするプログラム」:
[プログラムを表示]
*プログラムを開始する前にTools>Create Font...をクリックし「Monaco-10.vlw」を取り込んでおいて下さい(スケッチフォルダの中のdataフォルダ内にフォントが保存されます)。
複数あるピクセルのうち左端、右端、上端、下端のピクセルを抜き出すために、最小値と最大値を求めるためのmin()、max()を用いました。各ピクセルの座標値を比較し、X座標においては最小座標値を左端座標値とし、最大座標値を右端座標値として扱います。Y座標に対しても同様に導き出します。そして、それらの中点を最終的なXY座標値とします。
「分布するピクセルから割り出す方法」:
次は、物体の近似色のピクセルの分布から平均値を求めて座標値を割り出す方法についてです。
先ほどの方法と同様にfor()で全てのピクセルの色を識別し、その中から物体の近似色のピクセルを選びます。その際に近似色のピクセルの個数と、そのピクセルのXY座標値をそれぞれ加算しておきます。最終的に加算されたそれぞれの値を近似色のピクセル数で割って平均値を求めます。例えば、X座標値100に10個、101に12個、102に8個あるときは、(100*10+101*12+102*8)/(10+12+8)=100.9333となります。Y座標についても同様に求めておきます。
以下のプログラムでは、カメラからの映像を左右反転の鏡像として表示することにします(カメラに向かって、右に物体を動かせば、画面上でも右に動くようにします)。
「v」キーを押すことで、カメラからの映像を表示/非表示切り替え可能にします。
円の動きを滑らかにするために、移動量にフィルタをかけることにしました。
物体検知用のフラグがtrueの場合、許容値toleranceは自動的に下がり、falseの場合は自動的に上がるようにしました(変化の範囲は2~25に設定してあります)。設定した最大許容値:25以内の近似色が画面内にある場合は反応してしまいます(フラグがtrueになる)。不自然な反応をとる場合、最大許容値を下げるか、前回のプログラムのように手動で調整する内容に変更してみてください。
赤文字部分が、前回と異なる部分です。
前回同様、プログラムを開始する前に、使用するフォントを取り込んでおいて下さい(「Processing 文字と画像」を参照)。
「分布するピクセルから割り出すプログラム」:
[プログラムを表示]
*プログラムを開始する前にTools>Create Font...をクリックし「Monaco-10.vlw」を取り込んでおいて下さい(「Processing 文字と画像」を参照)。
「filterX+=(x-filterX)*0.3;」の「0.3」は円の動きをゆっくり滑らかに(鈍く)するための係数です。1.0に近づくほどフィルタの効果はなくなり、0に近づくほど鈍く動くので適度に調整して下さい。
左右反転(鏡像)しているために、円のX座標値はそのままの値ではなく「w-filterX」になっています。
「ビット演算による色変換」:
color(R,G,B,A)は、A:アルファ値(透明度)、R:赤、G:緑、B:青の4種類の8ビット(合計32ビット)の値が含まれています。32ビットの内訳(2進数の場合)は
になります。32あるそれぞれの桁には0か1が入ります。
透明度が100%(不透明)の緑であれば、
になります。16進数であれば「0xFF00FF00」や「#00FF00」になります。10進数なら「255,0,255,0」です。
上記プログラムでは、ピクセルの赤の値を調べるためにpixels[i]をred()で括って
にしましたが、
というビット演算を使っても求められます。32ビットを16桁右にシフト「>>」し、下位8桁(0xFF)だけを「&」を使って取り出す(ビットマスク)という方法になります。
結果的にはこの方法の方が処理速度が上がるようです。
緑と青については、
になります。
もし、処理速度が不安定な場合は、上記のようなビット演算を用いるか、画面サイズを小さくするか、もともとのフレームレートを下げるかなどの工夫や調整を行ってみてください。
ドライバなしですぐにコンピュータに接続可能(UVC対応)なWebカメラとして以下のようなものがあります。
Macintosh/Windows兼用です。
関連:
「Processing Video (Webカメラ)」--Webカメラの使い方/映像にフィルタをかけて表示。
「Arduino+Processing マトリクスLED+Webカメラ」--Webカメラ映像をマトリクスLEDに映す。
「Processing Webカメラを光センサとして使う」--点光源で画面内に線を描く。
「Processing Webカメラ/定点記録画像」--Webカメラ映像を0.5秒おきに画像保存(JPEG)する。
「Processing Webカメラ/モーショントラッキング」--Webカメラを使って動体検知する。
最初に物体の色を記憶させ、その色に近いピクセルを画面内から抜き出します。抜き出されたピクセルのXY座標値を調べ、中点や平均値を使って最終的なXY座標を導き出します。必ずしも単一の色面を背景にする必要はないのですが、色を手がかりとするので、対象とする物体と背景の色の差がある方が検出しやすくなります。
尚、Webカメラを使った画像認識や動体検知などのプログラムとしてFile>Examples>Libraries>Video(Capture)の中に「BrightnessTracking」や「FrameDifferencing」などのサンプルがあります。また、ライブラリとしては「JMyron」があります(「JMyron」のサンプルでは「Myron_CameraAsMouse」があります)。
Webカメラ(USBカメラ)を使用するには、ProcessingのVideoライブラリをインポートします。Webカメラの基本的な使い方は「Processing Video (Webカメラ)」や色抽出する方法として「Processing Webカメラを光センサとして使う」を参照して下さい。
*Windowsの場合、そのままの設定ではこのVideoライブラリを使用することができません。WinVDIG 1.0.1をインストールする必要があります。
「Processing上の画面」
(手に握った物体の動きに合わせて赤い円が動く)
今回の設定として:
・キャプチャする映像のサイズ(幅:w、高さ:h)を320×240(4:3)にします。
(処理速度が遅くなる場合は160×120などの小さいサイズに変更して下さい。)
・最初に、画面内の対象となる物体をマウスでクリックし、そのピクセルの色を記憶しておきます。
(背景とはできる限り異なる色の物体を選ぶ方が認識しやすくなります。)
・物体の動きに合わせて、画面上の図形(赤い円)が動くプログラムにします。
プログラムの手順としては:
・video.pixels[]で、カメラ映像内の各ピクセル(320×240=76800ピクセル)を全て読み込みます。
・対象となる物体の色(特定の1ピクセル分の色)をpixels[]で取り出します。
・各ピクセルをred()、green()、blue()でRGBに分解します。
・各ピクセルの色と物体の色を各RGB色ごとに比較します。
・比較した各RGB色が設定した許容値(tolerance)以内であるかを判別します。
・許容値以内のピクセルがある場合、そのピクセルの座標値を調べます。
・選択された複数のピクセルの座標を統合して、最終的にXY座標を導き出します。
・導かれた座標を図形(赤い円)の座標に代入し、物体に合わせて図形(赤い円)が動くようにします。
「選択したピクセルの色をRGBに分解し判別する」:
ひとつのピクセルであるpixels[i]には、color(R,G,B)の3つの値が含まれています(アルファ値/透明度も含めれば4つになりますが、今回はRGB値だけを扱います)。各RGB色に分解するには、red(pixels[i])、green(pixels[i])、blue(pixels[i])というようにred()、green()、blue()を用いてpixels[i]を括ります。得られる値はそれぞれ0.0~255.0の小数値になります。色を特定化しても光の反射などによって多少色が変化するので、特定化する色にある程度の許容値を与えておきます。例えば、赤の値が80の場合、許容値を10にすることで70~90の値であれば同等の色と見なすことにします。許容値が小さすぎれば、色が限定されすぎるので取りこぼしがでてきます。逆に許容値が大きすぎれば、他の色を混同してしまうので、状況に応じて調整できるようにプログラムすることにします。
「pixels[i]をXY座標に変換する方法」:
画面幅をw=320、高さをh=240とします。横一列には320個のピクセルが並んでおり、さらに320個のピクセルが240行並んでいます。つまり一つの画面内には、合計で76800個のピクセルがあります。
pixels[i]のiには、画面左上の0番目のピクセルから画面右下の76799番目のピクセルまでの連続した数値が入ります。例えば、画面上の(120,40)というXY座標は、画面幅をwとした場合、120+40*w=12920なので12920番目のピクセルであり、pixels[12920]になります。逆に、この12920番目のピクセルを画面上のX座標とY座標に変換するには、x=i%w、y=i/w(つまり、x=12920%320、y=12920/320)となります。「%」は割り算の余りを求める式で、「/」は割り算ですが整数(int)で割っているので小数点以下は切り捨てられます(四捨五入なし)。
マウスの座標値(mouseX,mouseY)であれば、pixels[mouseX+mouseY*w]になります。
上記の方法で選ばれたピクセル(物体の色のピクセル)は複数個あるので、それらのピクセルを座標値に置き換えるには幾つかの方法があります。
ひとつは:
画面内において最も右端にあるピクセルのX座標と左端にあるピクセルのX座標、ならびに上端にあるピクセルのY座標と下端にあるピクセルのY座標を調べ、右端と左端の中点をX座標、上端と下端の中点をY座標とみなす方法です。弱点としては、近似色がノイズとして画面上にある場合、そのピクセルも拾ってしまうことです。ノイズを除去するプログラムや予め画面全体にぼかしをかけることである程度回避できます。
もうひとつは:
選択したピクセル(物体の色のピクセル)が多く分布している箇所を調べ、ピクセルの分布数と位置から平均値を割り出す方法です。この場合、多少のノイズがあっても大きなずれは発生しなくなります。
その他の方法も考えられますが、今回は上記二つの方法で実験してみたいと思います。
「操作手順」:
プログラムが開始したら、画面上で対象となる物体をクリックして物体の色を記憶させます。画面左上に、10ピクセル角の矩形でその色が表示されます。直径20ピクセルの赤い円が、物体の移動に合わせて動きます(物体を追跡します)。
左右の矢印キーで色の許容値(変数:tolerance)を調節できるようにします(「←」:-1、「→」:+1)。
変化する数値をPFontを用いて表示するので、Tools>Create Font...をクリックし「Monaco-10.vlw」を取り込んでおいて下さい(「Processing 文字と画像」を参照)。
また、「c」キーを押せば、カメラセッティング画面に切り替わります(手動露出や手動コントラストなどに切り替えた方が認識しやすくなります)。
画面上に許容値を含めた物体の色がある場合は、「detected」という文字が表示されます。もし、近似色がない場合は「none」が表示され、赤い円は前回の位置に留まります。再度近似色が画面内に現れれば、赤い円はその位置に移動します。
「左右端、上下端の中点を座標値にするプログラム」:
[プログラムを表示]
//ビデオライブラリのインポート
import processing.video.*;
Capture video;//インスタンス生成
PFont font;//フォントを用意
int w=320;//画面幅
int h=240;//画面高
int tolerance=15;//色許容値用の変数(後で調整可)
color targetColor=color(255,0,0);//物体の色用の変数(後で変更可)
int x;//図形座標用変数
int y;
int xmin=w,xmax=0;//左端X座標、右端X座標
int ymin=h,ymax=0;//上端Y座標、下端Y座標
boolean detection=false;//物体検知のフラグ
void setup(){
size(w, h);//画面サイズ設定
smooth();//滑らかな描画に設定
video = new Capture(this, w, h);//キャプチャ映像の設定
font=loadFont("Monaco-10.vlw");//フォントをロード
textFont(font);//フォントの設定
noStroke();//外形線なし
}
void draw() {
if(video.available()){//キャプチャ映像がある場合
video.read();//映像読み込み
//video.filter(BLUR,2);必要に応じてぼかしフィルタをつかう(ノイズ除去用)
set(0,0,video);//映像表示
detection=false;//物体検知のフラグをfalse(検知なし)にしておく
for(int i=0;i<w*h;i++){//画面全体のピクセル数だけ繰り返し処理
//物体の色と各ピクセルの色の差を求める(RGB3色分)
float difRed=abs(red(targetColor)-red(video.pixels[i]));
float difGreen=abs(green(targetColor)-green(video.pixels[i]));
float difBlue=abs(blue(targetColor)-blue(video.pixels[i]));
//RGB各色が許容値以内の場合(近似色である場合)
if(difRed<tolerance && difGreen<tolerance && difBlue<tolerance){
//フラグを物体検知有りにする
detection=true;
//左端、右端のX座標、上端、下端のY座標を導く
//今回の値と今までの値を比較し、最小値、最大値を調べる
xmin=min(i%w,xmin);//左端(X最小値)
xmax=max(i%w,xmax);//右端(X最大値)
ymin=min(i/w,ymin);//上端(Y最小値)
ymax=max(i/w,ymax);//下端(Y最大値)
}
}
if(detection==true){//物体検知有りの場合
x=(xmin+xmax)/2;//X座標を左端と右端の座標の中点とする
y=(ymin+ymax)/2;//Y座標を上端と下端の座標の中点とする
//左端、右端、上端、下端の座標値を初期化しておく
xmin=w;
xmax=0;
ymin=h;
ymax=0;
}
}
fill(255,0,0);//塗り色:赤
ellipse(x,y,20,20);//円描画(求めたXY座標を代入)
//以下は設定内容の表示
fill(targetColor);//指定した物体の色
rect(0,0,10,10);//矩形表示
String s;//物体検知有無表示の文字列変数
if(detection==true){//物体検知有りの場合
s="detected";//表示:「検知」
}else{
s="none";//表示:「なし」
}
text(tolerance+": "+s,20,10);//文字列表示(許容値:物体検知有無)
}
void mousePressed(){//クリックしたら
//マウス座標上のピクセルの色(物体の色)を記憶しておく
targetColor=video.pixels[mouseX+mouseY*w];
}
void keyPressed(){
if(key=='c'){//「c」キーを押した場合
video.settings();//カメラセッティング
}
if(key==CODED){
if(keyCode==LEFT){//左キーを押した場合
tolerance-=1; //許容値を-1する
}
if(keyCode==RIGHT){//右キーを押した場合
tolerance+=1; //許容値を+1する
}
}
}
*プログラムを開始する前にTools>Create Font...をクリックし「Monaco-10.vlw」を取り込んでおいて下さい(スケッチフォルダの中のdataフォルダ内にフォントが保存されます)。
複数あるピクセルのうち左端、右端、上端、下端のピクセルを抜き出すために、最小値と最大値を求めるためのmin()、max()を用いました。各ピクセルの座標値を比較し、X座標においては最小座標値を左端座標値とし、最大座標値を右端座標値として扱います。Y座標に対しても同様に導き出します。そして、それらの中点を最終的なXY座標値とします。
「分布するピクセルから割り出す方法」:
次は、物体の近似色のピクセルの分布から平均値を求めて座標値を割り出す方法についてです。
先ほどの方法と同様にfor()で全てのピクセルの色を識別し、その中から物体の近似色のピクセルを選びます。その際に近似色のピクセルの個数と、そのピクセルのXY座標値をそれぞれ加算しておきます。最終的に加算されたそれぞれの値を近似色のピクセル数で割って平均値を求めます。例えば、X座標値100に10個、101に12個、102に8個あるときは、(100*10+101*12+102*8)/(10+12+8)=100.9333となります。Y座標についても同様に求めておきます。
以下のプログラムでは、カメラからの映像を左右反転の鏡像として表示することにします(カメラに向かって、右に物体を動かせば、画面上でも右に動くようにします)。
「v」キーを押すことで、カメラからの映像を表示/非表示切り替え可能にします。
円の動きを滑らかにするために、移動量にフィルタをかけることにしました。
物体検知用のフラグがtrueの場合、許容値toleranceは自動的に下がり、falseの場合は自動的に上がるようにしました(変化の範囲は2~25に設定してあります)。設定した最大許容値:25以内の近似色が画面内にある場合は反応してしまいます(フラグがtrueになる)。不自然な反応をとる場合、最大許容値を下げるか、前回のプログラムのように手動で調整する内容に変更してみてください。
赤文字部分が、前回と異なる部分です。
前回同様、プログラムを開始する前に、使用するフォントを取り込んでおいて下さい(「Processing 文字と画像」を参照)。
「分布するピクセルから割り出すプログラム」:
[プログラムを表示]
import processing.video.*;
Capture video;
PFont font;
int w=320;
int h=240;
int tolerance=20;
color targetColor=color(255,0,0);
float x;//X座標変数(小数値)
float y;//Y座標変数(小数値)
int sumX,sumY;//座標平均値を求めるための加算用変数
int pixelNum;//近似色ピクセルの個数用変数
float filterX,filterY;//滑らかな動きのためのフィルタ用変数
boolean videoImage=true;//カメラ映像の表示/非表示切り替えフラグ
boolean detection=false;
void setup(){
size(w, h);
smooth();
video = new Capture(this, w, h);
font=loadFont("Monaco-10.vlw");
textFont(font);
noStroke();
}
void draw() {
if(video.available()){
video.read();
scale(-1.0,1.0);//鏡像反転
if(videoImage){//カメラ映像表示の場合
image(video, -w, 0);//カメラ映像を表示する
}else{ //カメラ映像非表示の場合
background(0); //背景(黒)にする
}
detection=false;
for(int i=0;i<w*h;i++){
float difRed=abs(red(targetColor)-red(video.pixels[i]));
float difGreen=abs(green(targetColor)-green(video.pixels[i]));
float difBlue=abs(blue(targetColor)-blue(video.pixels[i]));
if(difRed<tolerance && difGreen<tolerance && difBlue<tolerance){
detection=true;
sumX+=(i%w);//X座標値を加算する
sumY+=(i/w);//Y座標値を加算する
pixelNum++;//近似色ピクセルの個数を加算する
}
}
if(detection){//物体検知有りの場合
x=sumX/pixelNum;//X座標平均値を求める
y=sumY/pixelNum;//Y座標平均値を求める
//初期化しておく
sumX=0;
sumY=0;
pixelNum=0;
tolerance--;//許容値を-1ずつ下げる
if(tolerance<2){//許容値が2より小さくなったら
tolerance=2; //許容値を2に戻す
}
}else{//物体検知無しの場合
tolerance++;//許容値を+1ずつ上げる
if(tolerance>25){//許容値が25より大きくなったら
tolerance=25; //許容値を25に戻す
}
}
}
scale(-1.0,1.0);//鏡像反転を戻しておく
filterX+=(x-filterX)*0.3;//X座標変化量のフィルタ、「0.3」は係数
filterY+=(y-filterY)*0.3;//Y座標変化量のフィルタ、「0.3」は係数
fill(255,0,0);//塗り色(赤)
ellipse(w-filterX,filterY,20,20);//フィルタ値を用いて円描画
//ellipse(w-x,y,20,20);//フィルタ値を使わない場合
fill(targetColor);
rect(0,0,10,10);
text(tolerance,20,10);
String s;
if(detection){
s="detected";
}else{
s="none";
}
text(s,40,10);
}
void mousePressed(){
targetColor=video.pixels[w-mouseX+mouseY*w];
}
void keyPressed(){
if(key=='c'){
video.settings();
}
if(key=='v'){//「v」キーを押して表示/非表示を切り替える
if(videoImage){
videoImage=false;
}else{
videoImage=true;
}
}
/*許容値調整は自動なので以下は使わない
if(key==CODED){
if(keyCode==LEFT){
tolerance-=1;
}
if(keyCode==RIGHT){
tolerance+=1;
}
}
*/
}
*プログラムを開始する前にTools>Create Font...をクリックし「Monaco-10.vlw」を取り込んでおいて下さい(「Processing 文字と画像」を参照)。
「filterX+=(x-filterX)*0.3;」の「0.3」は円の動きをゆっくり滑らかに(鈍く)するための係数です。1.0に近づくほどフィルタの効果はなくなり、0に近づくほど鈍く動くので適度に調整して下さい。
左右反転(鏡像)しているために、円のX座標値はそのままの値ではなく「w-filterX」になっています。
「ビット演算による色変換」:
color(R,G,B,A)は、A:アルファ値(透明度)、R:赤、G:緑、B:青の4種類の8ビット(合計32ビット)の値が含まれています。32ビットの内訳(2進数の場合)は
AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB
になります。32あるそれぞれの桁には0か1が入ります。
透明度が100%(不透明)の緑であれば、
11111111000000001111111100000000
になります。16進数であれば「0xFF00FF00」や「#00FF00」になります。10進数なら「255,0,255,0」です。
上記プログラムでは、ピクセルの赤の値を調べるためにpixels[i]をred()で括って
red(pixels[i])
にしましたが、
(pixels[i] >> 16) & 0xFF
というビット演算を使っても求められます。32ビットを16桁右にシフト「>>」し、下位8桁(0xFF)だけを「&」を使って取り出す(ビットマスク)という方法になります。
結果的にはこの方法の方が処理速度が上がるようです。
緑と青については、
(pixels[i] >> 8) & 0xFF //緑:8ビット右にシフトし下位8桁だけを取り出す
pixels[i] & 0xFF //青:下位8桁だけを取り出す
になります。
もし、処理速度が不安定な場合は、上記のようなビット演算を用いるか、画面サイズを小さくするか、もともとのフレームレートを下げるかなどの工夫や調整を行ってみてください。
ドライバなしですぐにコンピュータに接続可能(UVC対応)なWebカメラとして以下のようなものがあります。
Macintosh/Windows兼用です。
関連:
「Processing Video (Webカメラ)」--Webカメラの使い方/映像にフィルタをかけて表示。
「Arduino+Processing マトリクスLED+Webカメラ」--Webカメラ映像をマトリクスLEDに映す。
「Processing Webカメラを光センサとして使う」--点光源で画面内に線を描く。
「Processing Webカメラ/定点記録画像」--Webカメラ映像を0.5秒おきに画像保存(JPEG)する。
「Processing Webカメラ/モーショントラッキング」--Webカメラを使って動体検知する。
ラベル:
processing,
Webカメラ,
カラートラッキング
10/11/2008
Processing Webカメラ/定点記録画像
身体の動作などを連続写真として記録するために、Webカメラを用いインデックス番号をつけて画像保存する方法です。設定したフレームレートで撮影画像を順番に保存していきます。以下は、フレームレート2の速度(0.5秒/フレーム)で処理するサンプルです。sキーで連続写真の画像を0.5秒おきに保存し、eキーで保存を終了、cキーでカメラセッティング画面に切り替わります。
videoライブラリの基本的な使い方は「Processing Video(Webカメラ)」を参照して下さい。
*Windowsの場合、そのままの設定ではこのVideoライブラリを使用することができません。WinVDIG 1.0.1をインストールする必要があります。
連続写真の画像は、撮影された数だけスケッチフォルダのなかに保存されます。
(スケッチフォルダの中にインデックス番号を含んだ保存名で保存される/MacOSXの場合)
上図の場合、「image_0.jpg」から「image_10.jpg」までの合計11枚の画像が保存されています。フレームレートは2なので、約5.5秒間撮影(連続保存)したことになります。
関連:
「Processing Video (Webカメラ)」--Webカメラの使い方/映像にフィルタをかけて表示。
「Arduino+Processing マトリクスLED+Webカメラ」--Webカメラ映像をマトリクスLEDに映す。
「Processing Webカメラを光センサとして使う」--点光源で画面内に線を描く。
「Processing Webカメラ/カラートラッキング」--Webカメラを使い、色を手がかりに物体を追いかける。
「Processing Webカメラ/モーショントラッキング」--Webカメラを使って動体検知する。
videoライブラリの基本的な使い方は「Processing Video(Webカメラ)」を参照して下さい。
*Windowsの場合、そのままの設定ではこのVideoライブラリを使用することができません。WinVDIG 1.0.1をインストールする必要があります。
//ライブラリの取り込み
import processing.video.*;
Capture myCapture;
//記録開始用のフラグ
boolean start=false;
//記録画像インデックス用変数
int num=0;
void setup() {
//画面サイズ設定
size(320, 240);
//キャプチャする映像の設定(2フレーム/秒)
myCapture = new Capture(this, width, height, 2);
//ループのフレームレート(2フレーム/秒)
frameRate(2);
}
void draw() {
//映像を画面に配置
image(myCapture, 0, 0);
if(start){
//記録中の目印表示
rect(0,0,10,10);
//記録画像インデックス名(jpgで保存)
String s="image_"+num+".jpg";
//画像を保存
save(s);
//インデックス番号を更新
num++;
}
}
//映像の読み込み
void captureEvent(Capture myCapture) {
myCapture.read();
}
void keyPressed(){
//sキーで画像記録開始
if(key=='s'){
start=true;
}
//eキーで記録終了
if(key=='e'){
start=false;
}
//cキーでカメラセッティング
if(key=='c'){
myCapture.settings();
}
}
連続写真の画像は、撮影された数だけスケッチフォルダのなかに保存されます。
(スケッチフォルダの中にインデックス番号を含んだ保存名で保存される/MacOSXの場合)
上図の場合、「image_0.jpg」から「image_10.jpg」までの合計11枚の画像が保存されています。フレームレートは2なので、約5.5秒間撮影(連続保存)したことになります。
関連:
「Processing Video (Webカメラ)」--Webカメラの使い方/映像にフィルタをかけて表示。
「Arduino+Processing マトリクスLED+Webカメラ」--Webカメラ映像をマトリクスLEDに映す。
「Processing Webカメラを光センサとして使う」--点光源で画面内に線を描く。
「Processing Webカメラ/カラートラッキング」--Webカメラを使い、色を手がかりに物体を追いかける。
「Processing Webカメラ/モーショントラッキング」--Webカメラを使って動体検知する。
ラベル:
processing,
Webカメラ
9/26/2008
Processing Webカメラを光センサとして使う
今回は、パソコンに接続したWebカメラを光センサとして使う応用実験を行います。点光源(LEDなど)を空間内で動かし、その軌跡をProcessingの画面上に描画してみたいと思います(身体にLEDなどの点光源をつけて、腕を動かしたり歩いたりすれば、身体の動きを連続的に描画/記録することができます)。
Processingでは、videoライブラリを用いてWebカメラを通してキャプチャし、キャプチャした画面のピクセルをひとつずつ読み込んで、設定した明るさ以上のピクセルを選択します。選択したピクセルのみを別の色で表示するプログラムになります。
以下のプログラムでは、カメラからキャプチャした画像の各ピクセルの明るさ(0~255)を調べ、そのピクセルの明るさが254以上であれば、画面上に赤で表示する内容になります。クリックすれば、黒で塗りつぶして画面をリセットすることにします。
videoライブラリの基本的な使い方は「Processing Video(Webカメラ)」を参照して下さい。
*Windowsの場合、そのままの設定ではこのVideoライブラリを使用することができません。WinVDIG 1.0.1をインストールする必要があります。
LEDなどの点光源をカメラに対して動かせば、以下のような画像ができあがります。赤いピクセル部分が、動かした点光源の軌跡です。
webカメラからの映像と合成(オーバーレイ)するには、以下のようになります。ここでは、webカメラからの映像を左右鏡像反転しています(カメラによっては、セッティング画面で鏡像にできるものもあります)。カメラからの映像を鏡像にすることで、点光源を右に動かせば画面内の点光源も右に動くようになります。マウスボタンを押せば画面を黒にリセット、「s」キーを押すと画面内の映像をjpeg画像で保存、「t」キーを押すとカメラセッティング画面になります。
「s」キーを押すことで画面をjpegフォーマットで保存できるようにsave()を用います。画像は、save()の括弧内の指定したファイル名でスケッチフォルダ内に保存されます。インデックス用の変数numを用意し、image_0.jpg、image_1.jpg、image_2.jpg...というように、保存名にはインデックス番号がつくようにします。
「t」キーを押せばsettings()によって、カメラのセッティング画面が現れます。カメラの露出やコントラストなどの設定が「オート/自動」になっている場合があるので、できれば「マニュアル/手動」に切り替えて、それぞれを固定値にしたほうが、選択するピクセルの明るさが変化せずに済むのでいいでしょう。
上画像:合成/重ね合わせられた映像
映像内の手にはボタン電池に接続されたLEDが点灯しています。
この画像は、プログラム中にある「s」キーを押して画像保存したものです。
ドライバなしですぐにコンピュータに接続可能(UVC対応)なWebカメラとして以下のようなものがあります。
Macintosh/Windows兼用です。
関連:
「Processing Video (Webカメラ)」--Webカメラの使い方/映像にフィルタをかけて表示。
「Arduino+Processing マトリクスLED+Webカメラ」--Webカメラ映像をマトリクスLEDに映す。
「Processing Webカメラ/定点記録画像」--Webカメラ映像を0.5秒おきに画像保存(JPEG)する。
「Processing Webカメラ/カラートラッキング」--Webカメラを使い、色を手がかりに物体を追いかける。
「Processing Webカメラ/モーショントラッキング」--Webカメラを使って動体検知する。
Processingでは、videoライブラリを用いてWebカメラを通してキャプチャし、キャプチャした画面のピクセルをひとつずつ読み込んで、設定した明るさ以上のピクセルを選択します。選択したピクセルのみを別の色で表示するプログラムになります。
以下のプログラムでは、カメラからキャプチャした画像の各ピクセルの明るさ(0~255)を調べ、そのピクセルの明るさが254以上であれば、画面上に赤で表示する内容になります。クリックすれば、黒で塗りつぶして画面をリセットすることにします。
videoライブラリの基本的な使い方は「Processing Video(Webカメラ)」を参照して下さい。
*Windowsの場合、そのままの設定ではこのVideoライブラリを使用することができません。WinVDIG 1.0.1をインストールする必要があります。
//ライブラリを取り込む import processing.video.*; //オブジェクトの用意 Capture video; //画面サイズの変数と値 int w=320; int h=240; void setup() { size(w, h); video = new Capture(this, w, h, 30); //背景を黒にしておく background(0);
video.start();//Processing2.0以上の場合はこの行が必要 } void draw() { //画面のピクセルをロードしておく loadPixels(); //カメラ画像のピクセルをひとつずつ調べる for(int i=0;i<w*h;i++){ //ピクセルが254以上の明るさの場合 if(brightness(video.pixels[i])>=254){ //選択されたピクセルを赤にする pixels[i]=color(255,0,0); } } //ピクセル表示更新 updatePixels(); } //キャプチャ画面の読み込み void captureEvent(Capture video) { video.read(); } //マウスボタンを押したら void mousePressed(){ //背景を黒にする background(0); }
LEDなどの点光源をカメラに対して動かせば、以下のような画像ができあがります。赤いピクセル部分が、動かした点光源の軌跡です。
webカメラからの映像と合成(オーバーレイ)するには、以下のようになります。ここでは、webカメラからの映像を左右鏡像反転しています(カメラによっては、セッティング画面で鏡像にできるものもあります)。カメラからの映像を鏡像にすることで、点光源を右に動かせば画面内の点光源も右に動くようになります。マウスボタンを押せば画面を黒にリセット、「s」キーを押すと画面内の映像をjpeg画像で保存、「t」キーを押すとカメラセッティング画面になります。
import processing.video.*; Capture video; int w=320; int h=240; //軌跡用の配列を用意しておく int[] pix=new int[w*h]; void setup() { size(w, h); video = new Capture(this, w, h, 30); //軌跡用配列の値をすべてゼロにしておく for(int i=0;i<w*h;i++){ pix[i]=0; }
video.start();//Processing2.0以上の場合はこの行が必要 } void draw() { loadPixels(); for(int i=0;i<w*h;i++){ if(brightness(video.pixels[i])>=254){ //ピクセルを鏡像反転するための計算 //配列に値を記憶しておく int a=i/w; pix[w-i%w+a*w-1]=255;//選択されたピクセルだけを255にする } //配列からの値を画面ピクセルへ代入 //選択されたピクセルを緑で画面表示 pixels[i]=color(0,pix[i],0); } updatePixels(); //合成するカメラ映像の処理 tint(255,128);//透明度128(50%) scale(-1.0, 1.0);//左右反転(鏡像) image(video, -w, 0);//映像出力 } //カメラ映像読み込み void captureEvent(Capture video) { video.read(); } //マウスボタンを押すとリセット(黒へ) void mousePressed(){ for(int i=0;i<w*h;i++){ pix[i]=0; } } int num=0;//保存画像インデックスの変数 void keyPressed(){ //sキーを押すと(jpeg画像で保存) if(key=='s'){ String s="image_" + num + ".jpg";//保存ファイル名 save(s);//画像保存 num++;//保存画像インデックスを+1しておく } //tキーを押すと if(key=='t'){ video.settings();//カメラセッティング画面表示 } }
「s」キーを押すことで画面をjpegフォーマットで保存できるようにsave()を用います。画像は、save()の括弧内の指定したファイル名でスケッチフォルダ内に保存されます。インデックス用の変数numを用意し、image_0.jpg、image_1.jpg、image_2.jpg...というように、保存名にはインデックス番号がつくようにします。
「t」キーを押せばsettings()によって、カメラのセッティング画面が現れます。カメラの露出やコントラストなどの設定が「オート/自動」になっている場合があるので、できれば「マニュアル/手動」に切り替えて、それぞれを固定値にしたほうが、選択するピクセルの明るさが変化せずに済むのでいいでしょう。
上画像:合成/重ね合わせられた映像
映像内の手にはボタン電池に接続されたLEDが点灯しています。
この画像は、プログラム中にある「s」キーを押して画像保存したものです。
ドライバなしですぐにコンピュータに接続可能(UVC対応)なWebカメラとして以下のようなものがあります。
Macintosh/Windows兼用です。
関連:
「Processing Video (Webカメラ)」--Webカメラの使い方/映像にフィルタをかけて表示。
「Arduino+Processing マトリクスLED+Webカメラ」--Webカメラ映像をマトリクスLEDに映す。
「Processing Webカメラ/定点記録画像」--Webカメラ映像を0.5秒おきに画像保存(JPEG)する。
「Processing Webカメラ/カラートラッキング」--Webカメラを使い、色を手がかりに物体を追いかける。
「Processing Webカメラ/モーショントラッキング」--Webカメラを使って動体検知する。
ラベル:
processing,
Webカメラ,
光センサ
8/11/2008
Arduino+Processing マトリクスLED+Webカメラ
今回は、Webカメラから取り込んだ映像をArduinoに接続した8×8マトリクスLEDに映す実験を行います。まず、ProcessingでWebカメラからの映像を8×8ピクセルで取り込み、合計64個のピクセルの明るさの値(0〜255)を調べてから、その個々の値をシリアル通信でArduinoに送ります。Arduino側では、受け取った64個分の値をマトリクスLEDの個々の明るさに反映させます。Arduino基盤とマトリクスLEDとは、ICを使わず直結することにします(接続方法は「Arduino マトリクスLED1」を参照)。
Processingの画面では、マトリクスLEDの表示シミュレーション(モニタリング)を同時に行うことにします(前回行ったモザイク処理のような方法で赤い円を64個映し出すことにします)。
「Processingの画面(モニタリング)」
Processingのプログラム:
Processingの方では、VideoライブラリとSerialライブラリの二つを取り込む必要があります。マトリクスLEDが8×8の解像度なので、Webカメラから取り込む映像の解像度も8×8にしておきます(カメラ映像の横縦比は4:3なので、少し縦長の映像になってしまいます)。
*Windowsの場合、そのままの設定ではこのVideoライブラリを使用することができません。WinVDIG 1.0.1をインストールする必要があります。
「pixelValue[i]=int(brightness(video.pixels[i]))」では、まず映像の各ピクセルの色をpixels[]で読み込みます。pixels[]は、RGBの三色の値(三つの値)を含んでおり、brightness()で括ると明るさの値(一つの値)に変換されます(0〜255)。変換された値はfloat(小数)なのでint()で括って整数に変換しておきます。この値を、fill()の赤の値に代入し(緑と青は0)、LEDのような赤い円をellipse()を使って64個描画します。8×8を160×160の画面で表示しているので、20×20ピクセルのグリッド状に配置されます。ellipse()の直径はとりあえず15にしておきました。ellipse()のXとY座標は、「%」と「/」を使って計算します(X座標となる「(i%8)*20+10」は、iを8(横幅)で割った余りに20ピクセル掛けて、さらに10ピクセル足すことでellipse()が20×20のグリッドの中心に来るように位置調整しています)。最後に「port.write(pixelValue[i])」で、Arduinoへ各ピクセルの明るさの値を送信します。今回は画面をクリックしたらシリアル通信が開始されるようにしています。
次にArduinoの方に移ります。冒頭で書いたように、今回はマトリクスLEDを、ICを使わず直結します。個々のLEDはダイナミック点灯しているので、点灯時間の長さによって明るさを調整することになります。点灯時間が短ければ暗くなり、長くなれば明るくなります。つまり、Processingから送られて来た明るさの値(0〜255)を、個々のLEDの点灯時間に反映させるプログラムになるということです。マトリクスLEDとの接続方法や詳細については「Arduino マトリクスLED1」を参照してください。
Arduinoのプログラム:
以前の「Arduino マトリクスLED1」とほぼプログラム内容は同じです。異なる部分は、シリアル通信と各LEDを点灯/消灯させる継続時間の部分です。用意する二次元配列は、boolean型ではなくbyte型(0~255の値なので)にしています。
シリアル通信上で干渉しないようにするため、Arduino基盤の0番ピンと1番ピンには何も接続しないことにしています(2〜17番ピンを使用)。シリアル通信では、Processingから送られてくる64個のデータをSerial.available()でカウントして、それぞれの値を予め用意しておいた二次元配列matrixに保存しておきます。送られてくるデータは0〜255(明るさの値)となります。そしてダイナミック点灯していく際に、明るさの値をdelayMicroseconds()に代入して、点灯継続時間と消灯継続時間に割り当てます。delayMicroseconds(0)としてしまうと、0マイクロ秒としては扱ってくれないので、delayMicroseconds()の括弧内に入れられる最小値は1にしてあります。最小1マイクロ秒の点灯時間かつ最大256マイクロ秒の消灯時間のときが最も暗くなるときです。その逆で、最大256マイクロ秒の点灯時間かつ最小1マイクロ秒の消灯時間のときが最も明るくなります。個々のLEDは257マイクロ秒ごとにダイナミック点灯していることになります。個々のLEDの点滅を300マイクロ秒程度にすると点滅しているようには見えないので、今回の257マイクロ秒周期で点滅させれば、ほぼ問題ないでしょう。
関連:
・「シリアル通信1〜5」
・「Arduino マトリクスLED1」
・「Processing Video(Webカメラ)」
Processingの画面では、マトリクスLEDの表示シミュレーション(モニタリング)を同時に行うことにします(前回行ったモザイク処理のような方法で赤い円を64個映し出すことにします)。
「Processingの画面(モニタリング)」
Processingのプログラム:
//ビデオライブラリを取り込む
import processing.video.*;
//キャプチャ用オブジェクトを用意
Capture video;
//シリアル通信ライブラリを取り込む
import processing.serial.*;
//シリアル通信オブジェクトを用意
Serial port;
//64個分のピクセル色の配列を用意
int[] pixelValue=new int[64];
//シリアル通信開始用フラグ
boolean start=false;
void setup(){
//画面を160角に設定
size(160,160);
//描画を滑らかにする
smooth();
//映像キャプチャの設定(幅8,高さ8ピクセル,フレームレート30)
video = new Capture(this, 8, 8, 30);
//ポートの設定
port=new Serial(this,"/dev/tty.usbserial-A40014iU",9600);
//外形線なし
noStroke();
}
void draw(){
//背景を黒で塗る
background(0);
//64個分のピクセルの処理
for(int i=0;i<64;i++){
//映像の各ピクセルの色の値を
//明るさの値に変換する
pixelValue[i]=int(brightness(video.pixels[i]));
//円の塗色(赤の値)に代入
fill(pixelValue[i],0,0);
//円を描画
ellipse((i%8)*20+10,(i/8)*20+10,15,15);
//値を送信
if(start){
port.write(pixelValue[i]);
}
}
}
//キャプチャ映像読み込み
void captureEvent(Capture video) {
video.read();
}
クリックでシリアル通信開始
void mousePressed(){
start=true;
}
Processingの方では、VideoライブラリとSerialライブラリの二つを取り込む必要があります。マトリクスLEDが8×8の解像度なので、Webカメラから取り込む映像の解像度も8×8にしておきます(カメラ映像の横縦比は4:3なので、少し縦長の映像になってしまいます)。
*Windowsの場合、そのままの設定ではこのVideoライブラリを使用することができません。WinVDIG 1.0.1をインストールする必要があります。
「pixelValue[i]=int(brightness(video.pixels[i]))」では、まず映像の各ピクセルの色をpixels[]で読み込みます。pixels[]は、RGBの三色の値(三つの値)を含んでおり、brightness()で括ると明るさの値(一つの値)に変換されます(0〜255)。変換された値はfloat(小数)なのでint()で括って整数に変換しておきます。この値を、fill()の赤の値に代入し(緑と青は0)、LEDのような赤い円をellipse()を使って64個描画します。8×8を160×160の画面で表示しているので、20×20ピクセルのグリッド状に配置されます。ellipse()の直径はとりあえず15にしておきました。ellipse()のXとY座標は、「%」と「/」を使って計算します(X座標となる「(i%8)*20+10」は、iを8(横幅)で割った余りに20ピクセル掛けて、さらに10ピクセル足すことでellipse()が20×20のグリッドの中心に来るように位置調整しています)。最後に「port.write(pixelValue[i])」で、Arduinoへ各ピクセルの明るさの値を送信します。今回は画面をクリックしたらシリアル通信が開始されるようにしています。
次にArduinoの方に移ります。冒頭で書いたように、今回はマトリクスLEDを、ICを使わず直結します。個々のLEDはダイナミック点灯しているので、点灯時間の長さによって明るさを調整することになります。点灯時間が短ければ暗くなり、長くなれば明るくなります。つまり、Processingから送られて来た明るさの値(0〜255)を、個々のLEDの点灯時間に反映させるプログラムになるということです。マトリクスLEDとの接続方法や詳細については「Arduino マトリクスLED1」を参照してください。
Arduinoのプログラム:
//8x8の二次元配列を用意
byte matrix[8][8];
void setup(){
//出力ピンの設定、すべてオフにする
for(int i=2;i<=17;i++){
pinMode(i,OUTPUT);
digitalWrite(i,LOW);
}
//シリアル通信開始
Serial.begin(9600);
}
void loop(){
//シリアル通信(64個分のデータ)
if(Serial.available()>63){
for(int k=0;k<8;k++){
for(int l=0;l<8;l++){
//読み込んだ値を配列に代入
matrix[k][l]=Serial.read();
}
}
}
//各LEDの点灯制御
for(int i=2;i<=9;i++){
//列の点灯
digitalWrite(i,HIGH);
for(int j=10;j<=17;j++){
//行の点灯
digitalWrite(j,LOW);
//行の点灯継続時間
delayMicroseconds(1+matrix[i-2][j-10]);
//行の消灯
digitalWrite(j,HIGH);
//行の消灯継続時間
delayMicroseconds(256-matrix[i-2][j-10]);
}
//列の消灯
digitalWrite(i,LOW);
}
}
以前の「Arduino マトリクスLED1」とほぼプログラム内容は同じです。異なる部分は、シリアル通信と各LEDを点灯/消灯させる継続時間の部分です。用意する二次元配列は、boolean型ではなくbyte型(0~255の値なので)にしています。
シリアル通信上で干渉しないようにするため、Arduino基盤の0番ピンと1番ピンには何も接続しないことにしています(2〜17番ピンを使用)。シリアル通信では、Processingから送られてくる64個のデータをSerial.available()でカウントして、それぞれの値を予め用意しておいた二次元配列matrixに保存しておきます。送られてくるデータは0〜255(明るさの値)となります。そしてダイナミック点灯していく際に、明るさの値をdelayMicroseconds()に代入して、点灯継続時間と消灯継続時間に割り当てます。delayMicroseconds(0)としてしまうと、0マイクロ秒としては扱ってくれないので、delayMicroseconds()の括弧内に入れられる最小値は1にしてあります。最小1マイクロ秒の点灯時間かつ最大256マイクロ秒の消灯時間のときが最も暗くなるときです。その逆で、最大256マイクロ秒の点灯時間かつ最小1マイクロ秒の消灯時間のときが最も明るくなります。個々のLEDは257マイクロ秒ごとにダイナミック点灯していることになります。個々のLEDの点滅を300マイクロ秒程度にすると点滅しているようには見えないので、今回の257マイクロ秒周期で点滅させれば、ほぼ問題ないでしょう。
関連:
・「シリアル通信1〜5」
・「Arduino マトリクスLED1」
・「Processing Video(Webカメラ)」
8/09/2008
Processing Video (Webカメラ)
ProcessingのVideoライブラリを使用することで、パソコンに接続した(あるいは内蔵された)Webカメラからの映像を取り込むことができます。このライブラリを使用するには、パソコンにQuickTimeがインストールされている必要があるので、もしインストールされていない場合は、アップルのQuickTimeのサイトからダウンロード/インストールして下さい。
USB接続する外付けのWebカメラの場合は必要なドライバをメーカーのサイトなどからダウンロード/インストールして使用可能な状態にしておいて下さい。Webカメラがパソコンに内蔵されている場合は、そのまま使うことができるはずです。まずは、簡単な映像の取り込みかたから始めます。
*Windowsの場合、そのままの設定ではこのVideoライブラリを使用することができないことがあります。その場合、WinVDIG 1.0.1をインストールする必要があります。
上記プログラムでは、画面サイズが200×200の正方形であるため、Webカメラでキャプチャされた映像は縦長になってしまうかもしれません。通常画面の比率は4:3(横:縦)であるため、もし比率を合わせるのであれば、320×240(4:3)などに合わせてください。
Capture()によって、親オブジェクト(thisのままでよい)と映像の幅と高さ、フレームレートを設定できます。映像が滑らかに動かない場合は、フレームレートを下げるか、画像サイズを縮小して調整して下さい。
キャプチャされた映像は、毎フレームごとにimage()によって画面内に配置されます。image()の括弧内の数値は、配置するX座標、Y座標となります。上記プログラムでは0,0に設定されているので、左上角の座標を基準に映像が画面内に配置されます。
captureEvent()は、Webカメラから信号が送られてくる度に作動します。read()によって、毎回送られてくる映像信号を読み込んでいます。
今回は最後にクリックするとsettings()によって、カメラのセッティング画面(Webカメラ用の設定アプリケーション画面)が現れるようにしてあります。ここで、カメラの解像度やコントラストなどの設定を行うことができるはずです。
次に映像にフィルタをかけてみるプログラムをしてみます。
画像用のfilter()というコマンドがあり、
THRESHOLD 白黒ニ値化:0.0~1.0(黒〜白)/初期設定0.5
GRAY グレースケール:パラメータなし
INVERT 反転色:パラメータなし
POSTERIZE ポスタライズ:2~255(各チャンネルの色数の限定)
BLUR ぼかし:指定半径範囲でぼかす
それぞれをfilter()の括弧内に入れれば、映像にフィルタをかけることができます。フィルタの種類の後にパラメータを入れることで、フィルタのかかり具合を調整することができます。
複数のフィルタを重ねて使うこともできます。ただ、フィルタの種類(特にBLUR)によっては処理速度に影響がでる場合があるので、適宜フレームレートや画素数などを調整する必要がでてくるときがあります。
以下は、キャプチャした映像にぼかしをいれノイズを取払い、その後白黒でニ値化し、白黒の単純な映像に変換するサンプルです。尚、映像の比率は4:3にすることにします。
「フィルタ(ぼかし+白黒ニ値化)をかけた映像(上画像)」
次に、映像のモザイク化のプログラムをしてみます。画面サイズを320×240とし、横を32分割、縦を24分割し、10×10のモザイク処理をすることにします。まずloadPixels()によって映像の全ピクセルを読み込み、pixels[]によって選択したピクセルの色を取得します。取得した色をもとにrect()でモザイクの矩形を描くことにします。モザイク化されるには、必要なキャプチャ映像は結果的に32×24の解像度があれば済むので、予め32×24のサイズでキャプチャすることにします。
「モザイク映像(上画像)」
最終的に32×24のモザイクになるので、キャプチャする画像も同様の解像度にしておけば、処理速度が遅くならなくて済みます。pixels[]によってキャプチャされた映像の各ピクセルの色を取得します。32×24なので合計768ピクセル分となります。rect()による矩形も768個必要になるので、まずfill()で塗色を指定してから描きます。pixel[i]のiは画面左上から数えていき最後は右下のピクセルの番号になります。pixel[i]のiは0~767(合計768個)までの連続した数値なので、「%」と「/」を使ってXとYの座標値に変換します。変換したXとYの座標値をrect()に代入することで、320×240の画面に10ピクセル単位で横方向と縦方向に32×24のモザイク矩形として配置されます。今回はnoStroke()を使っていないので、黒い枠のついたモザイク矩形にしています。
ドライバなしですぐにコンピュータに接続可能(UVC対応)なWebカメラとして以下のようなものがあります。
Macintosh/Windows兼用です。
関連:
「Arduino+Processing マトリクスLED+Webカメラ」--Webカメラ映像をマトリクスLEDに映す。
「Processing Webカメラを光センサとして使う」--点光源で画面内に線を描く。
「Processing Webカメラ/定点記録画像」--Webカメラ映像を0.5秒おきに画像保存(JPEG)する。
「Processing Webカメラ/カラートラッキング」--Webカメラを使い、色を手がかりに物体を追いかける。
「Processing Webカメラ/モーショントラッキング」--Webカメラを使って動体検知する。
USB接続する外付けのWebカメラの場合は必要なドライバをメーカーのサイトなどからダウンロード/インストールして使用可能な状態にしておいて下さい。Webカメラがパソコンに内蔵されている場合は、そのまま使うことができるはずです。まずは、簡単な映像の取り込みかたから始めます。
*Windowsの場合、そのままの設定ではこのVideoライブラリを使用することができないことがあります。その場合、WinVDIG 1.0.1をインストールする必要があります。
//ライブラリの取り込み
import processing.video.*;
//キャプチャする映像のオブジェクトを用意
Capture myCapture;
void setup() {
size(200, 200);
//キャプチャする映像の設定
myCapture = new Capture(this, width, height, 30);
}
void draw() {
//映像を画面に配置
image(myCapture, 0, 0);
}
//映像の読み込み
void captureEvent(Capture myCapture) {
myCapture.read();
}
//クリックでカメラセッティング画面になる
void mousePressed(){
myCapture.settings();
}
上記プログラムでは、画面サイズが200×200の正方形であるため、Webカメラでキャプチャされた映像は縦長になってしまうかもしれません。通常画面の比率は4:3(横:縦)であるため、もし比率を合わせるのであれば、320×240(4:3)などに合わせてください。
Capture()によって、親オブジェクト(thisのままでよい)と映像の幅と高さ、フレームレートを設定できます。映像が滑らかに動かない場合は、フレームレートを下げるか、画像サイズを縮小して調整して下さい。
キャプチャされた映像は、毎フレームごとにimage()によって画面内に配置されます。image()の括弧内の数値は、配置するX座標、Y座標となります。上記プログラムでは0,0に設定されているので、左上角の座標を基準に映像が画面内に配置されます。
captureEvent()は、Webカメラから信号が送られてくる度に作動します。read()によって、毎回送られてくる映像信号を読み込んでいます。
今回は最後にクリックするとsettings()によって、カメラのセッティング画面(Webカメラ用の設定アプリケーション画面)が現れるようにしてあります。ここで、カメラの解像度やコントラストなどの設定を行うことができるはずです。
次に映像にフィルタをかけてみるプログラムをしてみます。
画像用のfilter()というコマンドがあり、
THRESHOLD 白黒ニ値化:0.0~1.0(黒〜白)/初期設定0.5
GRAY グレースケール:パラメータなし
INVERT 反転色:パラメータなし
POSTERIZE ポスタライズ:2~255(各チャンネルの色数の限定)
BLUR ぼかし:指定半径範囲でぼかす
それぞれをfilter()の括弧内に入れれば、映像にフィルタをかけることができます。フィルタの種類の後にパラメータを入れることで、フィルタのかかり具合を調整することができます。
複数のフィルタを重ねて使うこともできます。ただ、フィルタの種類(特にBLUR)によっては処理速度に影響がでる場合があるので、適宜フレームレートや画素数などを調整する必要がでてくるときがあります。
以下は、キャプチャした映像にぼかしをいれノイズを取払い、その後白黒でニ値化し、白黒の単純な映像に変換するサンプルです。尚、映像の比率は4:3にすることにします。
「フィルタ(ぼかし+白黒ニ値化)をかけた映像(上画像)」
//ライブラリの取り込み
import processing.video.*;
//キャプチャする映像のオブジェクトを用意
Capture myCapture;
void setup() {
size(320, 240);//比率4:3
//キャプチャする映像の設定
myCapture = new Capture(this, width, height, 30);
}
void draw() {
//映像を画面に配置
image(myCapture, 0, 0);
filter(BLUR,1.8);//ぼかし
filter(THRESHOLD,0.7);//白黒ニ値化
}
//映像の読み込み
void captureEvent(Capture myCapture) {
myCapture.read();
}
次に、映像のモザイク化のプログラムをしてみます。画面サイズを320×240とし、横を32分割、縦を24分割し、10×10のモザイク処理をすることにします。まずloadPixels()によって映像の全ピクセルを読み込み、pixels[]によって選択したピクセルの色を取得します。取得した色をもとにrect()でモザイクの矩形を描くことにします。モザイク化されるには、必要なキャプチャ映像は結果的に32×24の解像度があれば済むので、予め32×24のサイズでキャプチャすることにします。
「モザイク映像(上画像)」
//ライブラリの取り込み
import processing.video.*;
//キャプチャする映像のオブジェクトを用意
Capture myCapture;
void setup() {
size(320, 240);//比率4:3
//キャプチャする映像を32×24に設定
myCapture = new Capture(this, 32, 24, 30);
//noStroke(); //モザイクの黒枠をなしにする場合
}
void draw() {
//キャプチャ画像の各ピクセルの色を
//塗色に割当て、矩形を描く
for(int i=0;i<32*24;i++){
fill(myCapture.pixels[i]);
rect((i%32)*10,(i/32)*10,10,10);
}
}
//映像の読み込み
void captureEvent(Capture myCapture) {
myCapture.read();
}
最終的に32×24のモザイクになるので、キャプチャする画像も同様の解像度にしておけば、処理速度が遅くならなくて済みます。pixels[]によってキャプチャされた映像の各ピクセルの色を取得します。32×24なので合計768ピクセル分となります。rect()による矩形も768個必要になるので、まずfill()で塗色を指定してから描きます。pixel[i]のiは画面左上から数えていき最後は右下のピクセルの番号になります。pixel[i]のiは0~767(合計768個)までの連続した数値なので、「%」と「/」を使ってXとYの座標値に変換します。変換したXとYの座標値をrect()に代入することで、320×240の画面に10ピクセル単位で横方向と縦方向に32×24のモザイク矩形として配置されます。今回はnoStroke()を使っていないので、黒い枠のついたモザイク矩形にしています。
ドライバなしですぐにコンピュータに接続可能(UVC対応)なWebカメラとして以下のようなものがあります。
Macintosh/Windows兼用です。
関連:
「Arduino+Processing マトリクスLED+Webカメラ」--Webカメラ映像をマトリクスLEDに映す。
「Processing Webカメラを光センサとして使う」--点光源で画面内に線を描く。
「Processing Webカメラ/定点記録画像」--Webカメラ映像を0.5秒おきに画像保存(JPEG)する。
「Processing Webカメラ/カラートラッキング」--Webカメラを使い、色を手がかりに物体を追いかける。
「Processing Webカメラ/モーショントラッキング」--Webカメラを使って動体検知する。
ラベル:
processing,
Webカメラ,
ビデオ
登録:
投稿 (Atom)