つれづれなる備忘録

日々の発見をあるがままに綴る

OpenCVの使い方32 ~ ヒストグラム逆投影法2

今回は前回紹介したヒストグラム逆投影法を用いた領域の切り出しの応用例について紹介する。

atatat.hatenablog.com

1. 輝度による切り出し

前回はHSVのうちH(色相), S(彩度)の2次元ヒストグラムを用いて領域切り出しを行ったが、今回はV(輝度)を使って領域を切り出す。

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')

以下のように読み込んだテキスト画像でテキストボードの上下にある明るい部分8か所を切り出す。

"テキスト画像"
テキスト画像

明るい部分8か所のうち1か所をヒストグラム計算用の領域として切り出す。

hsvt=cv2.cvtColor(orig, cv2.COLOR_BGR2HSV)
roi=src[208:212,5:40,:]
plt.imshow(roi)

"ヒストグラム計算用領域"
ヒストグラム計算用領域

輝度を用いるためcv2.calcHistではカラーチャネルは[2], ヒストグラムサイズは255、範囲は[0,256]として、cv2.calcBackProjectでも同様の設定とする。 以下前回と同じ流れで処理を実行する。

roi=orig[208:212,5:40,:]
hsv=cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
roihist=cv2.calcHist([hsv],[2],None,[255],[0,256])
cv2.normalize(roihist,roihist,0,255,cv2.NORM_MINMAX)
dst=cv2.calcBackProject([hsvt],[2],roihist,[0,256],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)

テキストボード上下の明るい部分の1か所のヒストグラムのみを用いて8か所を切り出せた。(ただし、他の高い輝度部分も若干切り出されている)

"輝度による逆投影"
輝度による逆投影

輝度による切り出しは、逆投影法を用いなくても閾値処理などでも十分に機能する。

2. 道路の領域切り出し

 前回は標準画像を用いたが、今回は一般的な画像として道路の領域切り出しを行う。自動運転などでは、画像から道路、歩道、建物などの領域識別はよく行われている。

"道路画像"
道路画像

まず道路の領域を一部切り出してヒストグラムを計算する。今回は色相、彩度を用いる。

hsvt=cv2.cvtColor(orig, cv2.COLOR_BGR2HSV)
roi=src[350:450,200:300,:]
plt.imshow(roi)

"道路領域"
道路領域

roi=orig[350:450,200:300,:]
hsv=cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
roihist=cv2.calcHist([hsv],[0,1],None,[180,255],[0,180,0,256])
cv2.normalize(roihist,roihist,0,255,cv2.NORM_MINMAX)
dst=cv2.calcBackProject([hsvt],[0,1],roihist,[0,180,0,256],1)
disc=cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
cv2.filter2D(dst,-1,disc,dst)

ret,thresh=cv2.threshold(dst,200,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)

"道路領域切り出し結果"
道路領域切り出し結果

切り出し時の閾値を下げると、くっきりと道路領域を切り出すことができる。(ただし、他の領域を切り出す可能性がある)

ret,thresh=cv2.threshold(dst,10,255,0)
thresh=cv2.merge((thresh,thresh,thresh))
res4=cv2.bitwise_and(src,thresh)

plt.figure(figsize=(12,20))
plt.subplot(1,2,1)
plt.imshow(res)
plt.subplot(1,2,2)
plt.imshow(res4)

左側が閾値200、右側が閾値10で右側の方がきれいに切り出せているが、左側で除外できている白線や道路以外の風景の一部も切り出されている。

"閾値による切り出し領域違い"
閾値による切り出し領域違い

3. まとめ

 今回は輝度を用いたヒストグラム逆投影法の例と、一般的な画像から道路領域を切り出す例を紹介した。