INDEX(各項目ごとの目次)

[HOME]  [Processing関係]  [Arduino関係]  [マテリアル関係]  [秋葉原工作マップ]

2008年用ですが、部分的に内容を更新しています(2010/06/14)。
また、[建築農業工作ゼミ2009-2010]とも連動していますので、そちらにも幾つかサンプルがあります。
:

ラベル ビデオ の投稿を表示しています。 すべての投稿を表示
ラベル ビデオ の投稿を表示しています。 すべての投稿を表示

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のプログラム:

//ビデオライブラリを取り込む
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をインストールする必要があります。


//ライブラリの取り込み
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関係]  [HOMEへ戻る]  [目次:Arduino関係]