きっかけ
2023年6月,北海道立近代美術館の特別展トリック×イリュージョン!を訪れた際にある作品を見て,作りたいアートのイメージが急に湧いてきた.それはソースコードの文字列で人の顔を表現するもので,すぐにその場で作成可能か調べてみた.画像から人物だけを切り抜き,2値化して黒い部分だけに上からソースコードを貼り付けてみようかと思っていると,IPPONグランプリの公式サイトでそれっぽいものができることを発見した.しかし,このIPPON PROFILE STUDIOをそのまま用いる場合,名前を入力しないと生成できない点
と背景の色の変化が小さくないとうまくいかない点
が壁として立ちはだかる.そもそもアートのために手軽に使いたかったわけであり,これらを解決するプログラムを自分で組むことにした.
直近では2024年2月3日(土)にIPPONグランプリが放送されます.
作成例
下記画像を入力として
左が本家サイト,右が今回のプログラムによる出力結果.
ご覧の通り本家サイトでやろうとすると名前が必要で,背景もそのまま使われてしまうためできるだけ1色の壁などを背景にして撮った写真を用いる必要が出てくる.
前提
- 言語はPython
- 想定環境は誰でも試せるようにGoogle Colaboratory(今回のソースコードをまとめたものが私のGitHubに
.ipynb
にして置いてある)
今回やること
- 画像から背景を分離する
- 階調を減らす
- 黒以外の部分を黄色に変える
画像から背景を分離する
Google Colaboratoryを使っているので事前に画像をアップロードすることを忘れずに.ファイル名はinput.jpg
にしておくと変更しないで済むのでスムーズ.
画像から背景を削除できるRembgというライブラリがあるらしい.試してみると精度がすごすぎる.インストールする.
pip install rembg
その後
# 背景変更パート
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') # 背景を削除して白くしただけの画像を一旦保存
階調を減らす
本家プロフィール画像を見てもらうと分かるが,あえて粗くしたいので階調を減らす.調べ方がわからなくて時間がかかったがポスタリゼーション
で検索するとうまく引っかかった.
# 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階調にした画像を一旦保存
黒以外の部分を黄色に変える
その画素が変えたい色だったら変えるというのを繰り返すだけ.
# 黒以外を黄色にするパート
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グランプリまでに実装しようかな.
参考文献
この記事は以下の情報を参考にして執筆しました.