今回はOpencvでピクセルアートを作ってみました。 ようはドット絵に加工するやつです。

解説動画はこちら




さて今回はピクセルアート
平たく言うと画像をドット絵に加工するやつです。

さっそくコードを見ていきましょう。

import cv2
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

# 減色加工
def color_reduction(im, k):
    z = im.reshape(-1, 3).astype(np.float32)
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
    # K-means法で減色する
    ret, lab, cter = cv2.kmeans(z, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
    cter = np.uint8(cter)
    return cter[lab.flatten()].reshape(im.shape)

# モザイク加工
def mosaic(im, alpha):
    h, w, ch = im.shape
    res = cv2.resize(im,(int(w*alpha), int(h*alpha)))
    res = cv2.resize(res,(w, h), interpolation=cv2.INTER_NEAREST)
    return res

# ドット絵加工
def pixel_proc(im, alpha=0.5, k=8):
    return color_reduction(mosaic(im, alpha), k)

こんな感じの関数を用意しました。
モザイク処理で引き伸ばしを行ったのちに
減色処理を行って色を減らして
それっぽくします。
使う際はこんな感じで
# 入力画像
img = cv2.imread('画像のパス')

# ドット絵加工
k = 8
alpha = 0.3
dots = pixel_proc(img, alpha, k)

# 表示
plt.figure(figsize=(16,16))
plt.subplot(1,2,1)
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.axis("off")

plt.subplot(1,2,2)
plt.imshow(cv2.cvtColor(dots, cv2.COLOR_BGR2RGB))
plt.axis("off")
plt.show()
asuka

いい感じに加工されましたね。
alphaを減らすと画像が荒くなり
kを増やすと色合いが増えます。

maiyan
こんな感じで色合いとかを調整すれば
ピクセルアートっぽくなります。


コードの仕組みとしては
cv2.kmeans というのでk-means法を使って
画像の色をk個のグループに落とし込んでいます。

そうすることで減色加工ができている訳ですね。
im = cv2.imread('画像のパス')
z = im.reshape(-1, 3).astype(np.float32)
k = 4
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
ret, lab, cter = cv2.kmeans(z, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
lab = lab.squeeze(axis=1)
cter = cter.astype(np.uint8)
_, counts = np.unique(lab, axis=0, return_counts=True)
dots = cter[lab.flatten()].reshape(im.shape)

fig, [ax1, ax2 , ax3] = plt.subplots(1, 3, figsize=(16, 5))
fig.subplots_adjust(wspace=0.3)
colors = cter[:, ::-1] / 255
texts = list(map(str, cter))
ax1.imshow(cv2.cvtColor(im, cv2.COLOR_BGR2RGB))
ax1.set_axis_off()
ax2.imshow(cv2.cvtColor(dots, cv2.COLOR_BGR2RGB))
ax2.set_axis_off()
ax3.barh(np.arange(k), counts, color=colors, tick_label=texts)
plt.show()
2222

4色にした場合、背景に1色取られてしまい
残りの3色で人を表す感じになっちゃいます。
4色でもなかなか表現力は高いですね。

今回はopnecvを用いた
ピクセルアートの作り方でした。

それでは。