PythonとOpenCVを用いて画像をHSV色空間に変換し、赤・緑・青色の領域を色検出する方法をソースコード付きで解説します。
【はじめに】HSV色空間とは
HSV色空間とは、「色相(Hue)」「彩度(Saturation)」「明度(Value)」の3つの組み合わせで色を表現する手法です。
– | 説明 |
---|---|
色相(H) | 色合い。(赤っぽい、青っぽいといった色のおおまかな違いのことで、赤なら0度、黄色なら 60度といったように角度で色合いが決まります) |
彩度(S) | 色の鮮やかさ。(色相が同じ場合でも、彩度が高ければ鮮やかに見え、低ければグレーに見える。彩度がゼロの場合は無彩色[黒、グレー、白]) |
明度(V) | 色の明るさ。(高いほど明るい色になる) |
HSV色空間は人間が色を知覚する方法と類似しているため、RGB色空間よりも人がイメージした通りの色を作りやすいという特徴があります。
この特徴から、画像処理でも色検出をおこなう場合などにHSV色空間が利用されています。
本ページでは、画像をHSV色空間に変換し、赤・緑・青色の領域を色検出する方法を紹介します。
– | HSV色空間の詳細については下記事を参照 |
---|---|
1 | 【Python/OpenCV】RGBからHSVに変換(cv2.cvtColor) |
2 | 【画像処理】HSV色空間の原理・特徴・計算式 |
動画解説
本ページの内容は動画でも解説しています。
【Python版OpenCV】赤、緑、青色の物体を検出
HSV色空間における、赤色、緑色、青色のHue値のおおよその範囲は以下のとおりです。
– | 値の範囲 | 値の範囲(OpenCVの場合) |
---|---|---|
赤色のHue | 0~60, 300~360[度] | 0~30, 150~179 |
緑色のHue | 60~189[度] | 30~90 |
青色のHue | 180~300[度] | 90~150 |
SとVは対象に応じて適宜調整しますが、今回は以下の値域で赤、緑、青を検出します、
— | 値の範囲 | 値の範囲(OpenCVの場合) |
---|---|---|
S | 25~100[%] | 64~255 |
V | 00~100[%] | 0~255 |
Sは彩度(色の鮮やかさ)を示す値・・・下限をさげるほど薄い色も検出します。
Sは明るさを示す値
OpenCVのcv2.inRangeメソッドを使うことで、指定したH、S、V値の範囲でマスクを取ることができます。
#-*- coding:utf-8 -*- import cv2 import numpy as np # 赤色の検出 def detect_red_color(img): # HSV色空間に変換 hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 赤色のHSVの値域1 hsv_min = np.array([0,64,0]) hsv_max = np.array([30,255,255]) mask1 = cv2.inRange(hsv, hsv_min, hsv_max) # 赤色のHSVの値域2 hsv_min = np.array([150,64,0]) hsv_max = np.array([179,255,255]) mask2 = cv2.inRange(hsv, hsv_min, hsv_max) # 赤色領域のマスク(255:赤色、0:赤色以外) mask = mask1 + mask2 # マスキング処理 masked_img = cv2.bitwise_and(img, img, mask=mask) return mask, masked_img # 緑色の検出 def detect_green_color(img): # HSV色空間に変換 hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 緑色のHSVの値域1 hsv_min = np.array([30, 64, 0]) hsv_max = np.array([90,255,255]) # 緑色領域のマスク(255:赤色、0:赤色以外) mask = cv2.inRange(hsv, hsv_min, hsv_max) # マスキング処理 masked_img = cv2.bitwise_and(img, img, mask=mask) return mask, masked_img # 青色の検出 def detect_blue_color(img): # HSV色空間に変換 hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 青色のHSVの値域1 hsv_min = np.array([90, 64, 0]) hsv_max = np.array([150,255,255]) # 青色領域のマスク(255:赤色、0:赤色以外) mask = cv2.inRange(hsv, hsv_min, hsv_max) # マスキング処理 masked_img = cv2.bitwise_and(img, img, mask=mask) return mask, masked_img # 入力画像の読み込み img = cv2.imread("C:\prog\python\\test\input.png") # 色検出(赤、緑、青) red_mask, red_masked_img = detect_red_color(img) green_mask, green_masked_img = detect_green_color(img) blue_mask, blue_masked_img = detect_blue_color(img) # 結果を出力 cv2.imwrite("C:\prog\python\\test\\red_mask.png", red_mask) cv2.imwrite("C:\prog\python\\test\\red_masked_img.png", red_masked_img) cv2.imwrite("C:\prog\python\\test\green_mask.png", green_mask) cv2.imwrite("C:\prog\python\\test\green_masked_img.png", green_masked_img) cv2.imwrite("C:\prog\python\\test\\blue_mask.png", blue_mask) cv2.imwrite("C:\prog\python\\test\\blue_masked_img.png", blue_masked_img)
実行結果
サンプルプログラムの実行結果です。
■入力画像(input.png)
■赤色の検出結果
左がマスク画像(red_mask.png)、右がマスキング処理した画像(red_masked_img.png)
■緑色の検出結果
左がマスク画像(green_mask.png)、右がマスキング処理した画像(green_masked_img.png)
■青色の検出結果
左がマスク画像(blue_mask.png)、右がマスキング処理した画像(blue_masked_img.png)
お借りした画像:プロ生ちゃん(暮井 慧)
【補足】S、Vの値の調整、応用例など
S、Vの値の調整
対象とする色以外も抽出してしまった場合は、SやVの値を調整することで改善できます。
例えば、先程の赤色検出の例だと赤色の髪飾り以外にも、茶髪や顔の輪郭も検出してしまっています。SSは彩度(色の鮮やかさ)を示す値で、下限をさげるほど薄い色も検出してしまうため、茶色も検出してしまいます。
また、Sは明るさを示す値で、これも下限を下げるほど黒っぽい色も検出しやすくなります。
よって、これらの下限を次のように引き上げてみます。
# 赤色のHSVの値域1 hsv_min = np.array([0,200,50]) hsv_max = np.array([30,255,255]) mask1 = cv2.inRange(hsv, hsv_min, hsv_max) # 赤色のHSVの値域2 hsv_min = np.array([150, 200, 50]) hsv_max = np.array([179,255,255]) mask2 = cv2.inRange(hsv, hsv_min, hsv_max)
すると、赤色の髪飾りを検出し、その他の部分はカットできます。
このように、対象物の色の濃さ等も考慮して適宜SやVの値を調整することで、色検出の精度を改善できます。
■赤色の検出結果
左がマスク画像(red_mask.png)、右がマスキング処理した画像(red_masked_img.png)
応用例
よくある色検出の応用例として、カメラで物体の動きを追跡したいときに、
追跡対象に色を塗る、もしくはマーカーを塗ってそれを色検出するというものがあります。
これを使えば、振り子の運動をカメラで計測したりできます。
詳細は下記事で紹介していますので、興味のある方はご参照ください。
– | 関連記事 |
---|---|
1 | 【Python/OpenCV】カラートラッキング(色追跡)で移動物体の検出 |
2 | 【Python/OpenCV】Webカメラで振り子の運動を観測 |
3 | PythonでOpenCV入門 サンプル集 |
コメント