【Python/OpenCV】RGBからHSVに変換(cv2.cvtColor)

PythonとOpenCVを用いて画像をRGBからHSVに変換する方法をソースコード付きで解説します。

【はじめに】HSV色空間とは

HSV色空間とは、「色相(Hue)」「彩度(Saturation)」「明度(Value)」の3つの組み合わせで色を表現する手法です。

説明
色相(H) 色合い。(赤っぽい、青っぽいといった色のおおまかな違いのことで、赤なら0度、黄色なら 60度といったように角度で色合いが決まります)
彩度(S) 色の鮮やかさ。(色相が同じ場合でも、彩度が高ければ鮮やかに見え、低ければグレーに見える。彩度がゼロの場合は無彩色[黒、グレー、白])
明度(V) 色の明るさ。(高いほど明るい色になる)

HSV色空間は人間が色を知覚する方法と類似しているため、RGB色空間よりも人がイメージした通りの色を作りやすいという特徴があります。
この特徴から、画像処理でも色検出をおこなう場合などにHSV色空間が利用されています。

動画解説

本ページの内容は動画でも解説しています。

【換算式】RGB色空間からHSV色空間への変換

(R、G、B)の値が0.0(最小)から1.0(最大)の範囲にあるとします。
R,G,Bの3つの値のうち、最大のものをMAX、最小のものをMINとしたとき、色相(H)は以下の式で計算できます。

(1)   \begin{eqnarray*} H= \left{ \begin{array}{r@{\,}c@{\,}r@{\,}c@{\,}r@{\;\leq\;}r} undefined \hspace{10px}(MIN=MAX)\\ 60\times \frac{G-B}{MAX-MIN}\hspace{10px}(MAX=R)\\ 60\times \frac{B-R}{MAX-MIN}+120\hspace{10px}(MAX=G)\\ 60\times \frac{R-G}{MAX-MIN}+240\hspace{10px}(MAX=B)\\ \end{array}% \right. \end{eqnarray*}

円錐モデルのときのS(色彩)は以下の式で計算できます。

(2)   \begin{eqnarray*} S=MAX-MIN \ \end{eqnarray*}

円柱モデルのときのS(色彩)は以下の式で計算できます。

(3)   \begin{eqnarray*} S=\frac{MAX-MIN}{MAX} \end{eqnarray*}

V(明度)は以下の式で計算できます。

(4)   \begin{eqnarray*} V=MAX \end{eqnarray*}

色相Hが負の値になれば、360を加算して0~360の範囲内に収めます。
色彩Sと明度Vは0~1の範囲内に値が収まります。

関連記事
詳細① 【画像処理】RGBからHSVへの変換
詳細② 【画像処理】HSV色空間の原理・特徴・計算式

【実装】Python版OpenCVでRGBからHSV色空間に変換

画像をRGBからHSVに変換する計算式と原理については下記事で紹介しています。

また、OpenCVライブラリでは、cv2.cvtColorメソッドでRGBからHSVに変換できます。

書式

hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
パラメータ名 説明
img 入力画像(RGB)
hsv 出力画像(HSV)

※出力されたHSV画像のHueは[0,179], Saturationは[0,255],Valueは[0,255]の範囲の値をとります。
今回は、「変換アルゴリズムを自前で実装する方法」と「cvtColorメソッドを利用する方法」を両方試してみます。

ソースコード①

変換アルゴリズムを自前で実装した場合のソースコードです。

#-*- coding:utf-8 -*-
import cv2
import numpy as np


def rgb_to_hsv(src, ksize=3):
    # 高さ・幅・チャンネル数を取得
    h, w, c = src.shape

    # 入力画像と同じサイズで出力画像用の配列を生成(中身は空)
    dst = np.empty((h, w, c))

    for y in range(0, h):
        for x in range(0, w):
            # R, G, Bの値を取得して0~1の範囲内にする
            [b, g, r] = src[y][x]/255.0

            # R, G, Bの値から最大値と最小値を計算
            mx, mn = max(r, g, b), min(r, g, b)

            # 最大値 - 最小値
            diff = mx - mn

            # Hの値を計算
            if mx == mn : h = 0
            elif mx == r : h = 60 * ((g-b)/diff)
            elif mx == g : h = 60 * ((b-r)/diff) + 120
            elif mx == b : h = 60 * ((r-g)/diff) + 240
            if h < 0 : h = h + 360

            # Sの値を計算
            if mx != 0:s = diff/mx
            else: s = 0

            # Vの値を計算
            v = mx

            # Hを0~179, SとVを0~255の範囲の値に変換
            dst[y][x] = [h * 0.5, s * 255, v * 255]

    return dst


# 入力画像の読み込み
img = cv2.imread("C:\prog\python\\test\input.jpg")

# 方法1(NumPyで実装)
hsv = rgb_to_hsv(img)

# 結果を出力
cv2.imwrite("C:\prog\python\\test\hsv.jpg", hsv)

ソースコード②

変換アルゴリズムをcv2.cvtColorメソッドで実装した場合のソースコードです。

#-*- coding:utf-8 -*-
import cv2
import numpy as np


# 入力画像の読み込み
img = cv2.imread("C:\prog\python\\test\input.jpg")

# 方法2(OpenCVで実装)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

# 結果を出力
cv2.imwrite("C:\prog\python\\test\hsv.jpg", hsv)

実行結果

サンプルプログラムの実行結果です。

■左から入力画像(input.jpg)、出力画像(hsv2.jpg)

お借りした画像:プロ生ちゃん(暮井 慧)

- 関連記事
1 PythonでOpenCV入門 サンプル集
2 【Python】画像処理プログラミング入門
3 【画像処理入門】アルゴリズム&プログラミング

コメント

  1. 匿名 より:

    とても参考になりました。ありがとうございます。
    誤植なのかなと思う点があるので、こちら修正よければお願いします。間違っていたら申し訳ないです。
    1. HSV値のHを求めるところで、RGBの値のそれぞれどの値が最大なのかで3つの式に分かれると思うのですが、記事内の(1)の式で、MAX=BとMAX=Rの式が反対になっている気がします。
    2. 上で指摘した式と同じところで、60*(G-R)/(MAX-MIN)+60 の式ですが、+60は必要ないように思います。
    Pythonソースコードでは正しい式になっているため、おそらく誤植であろうと思い報告させていただきました。余計なおせっかいでしたら申し訳ないです。
    以下、参考にしたOpenCVのリファレンスです。
    https://docs.opencv.org/4.5.1/de/d25/imgproc_color_conversions.html#color_convert_rgb_hsv