画像処理では、画像から特定の色の部分だけを抽出したい場面があります。例えば、物体検知の前処理として特定の色のオブジェクトだけを残したり、不要な背景色を除去したりするケースです。
この記事では、色空間(RGB/HSV)を利用して画像から特定の色を抽出する方法を解説します。
目次
事前準備
色抽出がわかりやすいように、カラフルな画像を使用します。

import numpy as np
import cv2
# 画像の読込
img = cv2.imread('input/colorImage.jpg')
# 画像のサイズを小さくする(前処理)
height = img.shape[0]
width = img.shape[1]
resized_img = cv2.resize(img, (round(width / 4), round(height / 4)))RGBで抽出する
青色を抽出する
BGRの範囲を指定し、cv2.inRange()で2値化した後、cv2.bitwise_and()でマスク処理を行います。
# 青を抽出
bgr = [210, 150, 40]
thresh = 40
# 色の閾値
minBGR = np.array([bgr[0] - thresh, bgr[1] - thresh, bgr[2] - thresh])
maxBGR = np.array([bgr[0] + thresh, bgr[1] + thresh, bgr[2] + thresh])
# 画像の2値化
maskBGR = cv2.inRange(resized_img, minBGR, maxBGR)
# 画像のマスク(合成)
resultBGR = cv2.bitwise_and(resized_img, resized_img, mask=maskBGR)
cv2.imshow("Result BGR", resultBGR)
cv2.imshow("Result mask", maskBGR)
cv2.waitKey(0)
cv2.destroyAllWindows()処理の流れ:
- 抽出したい色の範囲を
minBGR〜maxBGRで定義する cv2.inRange()で、指定範囲内のピクセルを白(255)、範囲外を黒(0)に2値化するcv2.bitwise_and()で2値化マスクを使って元画像から該当部分のみを抽出する


赤色を抽出する
赤色の場合も同様の手順で抽出します。
# 赤を抽出
bgr = [-30, -30, 150]
thresh = 40
minBGR = np.array([bgr[0] - thresh, bgr[1] - thresh, bgr[2] - thresh])
maxBGR = np.array([bgr[0] + thresh, bgr[1] + thresh, bgr[2] + thresh])
maskBGR = cv2.inRange(resized_img, minBGR, maxBGR)
resultBGR = cv2.bitwise_and(resized_img, resized_img, mask=maskBGR)
cv2.imshow("Result BGR", resultBGR)
cv2.imshow("Result mask", maskBGR)
cv2.waitKey(0)
cv2.destroyAllWindows()

ポイント: BGRの値に負の値を指定していますが、これは赤とオレンジを明確に区別するためです。BGRの有効範囲は0〜255のため、負の値は無視されます。閾値の範囲(±40)を維持しつつ、0〜10付近の狭い範囲を指定するテクニックです。
HSVで抽出する
HSVで色を抽出するには、まず画像をHSV色空間に変換する必要があります。
import numpy as np
import cv2
img = cv2.imread('input/colorImage.jpg')
height = img.shape[0]
width = img.shape[1]
resized_img = cv2.resize(img, (round(width / 4), round(height / 4)))
# HSVに変換
resized_img_HSV = cv2.cvtColor(resized_img, cv2.COLOR_BGR2HSV)
OpenCVで色相(H)を扱う際の注意点
HSVの色相(H)は通常0〜360°で表現されますが、OpenCVでは0〜179の範囲で指定します。

青色を抽出する
# 青を抽出
hsv_min = np.array([100, 45, 70])
hsv_max = np.array([105, 255, 255])
# 画像の2値化
maskHSV = cv2.inRange(resized_img_HSV, hsv_min, hsv_max)
# 画像のマスク(合成)
resultHSV = cv2.bitwise_and(resized_img, resized_img, mask=maskHSV)
cv2.imshow("Result HSV", resultHSV)
cv2.imshow("Result mask", maskHSV)
cv2.waitKey(0)
cv2.destroyAllWindows()

赤色を抽出する
HSVで赤色を抽出する場合は注意が必要です。色相の値を見ると、赤色は0付近と179付近の2箇所に分かれています。そのため、2つの範囲のマスクを作成し、それらを統合する必要があります。
# 赤を抽出(色相が0付近)
low_hsv_min = np.array([0, 200, 50])
low_hsv_max = np.array([1, 255, 255])
maskHSV_low = cv2.inRange(resized_img_HSV, low_hsv_min, low_hsv_max)
# 赤を抽出(色相が179付近)
high_hsv_min = np.array([178, 200, 0])
high_hsv_max = np.array([179, 255, 255])
maskHSV_high = cv2.inRange(resized_img_HSV, high_hsv_min, high_hsv_max)
# 2つの領域を統合
hsv_mask = maskHSV_low | maskHSV_high
# 画像のマスク(合成)
resultHSV = cv2.bitwise_and(resized_img, resized_img, mask=hsv_mask)
cv2.imshow("Result HSV", resultHSV)
cv2.imshow("Result mask", hsv_mask)
cv2.waitKey(0)
cv2.destroyAllWindows()

maskHSV_low | maskHSV_highで2つのマスクのOR(和)を取ることで、色相が0付近と179付近の両方の赤色を統合して抽出しています。
まとめ
今回は、OpenCVで画像から特定の色を抽出する方法を紹介しました。
cv2.inRange()で色の範囲を指定して2値化マスクを作成するcv2.bitwise_and()でマスクを使って元画像から色を抽出する- HSVでの赤色抽出は色相が2箇所に分かれるため、マスクの統合が必要
- 色空間を活用した色の抽出は、画像解析における前処理として広く活用される