画像から塗り絵問題の生成(線画抽出)

塗り絵生成

  • 先日のお絵かきロジック生成の時にPILの使い方を覚えた。
  • その中で、画像処理って使うのも単純で、アルゴリズムも単純なものが多いなぁ、という感想をもった。
  • 例えば、2値化して、エッジ強調すれば塗り絵になるなぁ、すぐ出来そうだなぁ、みたいな。ということで調べたらすぐ出来た。画像処理は見た目がすぐわかるから面白いなぁ。
  • PILの中に、Filter.Find_Edgeというフィルタがあって、それでも一発で生成されるみたいだけど、膨張させて作るほうが綺麗な感じはある。
  • 特定の絵を与えて、膨張(dilation)の大きさを変えて塗り絵画像を生成できる。
  • 処理は敢えて各ステップをそのまま書いているのでわかると思うけれど、
    1. 画像をグレースケール化(convert('L'))
    2. その画像を膨張(MaxFilter)
    3. 膨張したものとグレースケール化したものの差分を取る(difference)。これでエッジ化される
    4. 白黒反転してるので反転(invert)
  • 膨張という処理だけでも結構面白そうで、よりアニメちっくな線画抽出だとこんな綺麗な例があるみたい。
import os
import argparse
from PIL import Image
from PIL import ImageOps
from PIL import ImageFilter
from PIL import ImageChops

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--img', action='store', type=str)
    parser.add_argument('--dilation', action='store', type=int, default=5)
    args = parser.parse_args()

    dir, fname = os.path.split(args.img)
    img_name, ext = os.path.splitext(fname)
    img_out_name = img_name + '_nurie' + ext

    print('File:{} is converted to {}'.format(fname, img_out_name))

    img_org = Image.open(args.img)
    img_gray = img_org.convert('L')  # Gray scale image
    img_gray_dilation = img_gray.filter(ImageFilter.MaxFilter(args.dilation))  # dilation
    img_diff = ImageChops.difference(img_gray, img_gray_dilation)  # diff(Edge image)
    img_diff_invert = ImageOps.invert(img_diff)

    img_diff_invert.show()
    img_diff_invert.save(img_out_name)

    # Memo: Below command generate similar image
    # ImageOps.invert(img_gray.filter(ImageFilter.FIND_EDGES))

サンプル

f:id:nobUnaga:20180329095748p:plain
元画像

f:id:nobUnaga:20180329095737p:plain
生成した塗り絵問題
f:id:nobUnaga:20180329095758p:plain
Filter.Find_Edgeでの生成