膨張差分法とキャニー法による線画の比較

アニメや漫画を線画にする際、白を膨張させてグレースケールとの差分を取る方法(以下、膨張差分法と呼ぶ)が多く用いられている。 しかし、実写に膨張差分法を適用したところ、実写の描写の細かさが影響してノイズが残りやすいことが分かった。 そこで膨張差分法とは別に、キャニー法という一般的なエッジ検出を適用して線画を生成し、両者の比較を行った。

処理コード

膨張差分法による線画生成をimage_2_linedraw_4_anime()、キャニー法による線画生成をimage_2_linedraw_4_photo()に実装。 前者は前述や参考文献でも述べられている通り、白を膨張させてグレースケールとの差分を取っている。 後者はブラーをかけたあとキャニー法を適用している。 main()を実行すると、画像ディレクトリーに入っているすべての画像に対して、2種類の手法で線画を生成する。

# coding: utf-8
import sys
import os
import random
import numpy as np
import cv2
import matplotlib
import numpy as np
import matplotlib.pyplot as plt


class Main:
    def __init__(self):
        self.blur_size = (7,7)
        self.dilate_size = (3,3)


    def main(self):
        image_dir = '../data/images/'
        image_names = [f for f in os.listdir(image_dir) if f[-4:].lower()=='.jpg' or f[-4:].lower()=='.png']
        image_names = [f for f in image_names if f.find('_linedraw.jpg')==-1]

        for image_name in image_names:
            self.image_2_linedraw_4_anime(image_dir, image_name)
            self.image_2_linedraw_4_photo(image_dir, image_name)


    def image_2_linedraw_4_anime(self, image_dir, image_name):
        img = cv2.imread(image_dir+image_name, cv2.IMREAD_GRAYSCALE) # Gray
        img_dilate = cv2.dilate(img, np.ones(self.dilate_size), iterations=1)  # Dilation
        img = cv2.absdiff(img_dilate, img)  # diff
        img = cv2.bitwise_not(img)  # Black and white inversion

        cv2.imwrite(image_dir+image_name.replace('.jpg', '_anime_linedraw.jpg'), img)  # Save


    def image_2_linedraw_4_photo(self, image_dir, image_name):
        img = cv2.imread(image_dir+image_name)
        img = cv2.GaussianBlur(img, self.blur_size, 0)  # Blur
        img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # BGR to Gray

        img = cv2.Canny(img, threshold1=90, threshold2=110)  # Canny method
        img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)  # Gray to BGR
        img = cv2.bitwise_not(img)  # Black and white inversion

        cv2.imwrite(image_dir+image_name.replace('.jpg', '_photo_linedraw.jpg'), img)


if __name__ == "__main__":
    Main().main()

膨張差分法とキャニー法による線画作成の比較

左から元画像、膨張差分法を用いたimage_2_linedraw_4_anime()の結果、キャニー法を用いたimage_2_linedraw_4_photo()の結果。 画像が小さいのでクリックして拡大して見てください。

アニメから線画を生成

膨張差分法の最初の4枚は素晴らしいほど、上手く線画になっている。 PaintsChainerが上手く機能するのも納得の訓練データ生成処理と言える。 最後だけ漫画と実写の共存だが、膨張差分法はTシャツの漫画が上手くできてて、キャニー法は女性の上半身が上手くできてる。 両者を融合すると良い感じになると思う。

f:id:Shoto:20180318035809j:plainf:id:Shoto:20180318035811j:plainf:id:Shoto:20180318035814j:plain
f:id:Shoto:20180318035820j:plainf:id:Shoto:20180318035825j:plainf:id:Shoto:20180318035830j:plain
f:id:Shoto:20180318035741j:plainf:id:Shoto:20180318035744j:plainf:id:Shoto:20180318035748j:plain
f:id:Shoto:20180318035757j:plainf:id:Shoto:20180318035801j:plainf:id:Shoto:20180318035804j:plain
f:id:Shoto:20180318035706j:plainf:id:Shoto:20180318035713j:plainf:id:Shoto:20180318035719j:plain

写真から線画を生成

やはり膨張差分法だと若干ノイズが大きい感じ。 かと言ってキャニー法がさらに良いかと言うと微妙だけど。 一応、最初の4枚は実写から線画の生成が個人的に上手くいったと思ったものを載せている。 ただ、最後だけは膨張差分法の方が良い感じだと思う。ノーマン・ロックウェルっぽささえある。 背景が白くて、対象物の足と靴がシンプルだからかも知れない。 というか、実写でも前処理でシンプルにすると、膨張差分法の方が上手くいくのかも。 この辺は暇ができたらリサーチしたい。

f:id:Shoto:20180318035631j:plainf:id:Shoto:20180318035635j:plainf:id:Shoto:20180318035640j:plain
f:id:Shoto:20180318035648j:plainf:id:Shoto:20180318035652j:plainf:id:Shoto:20180318035656j:plain
f:id:Shoto:20180318035839j:plainf:id:Shoto:20180318035842j:plainf:id:Shoto:20180318035846j:plain
f:id:Shoto:20180318035850j:plainf:id:Shoto:20180318035854j:plainf:id:Shoto:20180318035858j:plain
f:id:Shoto:20180318035905j:plainf:id:Shoto:20180318035909j:plainf:id:Shoto:20180318035914j:plain

まとめ

実写を線画にする際は、膨張差分法だとノイズが多くて、キャニー法だとノイズが少なすぎる傾向にある。 なので、その中間地点の線画が出せると良い感じになると思う。

参考文献