Processing

 Processingとは,マサチューセッツ工科大学(MIT)のCasey ReasとBen Fryによって開発されたJavaベースのプログラミング言語です.図の表示が簡単に行える他,シリアル通信,USBカメラ,サウンドなど各種入出力デバイスを容易に使用するための関数,ライブラリが多く用意されている言語です.関数やライブラリの詳細は,下記サイトを参考にしてください.英語サイトでは,Processing本体がダウンロードできる他(ダウンロードするだけでプログラム作成/実行ができます),様々なデモやプログラム例が掲載されています.


Processingの書き方

 Processingは,Fig.1のエディタを利用して作成します.プログラムのソースは,エディット領域に打ち込みます.エディタにプログラムを入力後,Runボタンを押すことでプログラムを実行します.プログラムに文法的な間違いがなければ実行されます.プログラムに文法的なエラーがあれば,エラーとその内容が,エディタ領域の下,コンソールの上の部分に表示されます.Processingでは実行後,ダイアログが作成されます.現在の計算結果などを数字として確認したい場合は,print関数,println関数を使用します(「コンソール」の項を参考にしてください).print関数,println関数を使用した場合,文字がコンソールの部分に表示されます.

Fig.1 エディタ


Processingの文法

 Processingの文法は,C言語の文法に似ています.以下に,主な規則を列挙します.


2次元グラフィクス

 以下に,2次元平面上にグラフィクスを表示するプログラムの例を示します.実行結果は,Appletとして作成しています(ブラウザによっては,Javaを実行するためにユーザーの許可が必要である場合があります).

ディスプレイウィンドウの表示

 大きさ200ピクセル x 200ピクセルで灰色のディスプレイウィンドウのみが表示されます.

size(200, 200);

点の描画

 大きさ200ピクセル x 200ピクセルで灰色のディスプレイウィンドウの(100, 100)の位置と(150, 100)の位置に点が表示されます.点(0, 0)がディスプレイウィンドウの左上隅です.また,座標を(x, y)と表すと,xがウィンドウの横軸,yが縦軸を表しています.

size(200, 200); // 点を描く point(100, 100); point(150, 100);

線の描画

 大きさ200ピクセル x 200ピクセルで灰色のディスプレイウィンドウの(20, 10)の位置と(150, 100)の位置を結ぶ線が表示されます.

size(200, 200); // 直線を描く line(20, 10, 150, 100);

円の描画

 大きさ200ピクセル x 200ピクセルで灰色のディスプレイウィンドウに円を描画します.円の描画にはellipse関数を使います.ellipse(中心のx座標,中心のy座標,円の縦の長さ,円の横の長さ)で指定します.下の例では,円の縦の長さと横の長さがともに50なので,中心を(100, 100)とする,直径50の円が描画されます.ellipse関数は楕円を描画する関数です.

size(200, 200); // 円を描く ellipse(100, 100, 50, 50);

図形の重ね合わせ

 複数の図形を描画した場合,後から書いた図形で上書きされます.

size(200, 200); // 円を描く ellipse(100, 100, 50, 50); ellipse(125, 125, 50, 50);

様々な図形を描く

 quad関数を使用して四角形を描きます.標準では,quad(x1, y1, x2, y2, x3, y3, x4, y4)と4つの点を指定します.四角形の4つの点を結ぶように描画します.下の例では,四角形の左上,右上,右下,左下の順番に指定しています.triangle関数を使用して三角形を描画します.標準では,triangle(x1, y1, x2, y2, x3, y3)と3つの点を指定します.rectMode関数などを使用して描画モードを変更することもできます.

size(200, 200); // 円を描く ellipse(100, 100, 50, 50); // 四角を描く quad(10, 30, 20, 30, 20, 50, 10, 50); // 三角を描く triangle(150, 150, 180, 180, 130, 180);

背景の色を変更する

 背景の色を変更するには,background関数を使用します.標準では,background(R, G, B)で指定します.Rは赤(red),Gは緑(green),Bは青(blue)で,0から255の値で指定します(色のモードを変更することも可能です).下の例では,背景は赤になります.RGBの値がすべて同じであると白,黒,灰色(グレースケール)が表示されます.background(0, 0, 0)は黒を,background(255, 255, 255)は白を表します.

size(200, 200); // 背景の色を変更する background(255, 0, 0); // 円を描く ellipse(125, 125, 50, 50);

図形の色を変更する

 図形の色を変更するには,fill関数を使用します.標準では,fill(R, G, B)で指定します.Rは赤(red),Gは緑(green),Bは青(blue)で,0から255の値で指定します.

size(200, 200); // 背景の色を変更する background(255, 255, 255); // 円を描く fill(0, 255, 0); ellipse(125, 125, 50, 50);

図形の枠の色/太さを変更する

 図形の枠の色を変更するには,stroke関数を使用します.標準では,stroke(R, G, B)で指定します.Rは赤(red),Gは緑(green),Bは青(blue)で,0から255の値で指定します.線の太さは,strokeWeight関数を使用して変更します.整数を引数とし,引数の値が線の太さになります.下の例では,緑色の円の枠が青色で太さ5で描画されます.標準では,線の太さは1です.

size(200, 200); // 背景の色を変更する background(255, 255, 255); // 円を描く fill(0, 255, 0); stroke(0, 0, 255); strokeWeight(5); ellipse(125, 125, 50, 50);

図形/図形の枠を塗りつぶさない

 noFill関数を使用すると,図形の枠だけ表示されます.noStroke関数を使用すると,図形を枠だけを表示します.noFill関数を使用した後,図形を描画する際には,fill関数を使用して,色を設定する必要があります.

size(200, 200); // 背景の色を変更する background(255, 255, 255); // 円を描く(枠のみ) noFill(); stroke(0, 0, 255); ellipse(125, 125, 50, 50); // 円を描く(枠なし) fill(0, 255, 0); noStroke(); ellipse(50, 50, 50, 50);

図形を滑らかに表示する

 図形を滑らかに表示するためには,smooth関数を使用します.描画に時間がかかる場合があります.下の例では,枠なしの円が滑らかに描画されています.

size(200, 200); // 背景の色を変更する background(255, 255, 255); // 円を描く(枠のみ) noFill(); stroke(0, 0, 255); ellipse(125, 125, 50, 50); // 円を描く(枠なし) smooth(); fill(0, 255, 0); noStroke(); ellipse(50, 50, 50, 50);

数学関数など

 計算を容易に行うために,いくつかの数学関数が用意されています.代表的なものを示します.引数,戻り値の型に関しては,外部サイトを参照してください.

その他高度な描画関数

 上記の関数以外にも,図形を回転させるrotate関数,座標を移動させるtranslate関数,座標を記憶したりもとに戻りたりするpushMatrix関数,popMatrix関数など高度な描画を行うための関数が用意されています.


プログラムの構造と繰り返し描画

 Processingでは,繰り返し描画やデバイスによる入出力を簡単に実現するために,特殊な関数が用意されています.それがsetup関数とdraw関数です.Fig.2に構造化されたプログラムを示します.setup関数は実行時の最初に一度だけ実行されます.それに対し,draw関数はsetup関数が実行された後,無限に実行され続けます.draw関数の中の別の関数を呼び出すことも可能です.Processingには,自分が好きなタイミングで呼び出す関数のほか,デバイスの入力時にのみ実行される関数(keyPressed関数など)などを利用することができます.

Fig.2 プログラムの構造

setup関数とdraw関数

 setup関数とdraw関数を利用して描画してみます.ただし,下の例では,赤い円が表示されるだけで,何が変わったか見ただけではわかりません.

void setup() { size(200, 200); } void draw() { background(255, 255, 255); fill(255, 0, 0); ellipse(50, 100, 50, 50); }

グローバル変数

 setup関数,draw関数とグローバル変数を利用して描画してみます.ただし,下の例では,赤い円がヨコ移動します.円の中心のx座標は,int circle_x = 50;の文で定義されています.このように,関数の外で定義する変数をグローバル変数といいます.グローバル変数は,すべての関数の中で値を変更することができます(便利ですが,複雑なプログラムになるとどこで値が変わったかわかりにくくなる場合もあります).これに対し,関数の中で定義する変数をローカル変数といいます.ローカル変数は他の関数の中で値が変更することはありません.draw関数は繰り返し実行されますので,circle_x = circle_x + 3;の1文だけで,円がヨコに移動します.

int circle_x = 50; void setup() { size(200, 200); } void draw() { circle_x = circle_x + 3; background(255, 255, 255); fill(255, 0, 0); ellipse(circle_x, 100, 50, 50); }

描画と塗りつぶし

 setup関数は1度しか実行されませんので,前節の background関数の位置が変わると,描画結果が変わります.

int circle_x = 50; void setup() { size(200, 200); background(255, 255, 255); } void draw() { circle_x = circle_x + 3; fill(255, 0, 0); ellipse(circle_x, 100, 50, 50); }

random関数/キャスト

 Processingには,擬似的な乱数を発生させる関数としてrandom関数が用意されています.random(0, 200);は0~200までの値の範囲で乱数を作成するという意味です(今回の200は作成するダイヤログのサイズに合わせています).下の例では,赤色の円がいろいろな場所に,繰り返し表示されます.ただし,random関数は小数型の値を返しますので,(int)random(0, 200);としてint型に変更しています.このように型を変更することをキャストと言います.

int circle_x = 50; int circle_y = 50; void setup() { size(200, 200); background(255, 255, 255); } void draw() { circle_x = (int)random(0, 200); circle_y = (int)random(0, 200); fill(255, 0, 0); ellipse(circle_x, circle_y, 50, 50); }

frameRate関数

 Processingには,描画のスピードを変更する関数としてframeRate関数が用意されています.フレームレートとは,1秒間に何枚処理できるかを表す言葉で,frameRate(2);では,1秒間に2枚の画像を描画します.前節のプログラムでは,パソコンのスペックに合わせて(スペックの中で可能な限り多く)描画しています.frameRate関数の数字を大きくすれば,高速で画像を切り替えることが可能ですが,パソコンのスペックを超えて描画することはできません(普通のカメラで撮影した動画は1秒間に30フレーム描画しています).

int circle_x = 50; int circle_y = 50; void setup() { size(200, 200); background(255, 255, 255); frameRate(2); // 2の場合1秒間に2枚描画 } void draw() { circle_x = (int)random(0, 200); circle_y = (int)random(0, 200); fill(255, 0, 0); ellipse(circle_x, circle_y, 50, 50); }


関数を作る

 ここでは,関数を作成してみましょう.関数をうまく利用することで,プログラムの可読性を高めることができます.C言語と異なり,プロトタイプ宣言はいりません.

引数のない関数

 引数のない関数は

関数の型 関数名() { }

で作成します.関数の型は,関数を返り値(return文で返す値)の型を表します.返り値がない場合は,void型とします.ここでは,画面を白くフェードアウトする関数fadeToWhiteをfill関数を利用して作成しましょう.fill関数は,色を指定するだけでなく,色の透明度も変更することができます.これを利用します.fill関数は,fill(R, G, B, x);と書いた場合,xが透明度を表します.下の例では,fadeToWhite白の透明の四角(画面と同じ大きさのサイズ)を書いています.赤の円の書いた上から,白の透明を重ねると,赤の円の色が薄くなります.これを何度か繰り返していると,最終的には赤い円が白になるという仕組みです.rectMode()関数は,rect関数の引数の意味を変える関数です.rectMode(CORNER);で,四角を書く際に,左上隅と右下隅の2点を引数とするモードに変わります.したがって,rect(0, 0, width, height);で,画面いっぱいの白の四角を書くことができます.引数widthと,heightは,画面の幅と高さを表す特殊な定数で,作成したダイヤログの幅によって決定されます.この例では,widthは200,heightは200です.

int circle_x = 50; int circle_y = 50; void setup() { size(200, 200); background(255, 255, 255); frameRate(10); } void draw() { fadeToWhite(); circle_x = (int)random(0, 200); circle_y = (int)random(0, 200); fill(255, 0, 0); ellipse(circle_x, circle_y, 50, 50); } void fadeToWhite() { noStroke(); fill(255, 255, 255, 30); rectMode(CORNER); rect(0, 0, width, height); }

引数のある関数

 関数の使う際,新しい関数内で,今まで使っていた数値を使いたい場合があります.これを実現するために.引数という概念を使います.例えば,1つの引数のある関数では

関数の型 関数名(変数1の型 変数1の名前) {  変数1がこの関数内で使える.  このとき,変数1の初期値は,  元の関数の引数として与えられた通りである. }

で作成します.変数が2個の場合は,関数の型 関数名(変数1の型 変数1の名前, 変数2の型 変数2の名前)のようにコンマで足していきます.引数はいくつでも構いません.用途に応じて数を決めます.ここでは,前節のプログラムに,円を描く関数circleをを追加してみましょう.動作自体は前節と変わりません.draw関数の中では,circle_xとなっていた変数が,circle関数ではxとなっていますが,問題ありません.関数の中で定義される変数はローカル変数ですので,draw関数とcircle関数の中での変数名は無関係です(もちろん,一緒でも構いませんが).

int circle_x = 50; int circle_y = 50; void setup() { size(200, 200); background(255, 255, 255); frameRate(10); } void draw() { fadeToWhite(); circle_x = (int)random(0, 200); circle_y = (int)random(0, 200); circle(circle_x, circle_y); } void fadeToWhite() { noStroke(); fill(255, 255, 255, 30); rectMode(CORNER); rect(0, 0, width, height); } void circle(int x, int y) { fill(255, 0, 0); ellipse(x, y, 50, 50); }


シリアル通信を行う

 ここでは,Processingを利用してシリアル通信を行ます.給電に使用しているUSBを通信線として利用して,通信を行います.

シリアル通信(受信)1

以下に,Processingを利用してシリアル通信(受信)を行うプログラムを示します.使用しているマイコンによって,"COM"ポートの番号は変わります(例では,COM3を使用するとしています).実験では,「Arduinoでシリアル通信(送信)を実行する(プログラムを書き込む)」→「Processingでシリアル通信(送信)を実行する」の順番で実行します.以下のプログラムでは,「受信した値を文字として表示」「受信した値に応じて円を移動する」ということを行っています.myPort = new Serial(this, "COM3", 9600);でCOM3を利用してシリアル通信を行うということを設定しています.9600は通信速度で9600bpsを表しています.この通信速度は送信する方と同じ値を設定します.x = myPort.read();の部分で実際に通信を行い,値を取得しています.取得した値は変数xに代入されます.myFont = createFont("Century.vlw", 48);の部分で,画面に表示する文字のフォントを準備しています.ここでは,Centuryというフォントを48ptの大きさで準備しています.

//シリアルライブラリを取り入れる import processing.serial.*; Serial myPort; PFont myFont; int x; //図形のX座標の変数を用意 void setup(){ //画面サイズ size(256,256); //シリアルポートの設定 myPort = new Serial(this, "COM3", 9600); myFont = createFont("Century.vlw", 48); textFont(myFont, 48); } void draw(){ //背景色を白に設定 background(255); //XY座標を(x,100)に設定し、 //幅50、高さ50の円を描画 fill(255,200,200); ellipse(x,100,50,50); fill(0,0,0); text(x, 100,100); println(x); } void serialEvent(Serial p){ //変数xにシリアル通信で読み込んだ値を代入 x = myPort.read(); }


シリアル通信(受信)2

 もう一つ例を示します.下の例では,取得した値に応じて2つの四角の大きさが変化するプログラムです.このプログラムは,もともとProseccingのエディタに用意されているサンプルプログラム Mouse1Dを改造したプログラムです.エディタの上にあるバーの「File」→「Examples」→「Basics」→「Input」→「Mouse1D」を選択するとサンプルプログラムが表示されます.Mouse1Dはマウスの位置に応じて2つの四角の大きさが変化するプログラムです.マウスの位置が入力になっている部分を,シリアルから取得した値に置き換えています.下のプログラムを実行後,実際のMouse1Dと比べてどこが変化しているかを確認してください.

//シリアルライブラリを取り入れる import processing.serial.*; Serial myPort; int x_serial; int gx = 15; int gy = 35; float leftColor = 0.0; float rightColor = 0.0; void setup() { size(200, 200); colorMode(RGB, 1.0); noStroke(); //シリアルポートの設定 myPort = new Serial(this, "COM3", 9600); } void draw() { background(0.0); update(x_serial); fill(0.0, leftColor + 0.4, leftColor + 0.6); rect(width/4-gx, width/2-gx, gx*2, gx*2); fill(0.0, rightColor + 0.2, rightColor + 0.4); rect(width/1.33-gy, width/2-gy, gy*2, gy*2); } void update(int x) { leftColor = -0.002 * x/2 + 0.06; rightColor = 0.002 * x/2 + 0.06; gx = x/2; gy = 100-x/2; if (gx < 10) { gx = 10; } else if (gx > 90) { gx = 90; } if (gy > 90) { gy = 90; } else if (gy < 10) { gy = 10; } } void serialEvent(Serial p){ //変数xにシリアル通信で読み込んだ値を代入 x_serial = myPort.read(); }

シリアル通信(受信)3

以下に,Processingを利用して2個の値を受信するプログラムを示します.2個の値を受信するために,myPort.read()関数を2回使用します.ただし,正しく2個の値を取得したかどうかを判断するために,myPort.available()関数を使って受信した値の個数をチェックしています.下の例では,受信した2個の値をx,yとし,描画する円の中心のx座標,y座標が変更されるようになっています.受信のCOM番号は自分が使用している環境によって適宜変更してください.Arduino側のプログラムは,Arduinoの項目「シリアル通信(送信)2」を参考にしてください.

//シリアルライブラリを取り入れる import processing.serial.*; Serial myPort; PFont myFont; int x; //図形のX座標の変数を用意 int y; //図形のY座標の変数を用意 void setup(){ //画面サイズ size(256,256); //シリアルポートの設定 myPort = new Serial(this, "COM3", 9600); myFont = createFont("Century.vlw", 48); textFont(myFont, 48); } void draw(){ //背景色を白に設定 background(255); //XY座標を(x,100)に設定し、 //幅50、高さ50の円を描画 fill(255,200,200); ellipse(x,y,50,50); fill(0,0,0); text(x, 100,100); text(y, 100,150); } void serialEvent(Serial p){ if(myPort.available()>2){ x = myPort.read(); y = myPort.read(); } }


コンソール

 以下に,コンソールに文字を表示するプログラムの例を示します.計算結果の確認等に使用します.実行するとコンソールに文字が表示される他,適当なサイズの何も書かれていないディスプレイウィンドウが表示されます.表示結果は自分で確認してください.

print関数

 print関数は,改行なしの文字の表示です.下の例では,

Hello world.

と表示されます.

print("Hello world.");

println関数

 println関数は,改行ありの文字の表示です.下の例では,

0
1
2
3
4

と表示されます.下の例のように,数字を引数としても文字列として表示されます.

int i; for(i=0; i<5; i++){ println(i); }

高度な表示

 print関数,println関数では,+の記号を使って,文字列を並べていくことができます.また,関数内で計算を行うこともできます.下の例では,

i = 0, 2*i = 0
i = 1, 2*i = 2
i = 2, 2*i = 4
i = 3, 2*i = 6
i = 4, 2*i = 8

と表示されます.

int i; for(i=0; i<5; i++){ println("i = " + i + ", " + "2*i = " + 2*i); }


画像を扱う

 以下に,画像を扱うプログラムの例を示します.例では,watar.JPGを使用しています. プログラムソースがあるフォルダにwatar.JPGを用意する必要があります.

画像の読み込み,表示

 loadImage関数を使って画像の読み込み,image関数を使って画像の表示を行います.下の例では,大きさ300ピクセル x 300ピクセルの画像(water.JPG)を読込み,300ピクセル x 300ピクセルの画像として表示しています.プログラムソースのあるフォルダの中にwater.JPGが存在するとディスプレイウィンドウ上に画像が表示されます.ファイルによって,拡張子がjpgなどになる場合があります.

size(300, 300); PImage sample = loadImage("water.JPG"); image(sample, 0, 0, 300, 300);

画像への描画

 画像にも描画することが可能です.画像描画後,線などを追加していきます.下の例では,water.JPGに赤色の丸を描画しています.

size(300, 300); PImage sample = loadImage("water.JPG"); image(sample, 0, 0, 300, 300); noFill(); stroke(255, 0, 0); strokeWeight(4); ellipse(100, 100, 100, 100);


参考文献

  1. C. Reas, B. Fry, "Processing: A Programming Handbook for Visual Designers and Artists", The MIT Press, 2007.
  2. B. Fry, "Visualizing Data", Oreilly & Associates Inc., 2007.
  3. 田中孝太郎, 前川峻志, "Built with Processing", ビー・エヌ・エヌ新社, 2010.
  4. 田原淳一郎, "Processingプログラミング入門", カットシステム, 2010.
  5. C. Reas, B. Fry, 船田(訳), "Processingをはじめよう", オライリージャパン, 2011.

オフィスアワー以外でも質問は受け付けます.

質問はメールでも受け付けます.