6:イメージ(Image)

以降のサンプルをローカルで実行するには、画像ファイルと、動作するローカルサーバーが必要です。

とはいえ、Visual Studio Codeとその機能拡張「Liver Server」を使用すると、簡単に簡易的なローカルサーバーが構築できます。ダウンロードや設定方法などは「1_1:スタート p5.play」で紹介しています。


以降のサンプルで行っているのは、HTMLの<img>タグを使ったイメージの表示ではなく、p5.jsが自動で作成する<canvas>への、イメージのデータの表示です。これはつねに意識しておく必要があります。画像はp5.jsによってイメージのデータに変換されるので、後はどのようにでも料理できます。image()関数については「6_1:イメージ p5.js JavaScript」や「6:メディア イメージとサウンド Creative Coding p5.js」で詳しく述べています。


イメージのロードと表示

イメージをロードして画面に表示することができます。そのときには、実際のサイズでもそれ以外のどんなサイズでも表示できます。

// 変数imgを宣言 => setup()とdraw()関数で共通して使用するので、
// グローバル変数として宣言する
let img;

function setup() {
    createCanvas(720, 400);
    img = loadImage('assets/moonwalk.jpg'); // 画像を読み込む
}

function draw() {
    // 読み込んだイメージを、点(0,0)に、実際のサイズで表示する
    image(img, 0, 0);
    // イメージを点(0, height/2)に、半分のサイズで表示する
    image(img, 0, height / 2, img.width / 2, img.height / 2);
}

解説

コード自体はp5.jsの機能によって非常に簡単です。画像はp5.jsのイメージのデータに変換されるので、image()関数の機能によって簡単に加工できます。

背景用イメージ

以下は背景用のイメージを最速でロードする方法の例です。画像を背景として読み込むには、プログラムと同じ幅と高さである必要があります。

let bg;
let y = 0;

function setup() {
    // 背景イメージは、createCanvas()関数のパラメータと同じサイズである必要がある。
    // このプログラムで使用している画像のサイズは720x400ピクセル
    bg = loadImage('assets/moonwalk.jpg');
    createCanvas(720, 400);
}

function draw() {
    // 背景イメージを描画
    background(bg);
    // 背景イメージであることを示すために、背景の前面で線のアニメーションを描画
    stroke(226, 204, 0);
    line(0, y, width, y);

    y++;
    if (y > height) {
        y = 0;
    }
}

解説

background()関数には0から255までのRGB値などが渡せますが、p5.Imageオブジェクトを渡すこともできます。

p5.Imageオブジェクトは、p5.jsで扱うことのできるイメージのデータです。これをbackground()に渡すと、p5.jsはそのデータを背景としてキャンバス全体に描画します。

透明度

マウスポインタを左右に動かすと、半透明のイメージの位置を変えることができます。このプログラムでは、2つのイメージの重なりを、tint()関数によるイメージのアルファ値の変更によって表しています。

let img;
let offset = 0;
let easing = 0.05;

function setup() {
    createCanvas(720, 400);
    img = loadImage('assets/moonwalk.jpg'); // 画像をプログラムに読み込む
}

function draw() {
    image(img, 0, 0); // 完全な不透明度で表示
    let dx = mouseX - img.width / 2 - offset;
    offset += dx * easing;
    tint(255, 127); // 半分の不透明度で表示
    image(img, offset, 0);
}
解説

tint()関数は重ね塗りのような効果をもたらします。

リファレンスメモ

tint()

説明

イメージを表示するための塗り値を設定する。指定したカラーでイメージを重ね塗りしたり、アルファ値を含めることでイメージに透明度を持たせることができる。

イメージのカラーに影響を及ぼさずに透明度を適用するには、ティント色に白を用い、アルファ値を指定する。たとえばtint(255, 128)は50&の透明度をイメージにもたらす(デフォルトのアルファ値の範囲が0-255と仮定した場合。これはcolorMode()で変更できる)。

パラメータgrayの値はcolorMode()で指定された現在の最大値以下でなくてはならない。デフォルトの最大値は255。

シンタックス

tint(v1, v2, v3, [alpha])
tint(value)
tint(gray, [alpha])
tint(values)
tint(color)

以下はtint()関数の例です。

let img;

function preload() {
    img = loadImage('assets/laDefense.jpg');
}

function setup() {
    createCanvas(300, 300);

    // ボタンを4つ作成
    buttonA = setButton('青で重ね塗り', 310, 10);
    buttonA.mousePressed(() => {
        clear();
        tint(0, 153, 204); // => (0, 153, 204)の青
        image(img, 0, 0);
    });
    buttonB = setButton('青で重ね塗りし半透明にする', 310, 60);
    buttonB.mousePressed(() => {
        clear();
        tint(0, 153, 204, 126); //=> (0, 153, 204)の青 + 126(半透明)
        image(img, 0, 0);
    });
    buttonC = setButton('色を変えずに透明度を適用', 310, 110);
    buttonC.mousePressed(() => {
        clear();
        tint(255, 126); // => 256は白、126は半透明
        image(img, 0, 0);
    });
    buttonD = setButton('オリジナル', 310, 160);
    buttonD.mousePressed(() => {
        clear();
        tint(255, 255); // => 256は白、255は透明なし
        image(img, 0, 0);
    });
    image(img, 0, 0);
}

function setButton(label, xpos, ypos) {
    button = createButton(label);
    button.size(200, 30);
    button.position(xpos, ypos);
    return button;
}

アルファマスク

イメージのさまざまな部分の透明度を指定するために、そのイメージにかける(イメージの前面を覆う)”マスク”を読み込んで使います。覆われるイメージと覆うマスクのイメージは、p5.Imageのmask()関数によって混ぜ合わされます。

let img;
let imgMask;

function preload() {
    img = loadImage('assets/moonwalk.jpg');
    imgMask = loadImage('assets/mask.png');
}

function setup() {
    createCanvas(720, 400);
    img.mask(imgMask);
    imageMode(CENTER);
}

function draw() {
    // 背景色を青で描画
    background(0, 102, 153);
    // アルファマスクをかけたimgを描画
    image(img, width / 2, height / 2);
    // image(img, mouseX, mouseY);
}

解説

上の実行図は、右の宇宙飛行士の部分が青い丸で覆われているように見えます。これがアルファチャンネルの効果です。p5.jsのアルファマスクは、マスク用画像のアルファチャンネルを、表示用画像のアルファチャンネルとして使用することで実現されます。

上記サンプルで使われている表示用画像(左、moonwalk.jpg)とマスク用画像(右、mask.png)は次のようなファイルです。

表示用画像の上にマスク用画像を重ねると、マスク用画像の透明度のある部分を通して、表示用画像が透けて見えます。これがp5.Imageのmask()関数の働きです。サンプルのdraw()では、background()関数で青の背景色を描画しているので、この色が透けて見えることになります。

リファレンスメモ

mask()

説明

イメージAを表示するとき、イメージMを読み込みそのアルファチャンネルを、イメージAのアルファチャンネルとして使用することで、イメージAの一部が表示されないようにマスクする。

シンタックス

mask(srcImage)

パラメータ

srcImage p5.Image: source image

イメージの作成

createImage()関数は、操作可能なピクセルの新しいバッファを提供します。次のサンプルはグラデーションイメージを作成します。

let img;

function setup() {
    createCanvas(720, 400);
    // 230 x 230ピクセルのp5.Imageオブジェクトを作成
    img = createImage(230, 230);
    // イメージのピクセルデータを、p5.Imageオブジェクトの[pixels]属性に読み込む
    // ピクセルデータにアクセスするには、その前にloadPixels()を呼び出す必要がある。
    img.loadPixels();
    // p5.Imageオブジェクトの全ピクセルを走査
    // 横に進みながら縦の1列を1つずつ操作する
    for (let x = 0; x < img.width; x++) {
        for (let y = 0; y < img.height; y++) {
            // 今のy位置(0から230の間)を、255から0の間に置き換える
            let a = map(y, 0, img.height, 255, 0);
            print(a);
            // 1ピクセルのカラーを設定
            img.set(x, y, [0, 153, 204, a]);
        }
    }
    // pixelsを変更したら、updatePixels()を呼び出して、その変更を更新する必要がある
    img.updatePixels();
}

function draw() {
    background(0);
    // 固定位置にイメージを描画
    image(img, 90, 80);
    // マウス位置にイメージを描画
    image(img, mouseX - img.width / 2, mouseY - img.height / 2);
}

解説

p5.jsでは、次の決まった手順で、イメージの作成、操作、描画が行えます。

  1. createImage()でp5.Imageオブジェクトを作成する。
  2. p5.ImageオブジェクトのloadPixels()メソッドを呼び出し、ピクセルにアクセスできるようにする。
  3. 2重のforループでピクセルにアクセスし、p5.Imageオブジェクトのset()メソッドでピクセルを設定する。
  4. 設定が終わったら、p5.ImageオブジェクトのupdatePixelsを呼び出してピクセルを更新する。
  5. image()関数にp5.Imageオブジェクトを渡して描画する。

以下は手順の簡単な例です。変数alphaに代入する数値を変えると、描画するピンクの透明度が変化します。またpixels配列を出力しています。

function setup() {
    createCanvas(200, 200);
    // 100 x 100ピクセルのp5.Imageオブジェクトを作成
    const img = createImage(100, 100);

    // イメージのピクセルデータを、p5.Imageオブジェクトの[pixels]属性に読み込む
    // ピクセルデータにアクセスするには、その前にloadPixels()を呼び出す必要がある。
    img.loadPixels();
    // p5.Imageオブジェクトの全ピクセルを走査
    // 横に進みながら縦の1列を1つずつ操作する
    for (let x = 0; x < img.width; x++) {
        for (let y = 0; y < img.height; y++) {

            const alpha = 255; // 0や1127などを代入してみる
            // [255, 102, 204, alpha]はピクセルの配列
            img.set(x, y, [255, 102, 204, alpha]);
        }
    }
    // p5.Imageオブジェクトのpixels配列を出力
    print(img.pixels);
    // pixelsを変更したら、updatePixels()を呼び出して、その変更を更新する必要がある
    img.updatePixels();

    background(0);
    image(img, 0, 0);
}

alphaを255に設定すると、不透明なピンクで描画されます。127にすると半透明になり、0にすると透明になります。

リファレンスメモ

createImage()

説明

新しいp5.Image(イメージを保持するためのデータ型)を作成する。これは、操作可能なピクセルの新しいバッファを提供する。バッファのサイズはwidthとheightパラメータで設定する。

p5.Image.pixelプロパティは、表示ウィンドウ(キャンバス)内の全ピクセルの値を含む配列へのアクセスを提供する。値はすべて数値。この配列は、表示ウィンドウ x 4のサイズ(pixelDensityで表される適切な要因も含まれる)を持つ。各行を左から右へ移動し、その行の1列を下って、各ピクセルを[ R,G,B,A ]の順で表す。詳細は.pixelsを参照。p5.Imageのset()get()を使う方が簡単な場合もある。

イメージのピクセルにアクセスするには、その前にloadPixels()でデータをロードする必要がある。また配列のデータを修正したら、その後はupdatePixels()を呼び出して変更を更新する必要がある。

シンタックス

createImage(width, height)

loadPixels()

説明

このイメージのピクセルデータを[pixels]属性に読み込む。

updatePixels()

説明

[pixels]配列の内容を使って、このイメージのキャンバスを更新する。

pixels

説明

p5.Image.pixelプロパティは、表示ウィンドウ(キャンバス)内の全ピクセルの値を含む配列。値はすべて数値。この配列は、表示ウィンドウ x 4のサイズ(pixelDensityで表される適切な要因も含まれる)を持つ。各行を左から右へ移動し、その行の1列を下って、各ピクセルを[ R,G,B,A ]の順で表す。

Retinaやそのほかの高密度ディスプレイはもっと多くのピクセルを持っている(pixelDensity^2分だけ)。たとえば100 x 100のイメージの場合、配列の要素数は40,000個(100 x 100 x 4)になり、pixelDensity = 2だと、160,000個になる(100 x 100 x 4 x 4)。配列の最初の4つの値(インデックス0から3)は、(0, 0)に当たるピクセルのR,G,B,A値で、次の4つの値(インデックス4から7)は、(1,0)に当たるピクセルのR,G,B,A値。一般的に言うと、(x, y)のピクセルの値を設定するには次のようにする。

// 現在のピクセル密度を調べる
let d = pixelDensity();
for (let i = 0; i < d; i++) {
    for (let j = 0; j < d; j++) {
        // loop over
        index = 4 * ((y * d + j) * width * d + (x * d + i));
        pixels[index] = r;
        pixels[index + 1] = g;
        pixels[index + 2] = b;
        pixels[index + 3] = a;
    }
}

点描

ダニエル・シフマンによる。マウスの水平方向の位置は点のサイズを制御します。イメージのピクセルにしたがって着色した円を使って、単純な点描効果を生み出します。

let img;
let smallPoint, largePoint;

function preload() {
    img = loadImage('assets/moonwalk.jpg');
}

function setup() {
    createCanvas(720, 400);
    smallPoint = 4;
    largePoint = 40;
    imageMode(CENTER);
    noStroke();
    background(255);
    img.loadPixels();
}

function draw() {
    let pointillize = map(mouseX, 0, width, smallPoint, largePoint);
    let x = floor(random(img.width));
    let y = floor(random(img.height));
    let pix = img.get(x, y);
    fill(pix, 128);
    ellipse(x, y, pointillize, pointillize);
}

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA