MENU

python 赤っぽいところを白色で表示する(HSV色空間)

 import cv2
 import numpy as np

 # Webカメラから入力を開始
 cap = cv2.VideoCapture(0)
 while True:
  # 画像を取得して縮小する
  _, frame = cap.read()
  frame = cv2.resize(frame, (500,300))
 # 色空間をHSVに変換 --- (*1)
  hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV_FULL)
 # HSVを分割する --- (*2)
  h = hsv[:, :, 0]
  s = hsv[:, :, 1]
  v = hsv[:, :, 2]
 # 赤色っぽい色を持つ画素だけを抽出 --- (*3)
  img = np.zeros(h.shape, dtype=np.uint8)
  img[*1 & (s > 100)] = 255
 # ウィンドウに画像を出力 --- (*4)
  cv2.imshow('RED Camera', img)
  if cv2.waitKey(1) == 13: break

cap.release() # カメラを解放
cv2.destroyAllWindows() # ウィンドウを破棄

実行結果(めちゃくちゃわかりにくくてごめんなさい)

f:id:hanamichi_sukusuku:20210106161712p:plain

 

実行結果は自分が目のところに眼鏡ケースを持っているライブ映像をスクショしたもの。

 

webカメラ起動

cap = cv2.VideoCapture(0)

 

while True:
# 画像を取得して縮小する
_, frame = cap.read()
frame = cv2.resize(frame, (500,300))
# 色空間をHSVに変換 --- (*1)
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV_FULL)
# HSVを分割する --- (*2)
h = hsv[:, :, 0]
s = hsv[:, :, 1]
v = hsv[:, :, 2]
# 赤色っぽい色を持つ画素だけを抽出 --- (*3)
img = np.zeros(h.shape, dtype=np.uint8)
img[*2 & (s > 100)] = 255
# ウィンドウに画像を出力 --- (*4)
cv2.imshow('RED Camera', img)
if cv2.waitKey(1) == 13: break

whileでワンフレームごとに出力している処理。

read()でワンフレーム取得。

resizeでサイズ変更。(大きな画像は必要ないから)

cv2.cvtColor()で色空間をHSVに変換。HSVは色相、彩度、明度の3つのパラメーターで色を表現する方式。RGB色空間は、赤緑青の原色による色の組み合わせで色を表現しているので色の変化がわかりにくいい。それに対してHSV色空間は彩度や明度を用いて色を表現するので、感覚的に色を指定できる。色相は360度の円形で右回りに赤、緑、青、赤のように色の円形で表現する。

f:id:hanamichi_sukusuku:20210106163258p:plainHSV色空間_Wikipedia参照

h = 色相

s = 彩度

v = 明度

 

h = hsv[:, :, 0]

この部分では全ピクセルの色相の値をhに格納している。画像データは[高さ, 幅, 色]

で表現されていて今回この配列の色の部分にはHSV色空間のデータが[色相,彩度,明度]のように格納されているのでインデックス番号0を指定することで色相のデータを取得している。

s = [:, :, 1]

v = [:, :, 2]

上記2つも同様。

 

赤色っぽい色を持つ画素だけを抽出

 img = np.zeros(h.shape, dtype=np.uint8)
img[*3 & (s > 100)] = 255

 

np.zeros()では引数に指定した値だけ0が格納された配列を作成するメソッドである。

h.shapeで色相のリストの要素数を取得している。dtypeはデータ型を指定しておりイメージしやすいのだとintやstr、unitは符号なしの整数[0 0 0]こーゆーやつ、[0. 0. 0.]これじゃないやつ。unit8の8は8ビットという意味で色を0~255で表現するものらしい。

 

img[*4 & (s > 100)] = 255は、imgのデータのうち「hが50未満」または「hが200より大きく、しかもsが100以上」のところを255にする、というもの。つまいhには要素数300の色相のデータが入っていてhの中身の要素が50未満、200より大きいかつsの中身のデータが100以上のものの位置(インデックス番号といった方がわかりやすいかも)とimgの中身の同じ位置を255にしているということ。色相の50~200は角度なので上の画像で確認すればなんとなく赤い部分を指定していることがわかる。

Numpyではブール演算子のandやorではなく|や&のビット演算子を使う。

imgの中身を確認すると0と255のみで配列が作成されているため白黒画像になる。

 

cv2.imshow()でウィンドウ表示して画像を表示。

cv2.waitKey()で繰り返し処理の中止。

 

release()でカメラ終了。

cv2.destoryAllWindow()でウィンドウ閉じる。

 

 

 

 

*1:h < 50) | (h > 200

*2:h < 50) | (h > 200

*3:h < 50) | (h > 200

*4:h <50 ) | (h > 200