今回はopencvを使って画像から人を抜き出して
背景を切りとってみました。
解説動画はこちら
今回は簡易なセグメンテーションです。
画像の人の領域を特定して
背景と切り分けてみましょう。
まずはライブラリの読み込みです。
# 描画用のメソッド import numpy as np import cv2 import matplotlib.pyplot as plt %matplotlib inline def img_display(img): fig = plt.figure(figsize=(10,8)) ax = fig.add_subplot(111) ax.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) ax.axis('off') def img_display2(img,cmap=None): fig = plt.figure(figsize=(10,8)) ax = fig.add_subplot(111) ax.imshow(img, cmap=cmap) ax.axis('off') def img_display3(imgs,texts): fig = plt.figure(figsize=(16,10)) for i , img in enumerate(imgs): tmp = fig.add_subplot(1, len(imgs), i+1) tmp.set_title(texts[i],fontsize=15) plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) plt.axis('off') plt.show()
次に人の画像を用意しましょう。
img = cv2.imread('kuro/kuro2.jpg') img_display(img)

今回はこちらの方を用意しました。
さてこの画像に対して
処理を行っていきましょう。
最初は画像にブラー(ぼかし)をかけてみます。
img_blur1 = cv2.medianBlur(img , 5) img_blur2 = cv2.medianBlur(img , 15) img_blur3 = cv2.medianBlur(img , 25) img_blur4 = cv2.medianBlur(img , 35) img_blur5 = cv2.medianBlur(img , 45) texts = ['Blur_5','Blur_15','Blur_25','Blur_35','Blur_45'] img_display3([img_blur1,img_blur2,img_blur3,img_blur4,img_blur5] , texts)

こんな感じでぼかされていきますね。
ぼかすと背景と物や人の領域が
やや滑らかに分かれる感じです。
次にグレースケールに加工します。
gray_img1 = cv2.cvtColor(img_blur1,cv2.COLOR_BGR2GRAY) gray_img2 = cv2.cvtColor(img_blur2,cv2.COLOR_BGR2GRAY) gray_img3 = cv2.cvtColor(img_blur3,cv2.COLOR_BGR2GRAY) gray_img4 = cv2.cvtColor(img_blur4,cv2.COLOR_BGR2GRAY) gray_img5 = cv2.cvtColor(img_blur5,cv2.COLOR_BGR2GRAY) texts = ['gray_img1','gray_img2','gray_img3','gray_img4','gray_img5'] img_display3([gray_img1,gray_img2,gray_img3,gray_img4,gray_img5] , texts)

カラー画像を白黒にすると
白黒の濃淡は0-255の数値で表せるので
閾値を決めて領域を分けることができます。
次は閾値を決めて
人のシルエットを作ってみましょう。
mid = 204 ret, img_thresh1 = cv2.threshold(gray_img1,mid,255,cv2.THRESH_BINARY_INV) ret, img_thresh2 = cv2.threshold(gray_img2,mid,255,cv2.THRESH_BINARY_INV) ret, img_thresh3 = cv2.threshold(gray_img3,mid,255,cv2.THRESH_BINARY_INV) ret, img_thresh4 = cv2.threshold(gray_img4,mid,255,cv2.THRESH_BINARY_INV) ret, img_thresh5 = cv2.threshold(gray_img5,mid,255,cv2.THRESH_BINARY_INV) texts = ['img_thresh1','img_thresh2','img_thresh3','img_thresh4','img_thresh5'] img_display3([img_thresh1,img_thresh2,img_thresh3,img_thresh4,img_thresh5] , texts)

うまくいくかは閾値次第ですが
今回は背景と人がくっきり分かれました。
このシルエットを使って
元の画像を切り取ってみましょう。
シルエット部分だけ抽出して背景を抜く
# ノイズ取り kernel = np.ones((3,3),np.uint8) mor_img = cv2.morphologyEx(img_thresh3,cv2.MORPH_OPEN,kernel,iterations = 2) # マスク mask_img = cv2.dilate(mor_img,kernel,iterations=2) mask_rgb = cv2.cvtColor(mask_img, cv2.COLOR_GRAY2RGB) # マスクの切り抜き result_img = cv2.bitwise_and(img, mask_rgb) img_display(result_img)

こんな感じで人と背景を分けて
人だけ抽出ができました。
まとめです。
背景を削除して物や人の画像を抽出できますが
背景が複雑だとうまくいかないです。
なにせ雑に簡単な方法なので
より精密にセグメンテーションするには
opencvでは限界がありますね。
精細に行うなら
機械学習などで学習させた
領域切り分けを使わないと
上手くいかないでしょうね。
今回はopnecvを使った
簡単な画像のセグメンテーションでした。
今回はここまでです。
それでは。なにせ雑に簡単な方法なので
より精密にセグメンテーションするには
opencvでは限界がありますね。
精細に行うなら
機械学習などで学習させた
領域切り分けを使わないと
上手くいかないでしょうね。
今回はopnecvを使った
簡単な画像のセグメンテーションでした。
今回はここまでです。
コメントする