Motive
ご存知の通りいらすとやは今トレンドのフリー素材をリリースし続けています。ふとこれらの画像をドット絵にしたらどうなるかが気になったので作成してみました。
Method
魔法使いの森に書いていたのですがファミコンの表示配色は52くらいだと言われています。(確定的でない。)
ここでは、ファミコンに似せるためにR,G,Bそれぞれの配色を4分割に減色して表示してみようと思います。
それぞれの範囲は0 ~ 255
ですが単純に分割すると、[0, 85, 170, 255]
となります。
全ての色の組み合わせは64
パターンあるのですが実際に画像として出力すると下記の表示になります。
import cv2
import numpy as np
if __name__ == "__main__":
height = 576
width = 1024
range_color = [0, 85, 170, 255]
mono = np.zeros((height, width, 3), np.uint8)
mono[:] = tuple((0,0,0))
for r in range(4):
for g in range(4):
for b in range(4):
mono[144*b:144*(b+1), 64*(r+g*4):64*(r+(g*4+1))] = tuple((85*b,85*g,85*r))
cv2.imwrite("out.png", mono)
余談ですが、パッと見灰色がない、と思ったのですが2行6列(85,85,85)
、3行11列(170,170,170)
にそれぞれ表示されています。
それで、どのようにもとの色データの数字によって判定するかですが、 一つの例として 110
の値を振り分けたい場合、85 ~ 170
がどちらが近いかを判定します。ここでは85
が一番近いので110 -> 85
に変換して、全ての画素にこのアルゴリズムを適合させます。
Develop
import cv2
import numpy as np
import sys
def resize(src):
h,w = mat.shape[:-1]
height = (h // 16) * 16
width = (w // 16)* 16
return cv2.resize(mat,(width,height))
def convertReduceColor(src):
thresholds = [42,127,212]
range_color = [0, 85, 170, 255]
count = 0
for th in thresholds:
if src <= th:
break
count += 1
return range_color[count]
if __name__ == "__main__":
__CELL_SIZE__ = 4
path = sys.argv[1]
mat = cv2.imread(path,cv2.IMREAD_UNCHANGED)
mat = resize(mat)
height, width = mat.shape[:-1]
for w in range(width//__CELL_SIZE__-1):
for h in range(height//__CELL_SIZE__-1):
c = np.mean(
np.mean(
mat[h*__CELL_SIZE__:(h+1)*__CELL_SIZE__,
w*__CELL_SIZE__:(w+1)*__CELL_SIZE__], axis=0
),
axis=0
)
mat[
h*__CELL_SIZE__:(h+1)*__CELL_SIZE__,
w*__CELL_SIZE__:(w+1)*__CELL_SIZE__
] = tuple([convertReduceColor(c[0]), convertReduceColor(c[1]), convertReduceColor(c[2]), c[3]])
cv2.imwrite("output.png",mat)
np.mean(np.mean(mat[h*__CELL_SIZE__:(h+1)*__CELL_SIZE__, w*__CELL_SIZE__:(w+1)*__CELL_SIZE__], axis=0),axis=0)
ここでセルの大きさから画素の平均値を取得しています。
また、convertReduceColor
でRGBそれぞれに対して近似判定しています。
Result
ソース画像 | 画素の大きさ | 処理後 |
---|---|---|
4 | ||
8 | ||
16 | ||
4 | ||
8 | ||
16 | ||
4 | ||
8 | ||
16 |
- 一番成功したのはセルの大きさを16にした猫の画像です。右端は処理できていないですが全体的にそれっぽいドット絵になっていると思います。右端もドット調にするときはリサイズ処理を再考しないとダメっぽいです。
- ドット絵に変換するときは一枚のイラストの中に人物・物体が一つの方が処理が成功しやすいです。
- 基本的にいらすとやの画像ですが凸凹なフェルト調で区画を塗り潰しているのが特徴です。そのためあるオブジェクトに一色で塗り潰されておらずノイズが入っているように見えます。
- セルの大きさを4にしたペンギンの画像の目が(´・ω・`)としている。いらすとやのキャラクターは基本的に目が点になっていて小さいのでセルの大きさを高くすると消えてしまうため注意が必要です。
Future
- ノイズが気になるので変則的な二値化とモルフォロジー変換でなんとかなりそう
- 実際のファミコン色ですが今回使った配色と異なるので、使う50くらいの配色を固定値で埋め込んで近傍探索でマッチングさせた方が良さそうです