乙Py先生のプログラミング教室
初学者のためのプログラミング学習サイト

ドット絵

今回は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を用いた
ピクセルアートの作り方でした。

それでは。




在宅勤務他で暇なので
ドット絵クイズを作ってみました。

問題の動画はこちら



ドット絵を作る
ソースコードはこちら
import cv2
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image, ImageDraw
%matplotlib inline

def resize1(img):
    height, width = img.shape[:2]
    rate = 720 / height
    n_width = round(width * rate)
    size = (n_width,720)
    return cv2.resize(img, size)

def resize2(img):
    height, width = img.shape[:2]
    rate = 256 / height
    n_width = round(width * rate)
    size = (n_width,256)
    return cv2.resize(img, size)

def center_img(img):
    img2 = np.zeros((720, 1280, 3), np.uint8)
    height, width = img.shape[:2]
    img2[0:height, (1280-width)//2:(1280-width)//2+width] = img
    return img2

def sub_color(src, K):
    Z = src.reshape((-1, 3))
    Z = np.float32(Z)
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
    ret, label, center = cv2.kmeans(
        Z, K, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
    center = np.uint8(center)
    res = center[label.flatten()]
    return res.reshape((src.shape))

def anime_filter(img, K):
    gray = cv2.cvtColor(img, cv2.COLOR_BGRA2GRAY)
    edge = cv2.blur(gray, (3, 3))
    edge = cv2.Canny(edge, 50, 150, apertureSize=3)
    edge = cv2.cvtColor(edge, cv2.COLOR_GRAY2BGR)
    img = sub_color(img, K)
    return cv2.subtract(img, edge)

def mosaic(src, ratio=0.25):
    small = cv2.resize(src, None, fx=ratio, fy=ratio, interpolation=cv2.INTER_NEAREST)
    return cv2.resize(small, src.shape[:2][::-1], interpolation=cv2.INTER_NEAREST)

input_path = 'フォルダのパス'
file_name = 'ファイル名'
input_file_path = input_path + file_name

# ファイル読み込み
img = cv2.imread(input_file_path, cv2.IMREAD_COLOR)
# リサイズ
img = resize1(img)
# アニメ化
img = anime_filter(img, 16)
# モザイク処理(img,粒度)
img = mosaic(img,0.01)
# リサイズ2
img = resize2(img)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
fig, ax = plt.subplots(figsize=(16,9))
ax.imshow(img)
plt.show()



download

やっていることは
画像を取り込んで
リサイズ加工し
ドット絵加工しています。

モザイクの粒度を変えれば、
もう少し判別できる形になります。
小さくすればするほど荒く
大きくすると細かくなります。

ぜひ挑戦してみてください。
分かった秒数を
コメント欄に是非!!!

それでは

このページのトップヘ