差分
このページの2つのバージョン間の差分を表示します。
| 両方とも前のリビジョン 前のリビジョン 次のリビジョン | 前のリビジョン | ||
| lecture:design_with_prototyping:p5.js編:11.ピクセル再構成 [2021/02/28 14:52] – [閑話休題] baba | lecture:design_with_prototyping:p5.js編:11.ピクセル再構成 [2021/05/11 15:25] (現在) – [Sample04] baba | ||
|---|---|---|---|
| 行 126: | 行 126: | ||
| for (let j = 0; j < sample_image.width; | for (let j = 0; j < sample_image.width; | ||
| let c = sample_image.get(j, | let c = sample_image.get(j, | ||
| - | let gray = (blue(c)+green(c)+blue(c))/ | + | let gray = (red(c)+green(c)+blue(c))/ |
| stroke(gray); | stroke(gray); | ||
| point(j, i); | point(j, i); | ||
| 行 232: | 行 232: | ||
| <WRAP clear/> | <WRAP clear/> | ||
| ====== 対象物を表現するには ====== | ====== 対象物を表現するには ====== | ||
| - | ここまでのサンプルは抽象的な画像を用いて来ましたが,少し具体的な下記画像に変えてみたいと思います. | + | 私達が見ているのは,画像のピクセルの集合体です.画面におけるピクセルとは画像を表示するための最小単位になっています.単位について考えてみます.単位とはなんでしょうか?なにかものを表すための基準となる目盛りのことです.ではその基準は誰が決めるのか.それはエンジニアであったりデザイナであったりアーティストであったり,研究者であったり.単位はそれを表す上で実は自由に決めて良いものでもあります.その証拠に,オーム(Ω)やニュートン(N),アンペア(A),テスラ,ボルト,ベクレル,ヘルツなどその単位を定義付けた科学者の名前がそのまま単位になっている事例が少なからず知られています. |
| - | {{ : | + | |
| + | 単位とは量を把握するための単なる仕組みであり、私達はこれを客観的な手法からときには超主観的な場合にもこの単位を利用して世界にアクセスしています。単位に関して個人的な短い記事を書いておいたので以下をお読みください。 | ||
| + | * 単位について:https:// | ||
| - | 私達が見ているのは,画像のピクセルの集合体です.画面におけるピクセルとは画像を表示するための最小単位になっています. | + | さて、画素単位は1ピクセルです.ではここで,10x10ピクセルを1単位として考えてみます.一つの画素を一つの単位として考えるのではなく,10の画素を一つ単位として考えます.10ピクセルごとに丸で描画してみると,目の細かいモザイクのような効果になりました. |
| - | 単位について考えてみます.単位とはなんでしょうか?なにかものを表すための基準となる目盛りのことです.ではその基準は | + | {{ : |
| - | 誰が決めるのか.それはエンジニアであったりデザイナであったりアーティストであったり,研究者であったり.単位はそれを | + | <file .js sketch.js> |
| - | 表す上で実は自由に決めて良いものでもあります.その証拠に,オーム(Ω)やニュートン(N),アンペア(A),テスラ,ボルト, | + | var sample_image; |
| - | ベクレル,ヘルツなどその単位を定義付けた科学者の名前がそのまま単位になっている事例が少なからず知られています. | + | |
| - | + | function preload() { | |
| - | 上記で見ている画像はニューヨークのセントラルパーク前の横断歩道前で私が撮影した画像です.800x597のピクセル数で構成 | + | sample_image |
| - | されており,画素単位は1ピクセルです.ではここで,10ピクセルを1単位として考えてみます.一つの画素を一つの単位として考えるのではなく,10の画素を一つ単位として考えます. | + | } |
| - | + | ||
| - | {{ : | + | function setup() { |
| - | <file .pde sample07.pde> | + | createCanvas(500, 336); |
| - | PImage img; | + | |
| - | img = loadImage(" | + | noLoop(); |
| - | size(800, 597); | + | } |
| - | imageMode(CENTER); | + | |
| - | noStroke(); | + | function draw() { |
| - | background(255); | + | background(0); |
| - | for ( int i = 0; i < img.height; i=i+10 ) { | + | |
| - | for ( int j = 0; j < img.width; j=j+10 ) { | + | |
| - | | + | for (let j = 0; j < sample_image.width; j+=10) { |
| - | stroke(red(c), green(c), blue(c)); | + | |
| - | | + | stroke(c); |
| - | | + | strokeWeight(10); |
| - | point(j, i); | + | point(j, i); |
| + | } | ||
| } | } | ||
| } | } | ||
| </ | </ | ||
| - | <WRAP center round tip 60%> | ||
| - | 上記のプログラムを setup(), draw()で下記直し,tweakモードで実行してみましょう.それぞれforループにあるi, | ||
| - | </ | ||
| - | 10ピクセルごとに丸で描画してみると,目の細かいモザイクのような効果になりました.ではこの10ピクセル分の塊を別の単位に置き換えてみましょう. | + | ===== 文字を単位にしてみる ===== |
| - | 文字' | + | |
| - | {{ : | + | この10ピクセル分の塊を別の単位に置き換えてみましょう. |
| - | <file .pde sample08.pde> | + | 文字' |
| - | PImage img; | + | {{ : |
| - | img = loadImage(" | + | <file .js sketch.js> |
| - | size(800, 597); | + | var sample_image; |
| - | imageMode(CENTER); | + | |
| - | noStroke(); | + | function preload() { |
| - | background(255); | + | sample_image |
| - | for ( int i = 0; i < img.height; | + | } |
| - | for ( int j = 0; j < img.width; | + | |
| - | | + | function setup() { |
| - | fill(red(c),green(c),blue(c)); | + | createCanvas(500, 336); |
| - | text("A",j,i); | + | |
| + | noLoop(); | ||
| + | } | ||
| + | |||
| + | function draw() { | ||
| + | background(255); | ||
| + | |||
| + | | ||
| + | for (let j = 0; j < sample_image.width; j+=10) { | ||
| + | | ||
| + | fill(c); | ||
| + | strokeWeight(0); | ||
| + | textSize(10); | ||
| + | text('A',j,i); | ||
| + | } | ||
| } | } | ||
| } | } | ||
| </ | </ | ||
| - | ====== 文字の複雑さを濃度として考え、ピクセルを描画する | + | |
| + | <WRAP center round todo 60%> | ||
| + | < | ||
| + | let char_typed; | ||
| + | function keyPressed(){ | ||
| + | char_typed | ||
| + | } | ||
| + | </ | ||
| + | というコードをsketch.jsに追記してあげると入力した文字を char_typed というグローバル変数に保存しておくことができます。これを利用してA以外の文字でピクセル表示に切り替えられるようにプログラムを書き換えて見ましょう。 | ||
| + | </ | ||
| + | |||
| + | |||
| + | ===== 文字の複雑さを濃度として考え、ピクセルを描画する ===== | ||
| いわゆるアスキーアートと呼ばれる手法です。ピクセルに対応する濃度を文字種に変換することで、文字だけで絵を表現する独特の手法になります。ここまでですでに各ピクセルの明るさ情報は取得できているので、それを利用してどの文字を利用するのが良いかがわかれば実装ができそうです。[[http:// | いわゆるアスキーアートと呼ばれる手法です。ピクセルに対応する濃度を文字種に変換することで、文字だけで絵を表現する独特の手法になります。ここまでですでに各ピクセルの明るさ情報は取得できているので、それを利用してどの文字を利用するのが良いかがわかれば実装ができそうです。[[http:// | ||
| char[] char_pixel = {' | char[] char_pixel = {' | ||
| 行 298: | 行 322: | ||
| 上記の配列を利用して、真っ暗だと ' | 上記の配列を利用して、真っ暗だと ' | ||
| * 0-255 のピクセルbrightnessを 0 - (char_pixel.length-1)のサイズに変換する | * 0-255 のピクセルbrightnessを 0 - (char_pixel.length-1)のサイズに変換する | ||
| - | * brightness(c1)とすることで、輝度情報を取得できる | + | * brightness(c)とすることで、輝度情報を取得できる |
| の2つを追記できれば良いかなと思います。下記画像をよく見ると小さな文字だけで構成されているのがわかるかと思います。 | の2つを追記できれば良いかなと思います。下記画像をよく見ると小さな文字だけで構成されているのがわかるかと思います。 | ||
| - | {{ : | + | {{ : |
| - | <file .pde sample08_2.pde> | + | <file .js sketch.js> |
| - | import processing.video.*; | + | var sample_image; |
| - | char[] | + | |
| + | const char_pixel = [' | ||
| ' | ' | ||
| ' | ' | ||
| - | '?', | + | '?', |
| - | PImage img; | + | function preload() { |
| - | size(800, 597); | + | |
| - | img = loadImage(" | + | } |
| - | imageMode(CENTER); | + | |
| - | noStroke(); | + | function setup() { |
| - | print(char_pixel.length); | + | |
| - | textSize(5); | + | |
| - | + | noLoop(); | |
| - | noFill(); | + | } |
| - | background(0); | + | |
| - | for ( int i = 0; i < img.height; i=i+5 ) { | + | function draw() { |
| - | | + | background(0); |
| - | | + | |
| - | color c1 = img.get(j, i); | + | |
| - | float brightness | + | for (let j = 0; j < sample_image.width; j+=2) { |
| - | text(char_pixel[int(brightness)], j, i); | + | let c = sample_image.get(j, i); |
| + | let pos = parseInt(map(brightness(c), | ||
| + | | ||
| + | | ||
| + | textSize(2); | ||
| + | | ||
| + | } | ||
| } | } | ||
| - | endShape(); | ||
| } | } | ||
| - | |||
| </ | </ | ||
| ===== 線で表現する ===== | ===== 線で表現する ===== | ||
| - | <WRAP center round tip 60%> | + | 上記はピクセルをベースに対象物を再構成してみましたが,次は線を用いてみます.テレビの走査線のように左から右へ向けて黒い線を引きます。ただしただ真っ直ぐな線では真っ黒なキャンバスができあがるだけですので、画素の明るさ(brightness)に応じて線を少し上方向にずらして描画してみると、以下のような出力結果を得ることができます。すこし不思議な画像になりましたね。このサンプルではパラメータを調整できるように, |
| - | 以下のサンプルプログラムはsetup(), draw()の内プログラムになっています.自分でvoid setup(){} void draw(){}に書き直して | + | |
| - | tweakモード実行しつつ,プログラムの振る舞いを観察してみましょう. | + | |
| - | </ | + | |
| - | 上記はピクセルをベースに対象物を再構成してみましたが,次は線を用いてみます. | + | {{ : |
| - | {{ : | + | <WRAP group> |
| - | <file .pde sample09.pde> | + | <WRAP half column> |
| - | PImage img; | + | |
| - | img = loadImage(" | + | <file .js sketch.js> |
| - | size(800, 597); | + | var sample_image; |
| - | imageMode(CENTER); | + | let x_step, y_step, y_max; |
| - | noFill(); | + | |
| - | background(255); | + | function preload() { |
| - | for( int i = 0; i < img.height; i++ ){ | + | sample_image |
| - | + | } | |
| - | | + | |
| - | for( int j = 0; j < img.width; j++ ){ | + | function setup() { |
| - | | + | createCanvas(500, 336); |
| - | float gray = (red(c)+green(c)+blue(c))/ | + | |
| - | | + | |
| - | vertex(j,i-gray/10.0); | + | |
| + | x_step = select('# | ||
| + | y_step = select('# | ||
| + | y_max = select('# | ||
| + | noLoop(); | ||
| + | } | ||
| + | |||
| + | function draw() { | ||
| + | | ||
| + | | ||
| + | | ||
| + | beginShape(); | ||
| + | for (let j = 0; j < sample_image.width; j += x_step) { | ||
| + | | ||
| + | let b = brightness(c); | ||
| + | b = map(b, 0, 255, 0, y_max); | ||
| + | vertex(j, i - b); | ||
| + | } | ||
| + | endShape(); | ||
| } | } | ||
| - | endShape(); | + | } |
| + | |||
| + | function xChanged() { | ||
| + | x_step = this.value(); | ||
| + | draw(); | ||
| + | } | ||
| + | |||
| + | function yChanged() { | ||
| + | y_step = this.value(); | ||
| + | draw(); | ||
| + | } | ||
| + | |||
| + | function maxChanged() { | ||
| + | y_max = this.value(); | ||
| + | draw(); | ||
| } | } | ||
| </ | </ | ||
| + | </ | ||
| + | |||
| + | <WRAP half column> | ||
| + | <file .html index.html> | ||
| + | < | ||
| + | <html lang=" | ||
| + | < | ||
| + | <script src=" | ||
| + | <script src=" | ||
| + | <link rel=" | ||
| + | <meta charset=" | ||
| + | |||
| + | </ | ||
| + | < | ||
| + | <script src=" | ||
| + | x_step:< | ||
| + | y_step:< | ||
| + | y_max:< | ||
| + | |||
| + | </ | ||
| + | </ | ||
| + | |||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | |||
| ここで少し工夫している箇所は vertex 関数において,ただ座標を正しくうつのではなく,その画素の | ここで少し工夫している箇所は vertex 関数において,ただ座標を正しくうつのではなく,その画素の | ||
| グレースケール値に基づいて上下に位置を動かしていることです.これにより明るめの画素は上方向に座標が | グレースケール値に基づいて上下に位置を動かしていることです.これにより明るめの画素は上方向に座標が | ||
| - | 移動し,暗めの画素は下方向に画素が移動します.上記プログラムはそれを画像サイズの縦ピクセル分すべて | + | 移動し,暗めの画素は下方向に画素が移動します. |
| - | 描画していますが,これを少し間引いて下記のようなプログラムに変更してみます.これまで i++ としてた | + | |
| - | ものを i=i+5 と変更したのみです. | + | |
| - | {{ : | + | |
| - | <file .pde sample10.pde> | + | |
| - | PImage img; | + | |
| - | img = loadImage(" | + | |
| - | size(800, 597); | + | |
| - | imageMode(CENTER); | + | |
| - | noFill(); | + | |
| - | background(255); | + | |
| - | for( int i = 0; i < img.height; i=i+5 ){ // 変更箇所 | + | |
| - | + | ||
| - | beginShape(); | + | |
| - | for( int j = 0; j < img.width; j++ ){ | + | |
| - | color c = img.get(j, | + | |
| - | float gray = (red(c)+green(c)+blue(c))/ | + | |
| - | stroke(0, | + | |
| - | vertex(j, | + | |
| - | } | + | |
| - | endShape(); | + | |
| - | } | + | |
| - | </ | + | |
| + | ==== 線の本数や頂点座標のずらし方を変更してみる ==== | ||
| 次はプログラムを少し最初に戻して,描く線にアルファ値をもたせてみます.アルファ値とは | 次はプログラムを少し最初に戻して,描く線にアルファ値をもたせてみます.アルファ値とは | ||
| - | 透明度のことで,詳細は https://processing.org/tutorials/color/ を参照すると | + | 透明度のことで,詳細は https://p5js.org/reference/#/p5/ |
| よいでしょう. | よいでしょう. | ||
| - | この透明度を利用し,これまで真っ黒で書いていた線に対して一定の透明度をつけてみます. | + | この透明度を利用し,これまで真っ黒で書いていた線に対して一定の透明度(stroke(0, |
| - | 実行結果とプログラムは下記の通りです.面白いことに結果として得られた画像は,デプスマップ(深度情報) | + | 実行結果とプログラムは下記の通りです.面白いことに結果として得られた画像は,凹凸がついた銀盤のように見えますね。なお下記画像のパラメータは |
| - | を持った画像のように見えますね. | + | * x_step = 1; |
| + | * y_step = 1; | ||
| + | * y_max = 5; | ||
| + | としています。 | ||
| - | {{ : | + | {{ : |
| - | <file .pde sample12.pde> | + | |
| - | PImage img; | + | |
| - | img = loadImage(" | + | <WRAP center round tip 60%> |
| - | size(800, 597); | + | ここまで学習した内容から、単位を別のなにかに置き換えることでスーラの絵画を再構成してください。 |
| - | imageMode(CENTER); | + | |
| - | noFill(); | + | |
| - | background(255); | + | |
| - | for( int i = 0; i < img.height; i++ ){ | + | |
| - | + | </WRAP> | |
| - | | + | |
| - | for( int j = 0; j < img.width; j++ ){ | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | vertex(j, | + | |
| - | } | + | |
| - | endShape(); | + | |
| - | } | + | |
| - | </file> | + | |