1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Posted at

はじめに

色相(Hue)の平均値を算出するため、色相環・ベクトルととらえることで、平均計算を実現する

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

  • 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)は下記のように「色相環」として捉えることができる。
この性質を活用し、色相の平均値算出を行う。

参照元:Thresholding Operations using inRange

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

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

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

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

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?