LoginSignup
6
6

More than 3 years have passed since last update.

いらすとやの画像をドット絵にしたった。(part2)

Last updated at Posted at 2020-02-03

Background

直接的なドット絵の改善についてではないですが、いらすとやの画像をドット絵にしたった。(part1)で周辺の画像がドットに変換しきれなかったので解決方法について説明します。

neko16.png

Method

方法としては、元画像の幅高さサイズの2倍ある画像を用意します。イメージとしてはラップの上にサンドイッチを置くイメージです:hamburger:


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)

mono_wrap.png

見た目でわかりやすく、G=255α(透過度)=128にしています。

次にドット絵にしたい画像を真ん中に配置します。

    wrap[top:top + mat.shape[0], left:left + mat.shape[1]] = mat
    cv2.imwrite("wrap.png", wrap)

wrap.png

で、ドット絵に変換します。
output.png
周辺に灰色のラインが生成されていますが、ちょうど境界線上でラップ画像の配色と透明色の平均値が算出されたためだと思います。

あとはこの画像を元画像のサイズにトリミングします。

cv2.imwrite("trim.png",wrap[top:top + mat.shape[0], left:left + mat.shape[1]])

trim.png

縁の方に灰色のラインが残るかと思ったのですが期待通りに出力できました。もし表示される場合はラップ画像の配色を(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つの配色にする方法を考えてみるとです。

Reference

6
6
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6