今回はOpenCVでヒストグラム逆投影法を用いた領域の切り出し方法について紹介する。
1. 画像読み込み
今回は標準画像データベースのうちPepperを利用する。
import cv2 import numpy as np from matplotlib import pyplot as plt import cv2 import numpy as np from matplotlib import pyplot as plt orig = cv2.imread(uploaded_file_name) src = cv2.cvtColor(orig, cv2.COLOR_BGR2RGB) plt.imshow(src) plt.title('Original')
以下のように読み込んだ画像から緑の領域を切り出すことを考える。
画像全体orig
をもとのBGRからHSVに変換してhsvt
としておく。
中央の緑のペッパーのヒストグラムを用いて、画像全体の緑の領域を切り出す。
とりあえずX:125~170, Y:150~200の領域を切り出して表示させてみる。
hsvt=cv2.cvtColor(orig, cv2.COLOR_BGR2HSV) roi=src[150:200,125:170,:] plt.imshow(roi)
2. ヒストグラム計算
配列src
はカラーがBGRからRGBに変換されているので、もとのBGRからHSVに変換するため配列orig
を用いて上で確認した領域 X:125~170, Y:150~200を切り出してhsvに変換してからヒストグラムを計算する。ヒストグラムを計算するにはcv2.calcHist([hsv],[0,1],None,[180,255],[0,180,0,256])
を用いる。引数[hsv]
は入力配列、[0,1]
はヒストグラムを計算するカラーチャネルで色相Hと彩度Sを指定する。None
はマスクオプションなし、[180, 256]
はHとSのヒストグラムのサイズ(Bin数)、[0,180, 0, 256]
はヒストグラムの出力レンジで最小と最大を指定する。
roi=orig[150:200,125:170,:] hsv=cv2.cvtColor(roi, cv2.COLOR_BGR2HSV) roihist=cv2.calcHist([hsv],[0,1],None,[180,255],[0,180,0,256])
3. 逆投影計算
逆投影の前にヒストグラム計算の結果roihist
をcv2.normalize()
で0~255に正規化しておく。次に切り出しを行うPepperのHSV画像hsvt
と緑の領域の正規化したヒストグラムroihist
を用いて逆投影dst
をcv2.calcBackProject([hsvt],[0,1],roihist,[0,180,0,256],1)
によって計算する。引数[0, 1]
はカラーチャネルでcalcHist
に用いた[0, 1]
を指定、[0,189,0,256]
はヒストグラムのレンジで、カラーチャネルと同じくcalcHist
に用いた[0,189,0,256]
を指定する。最後の引数1
は逆投影の出力スケールでとりあえず1を指定する。逆投影の結果dst
を表示すると緑色の部分に強度があり、赤色の部分はほぼ0になっている。
cv2.normalize(roihist,roihist,0,255,cv2.NORM_MINMAX) dst=cv2.calcBackProject([hsvt],[0,1],roihist,[0,180,0,256],1) plt.imshow(dst,cmap='gray',vmin=0,vmax=255) plt.colorbar()
4. 領域の切り出し
逆投影の結果dst
を元にしたマスクを作成することで、最終的にPepper画像から緑の領域を切り出す。下処理として円形領域を用いてフィルタをかけて少し滑らかに領域が選択できるようにする。次にcv2.threshold(dst,150,255,0)
で強度150を閾値としたバイナリマスクを作成し、cv2.merge((thresh,thresh,thresh))
として3色分のバイナリマスクになるようにする。最後にcv2.bitwise_and(src,thresh)
としてRGBのPepper画像であるsrc
にバイナリマスクthresh
を適用して、緑の領域を切り出した画像res
を生成する。
元の画像src
,バイナリマスクthresh
, 緑の領域を切り出したres
, をnp.hstack()
で1つの配列(画像)にまとめて表示して比較できるようにした。
disc=cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(2,2)) cv2.filter2D(dst,-1,disc,dst) ret,thresh=cv2.threshold(dst,150,255,0) thresh=cv2.merge((thresh,thresh,thresh)) res=cv2.bitwise_and(src,thresh) res3=np.hstack((src,thresh,res)) plt.figure(figsize=(15,8)) plt.imshow(res3)res=np.hstack((src,thresh,res)) plt.figure(figsize=(15,8)) plt.imshow(res)
虫食いにようになっているところは、HSVヒストグラムがroihist
と部分的にずれているためだが、より滑らかにするにはフィルタ処理やerosion, dilationで虫食いの領域をつぶすなどが考えられる。
5. まとめ
今回はヒストグラム逆投影を用いた領域の切り出し処理について紹介した。