IPPONグランプリのプロフィール画像を作りたい（わけではなかったのです）．

# きっかけ
2023年6月，北海道立近代美術館の特別展トリック×イリュージョン！を訪れた際にある作品を見て，作りたいアートのイメージが急に湧いてきた．それはソースコードの文字列で人の顔を表現するもので，すぐにその場で作成可能か調べてみた．画像から人物だけを切り抜き，2値化して黒い部分だけに上からソースコードを貼り付けてみようかと思っていると，[IPPONグランプリの公式サイト](https://www.fujitv.co.jp/ippon/profstudio.html)でそれっぽいものができることを発見した．しかし，この[IPPON PROFILE STUDIO](https://www.fujitv.co.jp/ippon/profstudio.html)をそのまま用いる場合，`名前を入力しないと生成できない点`と`背景の色の変化が小さくないとうまくいかない点`が壁として立ちはだかる．そもそもアートのために手軽に使いたかったわけであり，これらを解決するプログラムを自分で組むことにした．

:::note
直近では2024年2月3日（土）にIPPONグランプリが放送されます．
:::

# 作成例
下記画像を入力として
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3191770/40f666cc-1642-bf76-d82b-00e47afd3159.jpeg" width=50%>
左が本家サイト，右が今回のプログラムによる出力結果．
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3191770/127dacdd-4432-da80-90cd-23177aafb149.png" width=50%><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3191770/ca33bd04-7007-7e94-d86b-3b7773bc6370.png" width=50%>
ご覧の通り本家サイトでやろうとすると名前が必要で，背景もそのまま使われてしまうためできるだけ1色の壁などを背景にして撮った写真を用いる必要が出てくる．

# 前提
- 言語はPython
- 想定環境は誰でも試せるようにGoogle Colaboratory（今回のソースコードをまとめたものが[私のGitHub](https://github.com/Kenshiro-Tanaka/IPPON_PROFILE_GENERATOR)に`.ipynb`にして置いてある）

# 今回やること
- 画像から背景を分離する
- 階調を減らす
- 黒以外の部分を黄色に変える

# 画像から背景を分離する

:::note
Google Colaboratoryを使っているので事前に画像をアップロードすることを忘れずに．ファイル名は`input.jpg`にしておくと変更しないで済むのでスムーズ．
:::

画像から背景を削除できるRembgというライブラリがあるらしい．試してみると精度がすごすぎる．インストールする．
```python
pip install rembg
```
その後
```python
# 背景変更パート
from PIL import Image
from rembg import remove

img = Image.open('input.jpg') # 画像読み込み
bgless_img = remove(img) # 背景を削除

# このif文で透過部分を指定色(白)に置換
if bgless_img.mode in ('RGBA', 'LA'):
    background = Image.new(bgless_img.mode[:-1], bgless_img.size, '#FFFFFF')
    background.paste(bgless_img, bgless_img.split()[-1])
    bgless_img = background

bgless_img.save('output.png') # 背景を削除して白くしただけの画像を一旦保存
```

# 階調を減らす
本家プロフィール画像を見てもらうと分かるが，あえて粗くしたいので階調を減らす．調べ方がわからなくて時間がかかったが`ポスタリゼーション`で検索するとうまく引っかかった．
```python
# 256階調から3階調にするパート
import numpy as np

img = np.array(Image.open('output.png').convert('L')) # 画像の読み込み

#量子化レベルを (1/q)　とする
q = 3 # 階調数

h, w = img.shape[:2] #　画像サイズを取得

#全画素を走査し,量子化レベルを変換
for x in range(h):
    for y in range(w):
        for l in range(q):
            t1 = l*((255)/q);
            t2 = (l+1)*((255)/q);

            # ポスタリゼーション処理
            if t1 <= img[x,y] and img[x,y] < t2:
                img[x,y] = (t1+t2)/2
                break

Image.fromarray(img).save('3kaicho.png') # 3階調にした画像を一旦保存
```

# 黒以外の部分を黄色に変える
その画素が変えたい色だったら変えるというのを繰り返すだけ．

```python
# 黒以外を黄色にするパート
import cv2

img = cv2.imread('3kaicho.png') # 画像の読み込み

# 変えたい色
target_color1 = (212, 212, 212)
target_color2 = (255, 255, 255) # 背景は白にしたので
target_color3 = (127, 127, 127)

# 変更後の色
change_color1 = (212, 212, 0)
change_color2 = (238, 238, 0) # カラーピッカーで背景色はこれにした
change_color3 = (238, 206, 0)

# 色の変更
# 画像サイズh，wの取得は前のパートでやっている
for i in range(h):
    for j in range(w):
        b, g, r = img[i, j]
        if (b, g, r) == target_color1:
            img[i, j] = change_color2
        elif (b, g, r) == target_color2:
            img[i, j] = change_color2
        elif (b, g, r) == target_color3:
            img[i, j] = change_color3
        else:
            img[i, j] = (0, 0, 0) # 髪とか目を想定

Image.fromarray(img).save('result.png') # 最終結果画像の保存


# colabでやっていて，いちいち保存した画像を確認するのが面倒な人へ
# from matplotlib import pylab as plt
# plt.imshow(img)
# plt.show()
```

# 気になる点
各パートでいちいち保存して改めて読み込んでいたり，読み込みの仕方が違うところが突貫工事すぎて気になっている．また本家プロフィール画像らしくするには名前の部分を載せる必要があるが，そもそもアートのためだったので追加する予定はなし．就活が無事終わったら次のIPPONグランプリまでに実装しようかな．

# 参考文献
この記事は以下の情報を参考にして執筆しました．
- [IPPON PROFILE STUDIO](https://www.fujitv.co.jp/ippon/profstudio.html)
- [Rembgを使って画像から背景を削除してみた](https://dev.classmethod.jp/articles/python-rembg/)
- [1-5「ポスタリゼーション」](https://genetaka.hatenablog.com/entry/2019/11/09/152859)
- [【opencv】画像の特定の色を別の色に変更する方法](https://tanalib.com/opencv-change-color/)