ソースに絡まるエスカルゴ

貧弱プログラマの外部記憶装置です。

【python/OpenCV】画像の特定の色を抽出する方法

 今回はpythonOpenCVを使って画像の特定の色を抽出する方法の備忘録です。
 OpenCVでは2つの方法で特定の色を抽出できるので、その2つの方法を説明していきます。

 では始めます。


1:RGBでの色抽出方法
 まず一つ目の方法としてRGBでの色の抽出方法があります。その方法は以下の記述でできます。

import cv2
import numpy as np

image = cv2.imread('./test1.png') # ファイル読み込み

# BGRでの色抽出
bgrLower = np.array([102, 255, 255])    # 抽出する色の下限(BGR)
bgrUpper = np.array([102, 255, 255])    # 抽出する色の上限(BGR)
img_mask = cv2.inRange(image, bgrLower, bgrUpper) # BGRからマスクを作成
result = cv2.bitwise_and(image, image, mask=img_mask) # 元画像とマスクを合成

 ※OpenCVでは「RGBではなくBGRになっている」ので色の順番には注意してください。

 抽出する色の上限下限を作成してinRange関数でマスクを取得します。そのマスクを元画像に適応するとこで、範囲内の色以外を黒くするという方法になっています。


2:HSVでの色抽出方法
 もう一つの方法としてHSVでの色の抽出方法があります。

 HSVとは「色相(Hue)・彩度(Saturation)・明度(Value)」で色を表したもので、以下のリンクからRGB・HSVの変換ができます。

 ちなみにOpenCVでのそれぞれの範囲は以下の通りとなっています。

名称 値の範囲 備考
色相(H) 0〜180 本来は0〜360だがOpenCVでは1/2の範囲になる
彩度(S) 0〜255 値が0に近づくほど白く、255に近づくほどHの色になる
明度(V) 0〜255 値が0に近づくほど黒く、255に近づくほどHの色になる

 そのHSVを使った色の抽出方法は以下の記述でできます。

import cv2
import numpy as np

image = cv2.imread('./test1.png') # ファイル読み込み

# HSVでの色抽出
hsvLower = np.array([30, 153, 255])    # 抽出する色の下限(HSV)
hsvUpper = np.array([30, 153, 255])    # 抽出する色の上限(HSV)
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # 画像をHSVに変換
hsv_mask = cv2.inRange(hsv, hsvLower, hsvUpper)    # HSVからマスクを作成
result = cv2.bitwise_and(image, image, mask=hsv_mask) # 元画像とマスクを合成

 1の手法と似ていますが、上限下限がHSVになっているのと一度画像をHSV形式に変換しているところが違っています。


3:実装例
 色抽出の方法がわかったので実際に以下の画像から背景色を抽出してみたいと思います。
f:id:rikoubou:20190221185338p:plain

 上記の画像を「test1.png」として保存し、同じ階層に以下のファイルを作成して実行します。

・colorExtraction.py

#
# 色抽出のサンプルコード
#
import numpy as np
import cv2
from time import sleep

# メイン関数
def main():
    image = cv2.imread('./test1.png') # ファイル読み込み

    # BGRでの色抽出
    bgrLower = np.array([102, 255, 255])    # 抽出する色の下限
    bgrUpper = np.array([102, 255, 255])    # 抽出する色の上限
    bgrResult = bgrExtraction(image, bgrLower, bgrUpper)
    cv2.imshow('BGR_test1', bgrResult)
    sleep(1)

    # HSVでの色抽出
    hsvLower = np.array([30, 153, 255])    # 抽出する色の下限
    hsvUpper = np.array([30, 153, 255])    # 抽出する色の上限
    hsvResult = hsvExtraction(image, hsvLower, hsvUpper)
    cv2.imshow('HSV_test1', hsvResult)
    sleep(1)

    while True:
        # キー入力を1ms待って、keyが「q」だったらbreak
        key = cv2.waitKey(1)&0xff
        if key == ord('q'):
            break

    cv2.destroyAllWindows()


# BGRで特定の色を抽出する関数
def bgrExtraction(image, bgrLower, bgrUpper):
    img_mask = cv2.inRange(image, bgrLower, bgrUpper) # BGRからマスクを作成
    result = cv2.bitwise_and(image, image, mask=img_mask) # 元画像とマスクを合成
    return result

# HSVで特定の色を抽出する関数
def hsvExtraction(image, hsvLower, hsvUpper):
    hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # 画像をHSVに変換
    hsv_mask = cv2.inRange(hsv, hsvLower, hsvUpper)    # HSVからマスクを作成
    result = cv2.bitwise_and(image, image, mask=hsv_mask) # 元画像とマスクを合成
    return result


if __name__ == '__main__':
    main()

 すると以下のようにどちらの方法でも背景色のみが抽出できます。
f:id:rikoubou:20190221185739p:plain


 以上がpythonOpenCVで特定の色を抽出する方法です。

 基本的に画像から色を抽出する時ははっきりとした色ではなくグラデーションがある場合が多いです。
 どちらか一方だけではなく、画像の内容や目的によってBGRの方法とHSVの方法を使い分ける必要が出てくるかと思います。


・参考資料