Background
直接的なドット絵の改善についてではないですが、いらすとやの画像をドット絵にしたった。(part1)で周辺の画像がドットに変換しきれなかったので解決方法について説明します。
Method
方法としては、元画像の幅高さサイズの2倍ある画像を用意します。イメージとしてはラップの上にサンドイッチを置くイメージです
def wrapMat(height, width):
dst = np.zeros((height, width, 4), np.uint8)
dst[:] = tuple((0,255,0,128))
return dst
if __name__ == "__main__":
#元画像
mat = cv2.imread(path,cv2.IMREAD_UNCHANGED)
#幅高さを二つ折りにする
top = int(mat.shape[0] * 0.5)
left = int(mat.shape[1] * 0.5)
wrap = wrapMat(top*4,left*4)
cv2.imwrite("mono_wrap.png", wrap)
見た目でわかりやすく、G=255
、α(透過度)=128
にしています。
次にドット絵にしたい画像を真ん中に配置します。
wrap[top:top + mat.shape[0], left:left + mat.shape[1]] = mat
cv2.imwrite("wrap.png", wrap)
で、ドット絵に変換します。
周辺に灰色のラインが生成されていますが、ちょうど境界線上でラップ画像の配色と透明色の平均値が算出されたためだと思います。
あとはこの画像を元画像のサイズにトリミングします。
cv2.imwrite("trim.png",wrap[top:top + mat.shape[0], left:left + mat.shape[1]])
縁の方に灰色のラインが残るかと思ったのですが期待通りに出力できました。もし表示される場合はラップ画像の配色を(R,G,B,A)=(0,0,0,0)
にすれば問題ないです。
Development
全体のコードです。
import cv2
import numpy as np
import sys
def wrapMat(height, width):
dst = np.zeros((height, width, 4), np.uint8)
dst[:] = tuple((0, 255, 0, 128))
return dst
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]
def main():
CELL_SIZE = 16
path = sys.argv[1]
mat = cv2.imread(path, cv2.IMREAD_UNCHANGED)
top = int(mat.shape[0] * 0.5)
left = int(mat.shape[1] * 0.5)
# ラップ画像作成
wrap = wrapMat(top * 4, left * 4)
# 元画像を配置
wrap[top:top + mat.shape[0], left:left + mat.shape[1]] = mat
# ドット絵作成
height, width = wrap.shape[:-1]
for w in range(width // CELL_SIZE - 1):
for h in range(height // CELL_SIZE - 1):
c = np.mean(
np.mean(
wrap[h * CELL_SIZE:(h + 1) * CELL_SIZE,
w * CELL_SIZE:(w + 1) * CELL_SIZE], axis=0
),
axis=0
)
wrap[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]])
# トリミング
trim = wrap[top:top + mat.shape[0], left:left + mat.shape[1]]
cv2.imwrite("trim.png", trim)
if __name__ == "__main__":
main()
Future
次回はモノクロ画像を4つの配色にする方法を考えてみるとです。