【Python/OpenCV】赤・緑・青色の検出(HSV色空間)

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入門 サンプル集

コメント