MATHGRAM

主に数学とプログラミング、時々趣味について。

カラー画像から線画を作る[OpenCV & python]

最近, 初心者がchainerで線画着色してみた。わりとできた。 - Qiita をKerasで実装してサービス化してみようかと頑張ってたんですけど, ちんたらしてたらこの記事を書いてる製作者様本人がwebサービス化しちゃいました笑

正直60万の画像を一晩で20epochも回せるような環境はその辺の大学生には用意できないっす. アルゴリズムでどうにかなるようなもんではなかった… .一応学習は続けてみようと思うので, もし完成したら記事にさせていただきます.

とりあえず, このモデルを作るために溜まった知識をまとめておこうと思います.

線画抽出

このモデルのデータセットは, アニメやイラストから輪郭線を抽出する必要があります.

具体的にはこんなことをしたい.
画像は化物語の忍さん.

f:id:ket-30:20170122181601j:plain

写真でも試してますが, かなり微妙.
こちらはアザールさん.

f:id:ket-30:20170122181817j:plain

まぁ, 写真なら他の方法を考えた方がいいと思う.

輪郭抽出のアルゴリズム

  • 画像をグレースケールで読み込む.
    f:id:ket-30:20170122182409j:plain:w200:h200
  • 白い部分を膨張させる. (線を細くする.)
    f:id:ket-30:20170122182415j:plain:w200:h200
  • グレースケールと膨張画像の差をとる.
    f:id:ket-30:20170122182422j:plain:w200:h200
  • 白黒反転させる.
    f:id:ket-30:20170122182453j:plain:w200:h200

OpenCVによる実装

OpenCVのdilation(膨張処理)は, numpyのarrayでどの程度膨張させるか指定できます. 普通の膨張処理などでは4近傍とか8近傍が使われるのですが, 今回は輪郭線を強調したいので24近傍としています.

dilationについてはここを参照してください.
www.blog.umentu.work

import cv2
import numpy as np

def make_contour_image(path):
    neiborhood24 = np.array([[1, 1, 1, 1, 1],
                             [1, 1, 1, 1, 1],
                             [1, 1, 1, 1, 1],
                             [1, 1, 1, 1, 1],
                             [1, 1, 1, 1, 1]],
                             np.uint8)
    # グレースケールで画像を読み込む.
    gray = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
    cv2.imwrite("gray.jpg", gray)

    # 白い部分を膨張させる.
    dilated = cv2.dilate(gray, neiborhood24, iterations=1)
    cv2.imwrite("dilated.jpg", dilated)

    # 差をとる.
    diff = cv2.absdiff(dilated, gray)
    cv2.imwrite("diff.jpg", diff)

    # 白黒反転
    contour = 255 - diff
    cv2.imwrite("./output.jpg", contour)
    return contour

以上です.