python + opencv で肌色を検出して褐色にするだけ その3
おはこんばんちわ
褐色シリーズ(たぶん)最終回です。
前回、前々回とそれぞれ肌色を検出する方法を紹介してみました。
python + opencv で肌色を検出して褐色にするだけ - きよぽん=サンのブログ
python + opencv で肌色を検出して褐色にするだけ その2 - きよぽん=サンのブログ
今回は、前回の面による肌色検出を利用して、グラフカットを利用します。
グラフカットは前景領域(ここでは肌色領域)を抽出する手法です。
グラフカット
説明するより入出力を見てもらったほうが早い。
Interactive Foreground Extraction using GrabCut Algorithm — OpenCV 3.0.0-dev documentation から引用
左側の画像と青色の四角の線が入力、右側の画像が出力です。
グラフカットを使うと、割と綺麗に前景の物体領域が得られます。
提案手法
- 面を利用して肌色と思われる領域をとる(前回記事を参照
- 1で得られた領域を前景領域、それ以外の領域を背景領域としてマスク画像を作成
- グラフカットの適用
結果
前回、前々回と同じ画像を使わせていただきます。絵師さまに感謝
左が入力画像で、右が出力画像
マスクをかけた画像
眉と髪の間の肌色が検出漏れだが、かなり綺麗に切り取れるようになった。
まとめ
グラフカット先輩イケメン
ソースコード全体
gistに載せておく
ちょっと解説
def mask_from_contours(im_shape, fg_contours, bg_contours): mask = np.zeros(im_shape, np.uint8) mask.fill(cv2.GC_PR_BGD) for contour in fg_contours: cv2.drawContours(mask, [contour], 0, cv2.GC_FGD, -1) for contour in bg_contours: cv2.drawContours(mask, [contour], 0, cv2.GC_BGD, -1) return mask
画像サイズからマスクを作成し、すべての点を背景と思われる画素としてラべリング
肌色と思われる領域は前景としてラべリング
肌色と思われないと事は背景としてラべリング
グラフカットの際に利用されるマスク画像の各画素には、
の4パターンをラべリングできる。
# graph cut mask = mask_from_contours(image.shape[:2], skin_contours, bg_contours) bgd_model = np.zeros((1, 65), np.float64) fgd_model = np.zeros((1, 65), np.float64) mask, bgd_model, fgd_model = cv2.grabCut(image, mask, None, bgd_model, fgd_model, 5, cv2.GC_INIT_WITH_MASK) gc_mask = np.where((mask==2)|(mask==0), 0, 1).astype('uint8')
マスクを利用したグラフカットを適用し、結果のマスクを0,1に変換
+α
今回の記事では、面によって肌色と類似した領域を前景、
肌色とは類似していない領域を背景、どちらでもない場合は背景と思われる画素としています。
今回は面によって検出した領域だけの結果をメインに紹介しましたが、
点で検出した肌色領域、面で検出した肌色領域の2つからグラフカットのためのマスク画像を作成することで、
2つの検出手法の良いところを吸収できる可能性があります。
(短所も吸収するばあいもしかり)
パラメータをいじる根気があれば、おそらくコチラのほうが良い結果がでそう
コードはgistに載せておきます。
それではノシ