【Google Colab】OpenCVで画像をイラスト変換


はじめに

インスタグラムをはじめ、SNSで写真をシェアする方も多いのではないでしょうか。
その際、アプリを使用して画像を加工することもあるかと思います。
明るさや色味の調整、肌をキレイに見せるためのレタッチ、写真をスケッチ風に加工するなど、様々な機能があります。

今回は、OpenCVを用いて簡単なスケッチ風の画像加工に挑戦してみました。

OpenCVで画像をイラスト変換

環境

環境はGoogle Colaboratoryを使用します。
Pythonのバージョンは以下です。

import platform
print("python " + platform.python_version())
# python 3.6.9

画像の表示

では、早速コードを書いていきましょう。
まずは、画像の表示に必要なライブラリのインポートと設定を行います。

import cv2
import matplotlib.pyplot as plt
import matplotlib

%matplotlib inline
matplotlib.rcParams['image.cmap'] = 'gray'

サンプルの画像も用意しておきましょう。
今回は、Pixabayのフリー画像を使用します。

それでは、用意したサンプル画像を表示してみましょう。

image = cv2.imread(input_file) # input_fileは画像のパス

plt.figure(figsize=[10,10])
plt.axis('off')
plt.imshow(image[:,:,::-1])

結論

それではOpenCVを使用して、この画像をスケッチ風に加工してみましょう。
コードは以下です。

def sketch(image):
    pencilSketch_img = pencilSketch(image)
    bilateral_img = cv2.bilateralFilter(image, 75, 100, 100)
    sketch_img = cv2.bitwise_and(bilateral_img, pencilSketch_img)
    return sketch_img

def pencilSketch(image):
    gray_img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    median_img = cv2.medianBlur(gray_img, 5)
    laplacian_img = cv2.Laplacian(median_img, cv2.CV_8U, ksize=5)
    _, thresh_img = cv2.threshold(laplacian_img, 100, 255, cv2.THRESH_BINARY_INV)
    pencilSketch_img = cv2.cvtColor(thresh_img, cv2.COLOR_GRAY2BGR)
    return pencilSketch_img

sketch = sketch(image)

plt.figure(figsize=[20,10])
plt.subplot(121);plt.imshow(image[:,:,::-1]);plt.axis('off')
plt.title("original image")
plt.subplot(122);plt.imshow(sketch[:,:,::-1]);plt.axis('off')
plt.title("sketch image")

スケッチ風に加工する処理は、sketch関数として定義しています。
sketch関数の処理の流れは以下になります。

  • 鉛筆画風の画像作成(pencilSketch関数)
  • 平滑化(cv2.bilateralFilter)
  • マスク処理(cv2.bitwise_and)

鉛筆で線を描き、そこに色を塗っていくという順番になります。

各処理の説明

以下、各処理について説明していきます。

鉛筆画風の画像作成(pencilSketch関数)

鉛筆画風に加工する処理は、pencilSketch関数として定義しています。
pencilSketch関数の処理の流れは以下になります。

  • グレースケール
  • 平滑化(medianBlur)
  • 画像の微分(Laplacian)
  • 二値化

画像を表示してみます。

image = cv2.imread(input_file) # 元画像の読み込み
pencilSketch_img = pencilSketch(image) # 鉛筆画風の画像

plt.figure(figsize=[20,10])
plt.subplot(121);plt.axis('off');plt.imshow(image[:,:,::-1])
plt.subplot(122);plt.axis('off');plt.imshow(pencilSketch_img[:,:,::-1])[

pencilSketch関数について、詳細はこちらを参照下さい。

平滑化(cv2.bilateralFilter)

平滑化(へいかつか)、あるいはスムージング処理とは、簡単に言うと画像をぼかすことです。
画像をぼかすということは、画素値の変化を滑らかにすることとも言えます。
ノイズやエッジは、画素値の急激な変化です。
平滑化により、ノイズやエッジを消したり、目立たなくすることができます。

平滑化にはいくつかの方法が存在し、bilateralFilterはそのうちの一つです。
bilateralとは「両方の」という意味ですが、このフィルタはエッジをうまく残すことができます。
平滑化フィルタは、エッジなどのピークも含めて画像をぼかしてしまいます。
bilateralフィルタを使用すれば、エッジを残しつつ画像をぼかすことが可能です。

平滑化についての詳細は、こちらを参照下さい。

bilateralFilterのコードは以下です。

bilateral_img = cv2.bilateralFilter(image, 75, 100, 100)

plt.figure(figsize=[20,10])
plt.subplot(121);plt.axis('off');plt.imshow(image[:,:,::-1])
plt.subplot(122);plt.axis('off');plt.imshow(bilateral_img[:,:,::-1])

画像がぼやけているのが確認できます。

cv2.bilateralFilterを使用して、画像を平滑化しました。
cv2.bilateralFilterの用法は以下です。

  • dst = cv2.bilateralFilter(src, d, sigmaColor, sigmaSpace[, dst[, borderType]] )
    • src:インプット画像
    • dst:アウトプット画像
    • d:着目する領域の直径。
    • sigmaColor:色空間に関するパラメーター。値が大きいほど、色空間的に離れた色同士が影響し合う。
    • sigmaSpace:座標空間に関するパラメーター。値が大きいほど、座標空間的に離れたピクセル同士が影響し合う。

マスク処理(cv2.bitwise_and)

それでは最後に、マスク処理を用いてカラー画像と鉛筆画風スケッチ画像を合成します。
マスク処理にはcv2.bitwise_andを使用します。
cv2.bitwise_andは、2つの画像のビット単位のAND処理を行う関数です。

マスク処理のコードは以下です。

merged_img = cv2.bitwise_and(bilateral_img, pencilSketch_img)

plt.figure(figsize=[20,10])
plt.subplot(121);plt.axis('off');plt.imshow(bilateral_img[:,:,::-1])
plt.subplot(122);plt.axis('off');plt.imshow(merged_img[:,:,::-1])

うまく鉛筆画風スケッチをカラー画像にのせることができました。

まとめ

いかがだったでしょうか。

今回は、OpenCVを使用してスケッチ風の画像加工に挑戦してみました。
処理のフローをおさらいしておきます。

  • 鉛筆画風の画像作成(pencilSketch関数)
  • 平滑化(cv2.bilateralFilter)
  • マスク処理(cv2.bitwise_and)

パラメーターを色々と変えて、画像を出力してみると面白いと思います。