画像をピクセルっぽくしてみよう　

こんにちは[MYJLab Advent Calendar 2024](https://qiita.com/advent-calendar/2024/myjlab)の9日目を担当します@nightcountrycooperです。[7日目](https://qiita.com/nightcountrycooper/items/a1002de390fa118427a7)に引き続きp5.jsでのジェネラティブアート的な記事を書こうとおもいます。今回は写真をピクセルアートのように加工していきます。とても簡単ですぐできるのでぜひやってみてください。

## 準備
今回もp5.jsのwebエディタで行っていきます。以下のリンクから飛べます。
[p5.js Web Editor](https://editor.p5js.org/)

Webエディタ上に画像をロードするためにはログインする必要があります。
サイトの右上にあるLog inからログイン、もしくはアカウントがない場合はSign upをしてください。
|![p5_login.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3617893/f701bef7-ebc5-daa2-c6bb-66161fc7a9ca.png)|
|:-:|

ログインが完了したらimagesという新しいフォルダを作成します。
|![createNewFolder.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3617893/fae8424f-6400-e420-4c59-d0fb29c75cd9.png)|
|:-:|

作成したimagesフォルダの右側の▼を押してUpload Fileを開きます。
ファイルをドラッグ&ドロップしてロードします。
|![uploadImage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3617893/792fdf3f-81a8-d5e8-bb05-90a70f27656b.png)|
|:-:|





## 画像をピクセル化
#### preload
setupの前の部分で画像を読み込みます。自分の画像ごとにパスを変更してください。
```js:sketch.js
let img;
// ssetupの前に画像を読み込む
function preload() {
  img = loadImage('images/horse.jpg');
}
```

### setup
setupではcanvasサイズを指定し、画像をそのサイズに合わせていきます。
ここら辺の設定は適当に変更してください。

```js:sketch.js
function setup() {
  createCanvas(500, 500);
  
  // 画像のサイズをcanvasに合わせる
  img.resize(width, height);
  // 画像のピクセルデータを読み込む
  img.loadPixels();
  
  noStroke();
}
```

### draw 
drawではランダムな位置のピクセルの色を取得、取得した色の円を描いています。
```js:sketch.js
function draw() {
  // ランダムに取得したピクセルの色を取得
  const pixelX = random(width);
  const pixelY = random(height);
  const pixelColor = img.get(pixelX, pixelY);

  // 取得したピクセルの色で円を描く
  fill(pixelColor);
  ellipse(pixelX, pixelY, 20, 20);
}
```

**これだけで完成**

|![horse.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3617893/9ab55077-d703-130f-5f27-07d31dba2658.png)|![horsePixel.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3617893/1907b7c5-d6e4-46f5-81bc-4335e960e128.png)|
|:-:|:-:|
|before |after |


## 追加コンテンツ
ここからは好きにいじっていきましょう。

### 細かさの変更
- ellipseの直径を変更することで細かさを変更できる
- 描画のスピードが遅いと感じたら、関数を作り1回の呼び出しで複数回実行する

```js
function draw() {
  function drawPixel (){
    const pixelX = random(width);
    const pixelY = random(height);
    const pixelColor = img.get(pixelX, pixelY);

    fill(pixelColor);
    ellipse(pixelX, pixelY, 5, 5);
  }

  for (let i = 0; i < 100; i++){
    drawPixel()
  }
}
```
|<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3617893/a3f1f754-7ebc-72b0-f14b-15f3bfd0604a.png" width="50%">|
|:-:|

### 図形を変更
円ではなく四角形や三角形、楕円、その他色々な図形で描画できます。


正方形
```js
rect(pixelX, pixelY, 15, 15);
```
正六角形
beginShape()とendShape(),vertex()を用いて自分で形を作ることができます。

```js
// 正多角形を描画する
function drawPolygon(x, y, r, vertexNum) {
  push();
  translate(x, y);

  beginShape();
  for (let i = 0; i < vertexNum; i++) {
    let angle = TWO_PI * i / vertexNum;
    let vx = r * cos(angle);
    let vy = r * sin(angle);
    vertex(vx, vy);
  }
  endShape(CLOSE);
  
  pop();
}
```

|<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3617893/e9e7a19e-c31b-0d2c-62f5-f6e5a16411d1.png"width="100%">|<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3617893/ee369fb7-a262-44d7-8aa4-661fa7126489.png"width="100%">|
|:-:|:-:|
|正方形 | 正六角形|



### ランダムな大きさにする
randomやnoiseなどを用いてランダムな大きさの図形で描画する。
また図形自体を複数混ぜて描画することも可能です。
```js
ellipse(pixelX, pixelY, 1+random()*30, 1+random()*30)
```
|<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3617893/46f0aa4d-a3e5-92d1-ce5e-9787826c4f5d.png" width="50%">|
|:-:|

### 色を変えてみる
`const pixelColor = img.get(pixelX, pixelY);`で得られる色の情報は`[135, 176, 211, 255] = [R, G, B, A]`の形になっています。
そのため色を自由にいじって変換することができます。

|<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3617893/1de9371a-5036-9aef-9019-3ab5e05c198b.png" width="100%">|<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3617893/cfa8e10c-7ec4-50fd-f28a-bcdfae48e4d9.png" width="100%">|<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3617893/1033be4b-e9af-e380-888f-f73098a572de.png" width="100%">|
|:-:|:-:|:-:|
|Alpha = 10|RGBすべての値を反転|補色での表示|

- 補色の変換
```js
// RGBのリストを引数にして呼び出すと保初稿のリストを返す
function ConvertToComplementaryColor(col){
  let buf = Math.max(...col) + Math.min(...col)
  console.log(buf)
  new_col = [buf - col[0], buf - col[1], buf - col[2]]
  return new_col
}
```


## おわりに
まだまだ変更の余地はあると思うので好きにいじってみてください。
今回はピクセルの色を取得してその色で図形を描いているだけですが、実際に画像のピクセルをいじることもできます。ピクセルを直接操作することで、画像が溶けているように見せたりピクセルの粒子を動かすこともできます。興味があれば挑戦してみてください。