目的
いきなりむさいおじさん画像で申し訳ありません。
「赤黄青緑の4色の木の玉を、それぞれ抽出できないか」、やってみました。
Python歴OpenCV歴ともに1ヶ月程度ですので、拙い点はぜひご指摘下さい(本当に)。
フィルタのコード
以下は、
- 指定した色相(
hue
)のピクセル(hTarget
)を明るくして - 該当しないピクセル(
hMask2
)をグレースケールにする
コードです。
filters.py
...
def hueMask(src, dst, hue, hueRange):
src = cv2.cvtColor(src, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(src)
hOrg = h.copy()
hTarget = h.copy()
cv2.threshold(hTarget, hue + hueRange, hue, cv2.THRESH_TOZERO_INV, hTarget)
# 「src(x,y)がthreshより大きければ、dst(x,y)は0」
# 0
# 0
# 0
# thresh
# src
# src
# src
# src
# src
cv2.threshold(hTarget, hue - hueRange, hue, cv2.THRESH_BINARY, hTarget)
# 「src(x,y)がthreshより小さければ、dst(x,y)は0」
# 0(src)
# 0(src)
# 0(src)
# src
# src
# thresh
# 0
# 0
# 0
# 結果
# 0
# 0
# 0
# thresh
# src
# thresh
# 0
# 0
# 0
# 蛍光灯の光(黄)や髪の毛(青)を除外するため、
# 極端に彩度の低いピクセルをターゲット範囲から除外する
sNotVeryLow = s.copy() # 極端に彩度が低くないところ
# 彩度が31より高いならターゲット範囲(255)に入れる。
# さもなくば非ターゲット範囲(0)。
cv2.threshold(sNotVeryLow, 31, 255, cv2.THRESH_BINARY, sNotVeryLow)
# hTargetとvNotHighlightの論理積が新しいhTarget
cv2.bitwise_and(hTarget, vNotVeryLow, hTarget)
# 明度画像のコピーをとる。
vBrightened = v.copy()
# それに+96のガンマ補正をかけ、明るくする
cv2.addWeighted(v, 0.625, v, 0.0, 96, vBrightened)
# 明度画像のターゲット範囲のみ、ガンマ補正済み明度画像を入れる
cv2.bitwise_and(vBrightened, 255, v, hTarget)
hMask2 = h.copy()
# hTarget(1チャンネル画像)の該当ピクセルが0のとき、
# hMask2(1チャンネル画像)の該当ピクセルを255にセットする。
# さもなくば、0にセットする。
# 要するにhMask2はhTargetマスク画像を反転させたもの。
cv2.compare(hTarget, 0, cv2.CMP_EQ, hMask2)
cv2.bitwise_and(s, 0, s, hMask2) # 論理積
cv2.merge((hOrg, s, v), src)
cv2.cvtColor(src, cv2.COLOR_HSV2BGR, dst)
...
なんだか変数の名前が汚いですが・・・これで任意の色相を抽出できるようになりました。
アプリケーションのコード
次に4色つまり赤黄青緑の色相を抽出するようにしてみます。
App.py
...
class App(object):
def __init__(self):
...
self._shouldHueMask = False
...
def run(self):
...
while self._windowManager.isWindowCreated:
...
if self._shouldHueMask:
filters.hueMask(frame, frame, self._hue, self._hueRange)
...
def onKeypress(self, keycode):
...
elif keycode == ord('B'): # 青
self._hue = 110
self._hueRange = 10
self._shouldHueMask = \
not self._shouldHueMask
elif keycode == ord('G'): # 緑
self._hue = 70
self._hueRange = 25
self._shouldHueMask = \
not self._shouldHueMask
elif keycode == ord('R'): # 赤
self._hue = 5
self._hueRange = 5
self._shouldHueMask = \
not self._shouldHueMask
elif keycode == ord('Y'): # 黄
self._hue = 30
self._hueRange = 15
self._shouldHueMask = \
not self._shouldHueMask
...
if __name__=="__main__":
App().run()
赤黄青緑それぞれの色相値と幅は、試行錯誤の末に決めました。
結果
赤
うーん、肌の色が「赤色抽出」に反応してしまっているようです。これでは木の玉「だけ」を抽出することはできません。
黄
うーん、今度は天井が「黄色抽出」に反応してしまっています。
青
今度は髪の毛と黒いセーターが「青色抽出」に反応してしまっています。
緑
いちばんきれいに木の玉を抽出することができました。
映像でも合成するときはグリーンバックといって緑色の布の前に立ちますよね。あれが緑色だったのには理由があるわけですね。
緑色が心に和む色なのも、普段の生活の中に出てくる色とは違い、目が新たな刺激を快いと感じるからなのかもしれません。
ひょっとしたら黒板が緑色なのも、それが理由かも?
・・・などと議論の余地を残して筆を置きます。
ブログやってます:Weed.nagoya