Processingによる画像処理プログラミング 画像情報処理 http://www.vision.cs.chubu.ac.jp/P5/ 藤吉弘亘 (Hironobu Fujiyoshi) E-mail: [email protected] Twitter: twitter.com/hf149 1 processing • JAVAをベースに開発されたプログラミング環境 – Ben Fry(MIT Media Lab) – Casey Reas (Design ¦ Media Arts Department at UCLA) – ビジュアライゼーションやメディアアートの作品制作等に 利用 See→http://processing.org/ 2 processingのダウンロード – http://processing.org/download/より使用するOSに合った ものをダウンロード Windows:解凍後、CもしくはDドライブへコピー Mac:解凍後、アプリケーションフォルダへコピー 3 processingのインターフェース 実行(play)ボタン プログラムを実行する際に使用 停止(stop)ボタン プログラムを停止する際に使用 新規作成(new)ボタン 新しいファイルのことをProcessingではスケッチと呼ぶ 読込み(Opens)ボタン スケッチを読み込む 保存(Saves)ボタン インターフェイス上に表示しているスケッチに名前を つけて保存する際に使用 出力(Exports)ボタン 表示されているスケッチをJavaアプレットとして出力 またその際にJavaアプレットを表示するために必要な 最低限のHTMLタグを書き出す 4 ため,作品をそのまま 上で公開できる簡易さも備えている. カメラや ムー ビーからの読み込みが簡易であり,簡単な動画像処理プログラミングにも適しているといえる. 操作インターフェイス processingの実行 図 は のインターフェイスを示している. 図 のインターフェイス 5 URLs → http://www.processing.org/ processingのサイト → http://www.vision.cs.chubu.ac.jp/P5/ 講義資料アーカイブページ 6 Books Getting Started with Processing Casey Reas and Ben Fry. Processing: A Programming Handbook for Visual Designers and Artists Casey Reas and Ben Fry Built with Processing 前川峻志 and 田中孝太郎 7 画像の表示:画像ファイルの用意 1. 2. imageという名前のスケッチを作成 Sketch→Add Fileより画像を選択 (画像は、jpgまたはgif形式のみ) スケッチフォルダ内にdataフォルダが作成される C:¥ Documents and Setteing¥ USER¥ My Documents 8 画像の表示:image( ) PImage b; //外部変数 void setup(){ size(300,300); b = loadImage("woman.jpg"); } (0,0) (150,150) void draw() { //画像を座標(0,0)に表示 image(b, 0, 0); //画像を(150,150)にサイズ150 150で表示 image(b, 150, 150, 150, 150); } PImageはイメージを保持するためのデータタイプ。image関数が実際に画像をスクリーンに描画する。 image(PImage, x, y, width, height); 画像の表示サイズを決める高さ(height)と横幅(width)については省略することが可能である。省略した場 合は元画像のサイズが適用される。 9 画像サイズの取得:image( ) PImage b; (0,0) void setup(){ b = loadImage("woman.jpg"); size(b.width, b.height); } void draw() { image(b, 0, 0); } 外部変数としてbを登録しておくと、どこからも使用可能 画像(woman.jpg)をロードした際、width, heightにその画像サイズが代入される →これを利用してスケッチのサイズを決定すれば、サイズが違う画像に入れ変えても自動的に反映される 10 ピクセルデータの取得:get( ) get()は座標(x, y)のピクセルのRGB値を取得 get(x, y) color c = get(150, 160); → RGBカラーを扱う変数cに(255, 200, 131)が代入 ・座標(150, 160)の赤色の値だけを取り出すには int a = red(get(150, 160)); → aに255が代入される ・座標(150, 160)の緑色の値だけを取り出すには int a = green(get(150, 160)); → aに200が代入される ・座標(150, 160)の青色の値だけを取り出すには int a = blue(get(150, 160)); → aに131が代入される 11 ピクセルデータのセット:set( ) set()は座標(x, y)のピクセルにRGB値をセット set(x, y, c) color c = color(255, 255, 255); → RGBカラー変数cに白色(255,255,255)を代入 set(150, 160, c); → 座標(150,160)にカラー変数Cの値をセット 12 画像ピクセルデータの取得:get( ) PImage b; (0,0) void setup(){ b = loadImage("woman.jpg"); size(b.width, b.height); } void draw() { background(255); for(int i=0; i<b.height; i+=2){ for(int j=0; j<b.width; j+=2){ set(j, i, b.get(j,i)); } } } 13 画像ピクセルデータの取得:pixel[ ] PImage b; (0,0) void setup(){ b = loadImage("woman.jpg"); size(b.width, b.height); } void draw() { background(255); for(int i=0; i<b.height; i+=2){ for(int j=0; j<b.width; j+=2){ int pos = j * b.width + i; set(j, i, b.pixel[pos]); } } } 14 反転:Inverse PImage b; void setup(){ b = loadImage("woman.jpg"); size(b.width, b.height); } void draw() { color c; image(b, 0, 0); for(int y=0; y<b.height; y++){ for(int x=0; x<b.width; x++){ c = color(255-red(get(x,y)), 255-green(get(x,y)), 255-blue(get(x,y))); set(x, y, c); } } } http://www.vision.cs.chubu.ac.jp/p5/app/04/04/ 15 2値化:Binarization PImage b; void setup(){ b = loadImage("woman.jpg"); size(b.width,b.height); } void draw() { color c; image(b, 0, 0); for(int y=0; y<b.height; y++){ for(int x=0; x<b.width; x++){ if(red(get(x,y)) > 200){ c = color(255,255,255); } else { c = color(0,0,0); } set(x, y, c); } } } http://www.vision.cs.chubu.ac.jp/p5/app/04/05/ 16 画像フィルタによる平滑化 PImage a; void MovingAverageFilter(PImage F, PImage G, int m) PImage b; { for(int y=0; y<F.height; y++) { void setup(){ for(int x=0; x<F.width; x++) { a = loadImage("woman.jpg"); int sum=0; b = a.copy(); int cc=0; size(b.width,b.height); for(int j=-m; j<m+1; j++){ } for(int i=-m; i<m+1; i++){ if(0 < x+i && x+i < F.width && int gray(color c){ 0 < y+j && y+j < F.width){ float r = red(c); sum += gray(F.get(x+i,y+j)); float g = green(c); cc++; float b = blue(c); } return((int)(0.299*r + 0.587*g + 0.114*b)); } } } void draw() int c = sum/cc; { G.set(x,y,color(c,c,c)); background(255); } MovingAverageFilter(b,a,2); image(a, 0, 0); } } } http://www.vision.cs.chubu.ac.jp/p5/app/04/11/ 17 処理結果 m=2 m=5 18 ラプラシアンフィルタによる鮮鋭化 PImage a; void LapracianFilter(PImage F, PImage G) PImage b; { int m=1; void setup(){ int[][] H = { {0, 1, 0}, a = loadImage("woman.jpg"); {1, -4, 1}, b = a.copy(); {0, 1, 0} }; size(b.width,b.height); } for(int j=m; j<F.height-m; j++) { for(int i=m; i<F.width-m; i++){ int gray(color c){ int sum = 0; float r = red(c); for(int k=-m; k<(m+1); k++) { float g = green(c); for(int l=-m; l<(m+1); l++){ float b = blue(c); sum += grey(F.get(i+k,j+l)) * H[k+m][l+m]; return((int)(0.299*r + 0.587*g + 0.114*b)); } } } void draw() int c = grey(b.get(i,j)) - sum; { G.set(i,j,color(c,c,c)); background(255); } LapracianFilter(a,b); image(b,0,0); } } } http://www.vision.cs.chubu.ac.jp/p5/app/04/10/ 19 処理結果 元画像 ラプラシンフィルタによる鮮鋭化 20 コンボリューション float [][]Mask={ {1.0/9, 1.0/9, 1.0/9}, {1.0/9, 1.0/9, 1.0/9}, {1.0/9, 1.0/9, 1.0/9} }; void Convolution(PImage F, PImage G, float h[][], int M, int N){ for(int j=0; j<F.height; j++){ for(int i=0; i<F.width; i++){ float r=0, g=0, b=0; for(int l=-N; l<N+1; l++){ for(int k=-M; k<M+1; k++){ 1/9 1/9 1/9 1/9 1/9 1/9 1/9 1/9 1/9 フィルタ(2次元配列) if(0 < i+k && i+k < F.width && 0 < j+l && j+l < F.height){ r += red( F.get(i+k, j+l)) * h[l+N][k+M]; g += green(F.get(i+k, j+l)) * h[l+N][k+M]; b += blue( F.get(i+k, j+l)) * h[l+N][k+M]; } } } color c = color(r, g, b); G.set(i, j, c); } } コンボリューション } http://www.vision.cs.chubu.ac.jp/p5/app/ImageProcessing/01/ 21 コンボリューション PImage a, b; void setup() { a = loadImage("NGO.jpg"); b = a.get(); size(b.width*2, b.height); Convolution(a, b, Mask, Mask[0].length/2, Mask.length/2); } void draw() { Mask.length ↓ image(a, 0, 0); 3/2=1 image(b, a.width, 0); } Mask[0].length→ 5/2=2 1/15 1/15 1/15 1/15 1/15 1/15 1/15 1/15 1/15 1/15 1/15 1/15 1/15 1/15 1/15 M=2, N=1 Mask[3][5]の場合 22 処理結果1:平均フィルタによる平滑化 1/25 1/25 1/25 1/25 1/25 1/25 1/25 1/25 1/25 1/25 1/25 1/25 1/25 1/25 1/25 1/25 1/25 1/25 1/25 1/25 1/25 1/25 1/25 1/25 1/25 23 処理結果2 : ガウシンフィルタによる平滑化 1/ 4/ 6/ 4/ 1/ 256 256 256 256 256 4/ 16/ 24/ 116/ 4/ 256 256 256 256 256 6/ 24/ 36/ 24/ 6/ 256 256 256 256 256 4/ 16/ 24/ 16/ 4/ 256 256 256 256 256 1/ 4/ 6/ 4/ 1/ 256 256 256 256 256 24 処理結果3:特定方向フィルタによる平滑化 0 0 0 0 1/7 0 0 0 1/7 0 0 0 1/7 0 0 0 1/7 0 0 0 1/7 0 0 0 0 25 処理結果4:ラプラシアンフィルタによる先鋭化 -1 -1 -1 -1 9 -1 -1 -1 -1 26 TiltShift Generator ミニチュア風写真の原理: http://d.hatena.ne.jp/htee2006/20090928/1254122943 被写界深度情報とシーンの意味的情報のズレを利用 して、脳を騙すこと。 本来は、レンズを傾けられるティルトレンズを用い て、上下、あるいは左右の被写界深度を変えて撮影 する。 ティルトレンズ iOSアプリ→http://itunes.apple.com/jp/app/tiltshift-generator-minichua/id327716311?mt=8 27 ProcessingでTiltShift Generator 平滑化度合:大 平滑化度合:小 m=0 平滑化度合:小 平滑化度合:大 28 P5TiltShiftGenerator 01 PImage a, b; boolean ON = false; void draw() { background(255); void setup() if(ON){ { TiltShiftGenerator(a, b, mouseY, 30); a = loadImage("TYO.jpg"); ON = false; b = a.get(); } size(b.width, b.height); image(b, 0, 0); //size(600, 300); } draw_line(mouseY, 30); } void draw_line(int y, int w) { if(w < y && y < height-w){ stroke(255, 255, 255, 100); line (0,y-w,width,y-w); void mousePressed() { ON = true; } line (0,y+w,width,y+w); } } http://www.vision.cs.chubu.ac.jp/p5/app/ImageProcessing/02/ 29 P5TiltShiftGenerator 02 void TiltShiftGenerator(PImage F, PImage G, int center, int w) { for(int y=0; y<F.height; y++){ for(int x=0; x<F.width; x++){ if(y < center-w){ MovingAverageFilter_ColorImage(F, G, x, y, ((center-w)-y)/20+1,((center-w)-y)/20+1); } else if(y < (center+w)-10){ G.set(x,y,F.get(x,y)); } else{ MovingAverageFilter_ColorImage(F, G, x, y, (y-(center+w))/20+1,(y-(center+w))/20+1); } } } } 30 P5TiltShiftGenerator 03 void MovingAverageFilter_ColorImage(PImage F, PImage G, int x, int y, int m, int n) { int sum_r = 0; int sum_g = 0; int sum_b = 0; int cc = 0; for(int j=-n; j<n+1; j++){ for(int i=-m; i<m+1; i++){ if(0 < x+i && x+i < F.width && 0 < y+j && y+j < F.width){ sum_r += red(F.get(x+i, y+j)); sum_g += green(F.get(x+i, y+j)); sum_b += blue(F.get(x+i, y+j)); cc ++; } } } color c = color(sum_r/cc, sum_g/cc, sum_b/cc); G.set(x, y, c); } 31 移動平均の高速化:積分画像の利用 • 矩形領域の輝度値の和を高速に算出可能 O I(i, j) B D S = A-B-C+D S (i, j) C A 32 P5TiltShiftGenerator(積分画像)01 PImage a, b; for(int x=1; x<F.width; x++){ int ii_r[][], ii_g[][], ii_b[][]; ii_r[0][x] = ii_r[0][x-1] + (int)red(F.get(x,0)); ii_g[0][x] = ii_r[0][x-1] + (int)green(F.get(x,0)); boolean ON = false; ii_b[0][x] = ii_r[0][x-1] + (int)blue(F.get(x,0)); } void setup() for(int y=1; y<F.height; y++){ { int r=(int)red(F.get(0,y)); a = loadImage("TYO.jpg"); int g=(int)green(F.get(0,y)); b = a.get(); int b=(int)blue(F.get(0,y)); ii_r = new int[a.height][a.width]; for(int x=1; x<F.width; x++){ ii_g = new int[a.height][a.width]; r += (int)red(F.get(x,y)); ii_b = new int[a.height][a.width]; g += (int)green(F.get(x,y)); size(541, 541); b += (int)blue(F.get(x,y)); IntegralImage(a, ii_r, ii_g, ii_b); ii_r[y][x] = ii_r[y-1][x] + r; } ii_g[y][x] = ii_g[y-1][x] + g; ii_b[y][x] = ii_b[y-1][x] + b; void IntegralImage(PImage F, int ii_r[][], int ii_g[][], } int ii_b[][]){ } ii_r[0][0] = (int)red(F.get(0,0)); } ii_g[0][0] = (int)green(F.get(0,0)); ii_b[0][0] = (int)blue(F.get(0,0)); http://www.vision.cs.chubu.ac.jp/p5/app/ImageProcessing/03/ 33 P5TiltShiftGenerator(積分画像) 02 void draw_line(int y, int w) void TiltShiftGenerator(PImage F, PImage G, int { center, int w) if(w < y && y < height-w){ { stroke(255, 255, 255, 100); for(int y=0; y<F.height; y++){ line (0,y-w,width,y-w); for(int x=0; x<F.width; x++){ line (0,y+w,width,y+w); if(y < center-w){ } MovingAverageFilter_ColorImage(F, G, x, y, } ((center-w)-y)/20+1,((center-w)-y)/20+1); void draw() } { else if(y < center+w){ background(255); G.set(x,y,F.get(x,y)); if(ON){ } TiltShiftGenerator(a, b, mouseY, 30); else{ ON = false; } MovingAverageFilter_ColorImage(F, G, x, y, (y(center+w))/20+1,(y-(center+w))/20+1); image(b, 0, 0); } draw_line(mouseY, 40); } } } void mousePressed() } { ON = true; } 34 P5TiltShiftGenerator(積分画像) 02 void MovingAverageFilter_ColorImage(PImage F, else { PImage G, int x, int y, int m, int n) for(int j=-n; j<n+1; j++){ { for(int i=-m; i<m+1; i++){ int sum_r = 0; int sum_g = 0; if(0 < x+i && x+i < F.width && 0 < y+j && y+j < F.width){ int sum_b = 0; sum_r += red(F.get(x+i, y+j)); int cc = 0; sum_g += green(F.get(x+i, y+j)); color c; sum_b += blue(F.get(x+i, y+j)); cc ++; if(0<x-m && 0<y-n && x+m < F.width && y+n < } F.height){ } sum_r = ii_r[y+n][x+m] - ii_r[y-n][x+m] - ii_r[y+n] } [x-m] + ii_r[y-n][x-m]; c = color(sum_r/cc, sum_g/cc, sum_b/cc); sum_g = ii_g[y+n][x+m] - ii_g[y-n][x+m] - ii_g[y } +n][x-m] + ii_g[y-n][x-m]; sum_b = ii_b[y+n][x+m] - ii_b[y-n][x+m] - ii_b[y G.set(x, y, c); } +n][x-m] + ii_b[y-n][x-m]; c = color(sum_r/((2*m)*(2*n)), sum_g/ ((2*m)*(2*n)), sum_b/((2*m)*(2*n))); } 35
© Copyright 2024 ExpyDoc