Python

【Python】色相(Hue)の平均値を算出する方法・実装

※ 本ブログはプロモーションが含まれています

【Python】色相(Hue)の平均値を算出する方法・実装

ポロシャツエンジニア

3分で技術が身に付くブログ!
・ポロシャツを愛するエンジニア
・企業にて研究開発職
・画像処理 | Deep Learning

Pythonにて、HSV色空間の色相(Hue)の平均値を算出する方法を紹介します!

おすすめの読者

  • 色相(Hue)の平均値を算出する設計を知りたい方
  • 色相(Hue)の平均値を算出する実装を知りたい方
  • 色相(Hue)の平均値を算出結果を知りたい方

【結論】色相(Hue)の平均値を算出する方法

結論、色相(Hue)の平均値を算出するため、色相環・ベクトルととらえることで、平均計算を実現します!
本記事の内容を深く理解するためには、 詳解 OpenCV 3 ―コンピュータビジョンライブラリを使った画像処理・認識 がおすすめです!

色相の平均値を算出する方法

  • Hueの画素をベクトル化する
  • 全画素のベクトル平均を算出する
  • 平均ベクトルを色相の平均値として返す

色相の平均値を算出するためのコードはこちらです。

import numpy as np

def calculate_average_hue(hue_image: np.ndarray) -> float:
    if (0 > np.min(hue_image)) or (np.max(hue_image) > 179):
        raise ValueError("入力するHue画像は0~179を入力してください")

    # OpencvのHueの範囲は0~180であるため、0~360に拡張
    hue_image_0_to_360 = hue_image * 2

    # X, Y方向にそれぞれベクトル化
    hue_vec_x = np.cos(np.deg2rad(hue_image_0_to_360))
    hue_vec_y = np.sin(np.deg2rad(hue_image_0_to_360))
    
    # X, Y方向それぞれベクトルを平均化 
    hue_vec_x_ave = np.average(hue_vec_x)
    hue_vec_y_ave = np.average(hue_vec_y)

    # ベクトルのarctanを算出
    average_hue_vec_arctan_deg = np.rad2deg(
        np.arctan2(hue_vec_y_ave, hue_vec_x_ave))

    # np.arctan2の出力範囲は-180deg~180degであるため、0~360degに変換
    if average_hue_vec_arctan_deg < 0:
        average_hue_vec_arctan_deg += 360

    # OpencvのHueの範囲である0~180に合わせる
    average_hue_vec_arctan2_deg_0_to_180 = average_hue_vec_arctan_deg / 2.
    
    return average_hue_vec_arctan2_deg_0_to_180    

【設計】色相(Hue)の平均値を算出する考え方

色相を「環」として考える

色相(Hue)は下記のように「色相環」として捉えることができます。
この性質を活用し、色相の平均値算出を行います。

色相をベクトル演算として解く

色相をベクトルとして定義することで、色相環上の計算として求めることができるようになります。

OpenCVのHueの範囲に注意する

OpenCVのHue成分は、0~179の範囲で表現されます。
そのため、実装上は0~360 [deg] の範囲で演算するように前処理・後処理を行う必要があります。

Note For HSV, Hue range is [0,179], Saturation range is [0,255] and Value range is [0,255]. Different softwares use different scales. So if you are comparing OpenCV values with them, you need to normalize these ranges.

Changing Colorspaces

【実装】色相(Hue)の平均値をPythonで算出する

実装例

下記コードによって、色相の平均値を算出することができます!

import numpy as np

def calculate_average_hue(hue_image: np.ndarray) -> float:
    if (0 > np.min(hue_image)) or (np.max(hue_image) > 179):
        raise ValueError("入力するHue画像は0~179を入力してください")

    # OpencvのHueの範囲は0~180であるため、0~360に拡張
    hue_image_0_to_360 = hue_image * 2

    # X, Y方向にそれぞれベクトル化
    hue_vec_x = np.cos(np.deg2rad(hue_image_0_to_360))
    hue_vec_y = np.sin(np.deg2rad(hue_image_0_to_360))
    
    # X, Y方向それぞれベクトルを平均化 
    hue_vec_x_ave = np.average(hue_vec_x)
    hue_vec_y_ave = np.average(hue_vec_y)

    # ベクトルのarctanを算出
    average_hue_vec_arctan_deg = np.rad2deg(
        np.arctan2(hue_vec_y_ave, hue_vec_x_ave))

    # np.arctan2の出力範囲は-180deg~180degであるため、0~360degに変換
    if average_hue_vec_arctan_deg < 0:
        average_hue_vec_arctan_deg += 360

    # OpencvのHueの範囲である0~180に合わせる
    average_hue_vec_arctan2_deg_0_to_180 = average_hue_vec_arctan_deg / 2.
    
    return average_hue_vec_arctan2_deg_0_to_180    

動作確認

単純な「1x2」の配列での動作確認

>>> print("[0, 0]の色相平均:", calculate_average_hue(np.array([0, 0])))
[0, 30]の色相平均: 0.0

>>> print("[0, 30]の色相平均:", calculate_average_hue(np.array([0, 30])))
[0, 30]の色相平均: 14.999999999999998

>>> print("[0, 90]の色相平均:", calculate_average_hue(np.array([0, 90])))
[0, 90]の色相平均: 45.0

>>> print("[0, 91]の色相平均:", calculate_average_hue(np.array([0, 91])))
[0, 91]の色相平均: 135.49999999999997

>>> print("[0, 100]の色相平均:", calculate_average_hue(np.array([0, 100])))
[0, 100]の色相平均: 140.0

>>> print("[0, 170]の色相平均:", calculate_average_hue(np.array([0, 170])))
[0, 170]の色相平均: 175.0

>>> print("[0, 179]の色相平均:", calculate_average_hue(np.array([0, 179])))
[0, 179]の色相平均: 179.5

>>> print("[90, 90]の色相平均:", calculate_average_hue(np.array([90, 90])))
[90, 90]の色相平均: 90.0

>>> print("[90, 91]の色相平均:", calculate_average_hue(np.array([90, 91])))
[90, 91]の色相平均: 90.5

>>> print("[90, 170]の色相平均:", calculate_average_hue(np.array([90, 170])))
[90, 170]の色相平均: 130.0

>>> print("[90, 179]の色相平均:", calculate_average_hue(np.array([90, 179])))
[90, 179]の色相平均: 134.50000000000003

>>> print("[90, 1]の色相平均:", calculate_average_hue(np.array([90, 1])))
[90, 1]の色相平均: 45.49999999999997

lennaでの動作確認

>>> import cv2
>>> # lennaの画像は`http://www.lenna.org/len_std.jpg`より取得
>>> bgr_image = cv2.imread("len_std.jpg", cv2.IMREAD_UNCHANGED)
>>> hue_image = cv2.split(cv2.cvtColor(bgr_image, cv2.COLOR_BGR2HSV))[0]
>>> calculate_average_hue(hue_image)
24.453125

【まとめ】色相(Hue)の平均値を算出する方法

結論、データ構造管理にはJSONスキーマを活用すべきです
本記事の内容を深く理解するためには、

詳解 OpenCV 3 ―コンピュータビジョンライブラリを使った画像処理・認識

がおすすめです!

色相の平均値を算出する方法

  • Hueの画素をベクトル化する
  • 全画素のベクトル平均を算出する
  • 平均ベクトルを色相の平均値として返す

本日紹介したコードのスニペットは以下に公開しています!

参考文献

中級・上級者にはこちらがおすすめ!
中級・上級者にはこちらがおすすめ!
  • この記事を書いた人

ポロシャツエンジニア

3分で技術が身に付くブログ!
・ポロシャツを愛するエンジニア
・企業にて研究開発職
・画像処理 | Deep Learning

-Python