Qt QColor::hslHue()徹底解説:色の基本と活用法

2025-05-27

QColorクラスは、色を表現するためのQtのクラスです。通常、色はRGB(赤、緑、青)で表現されますが、HSV(色相、彩度、明度)やCMYK(シアン、マゼンタ、イエロー、キープレート)など、他の色空間でも表現できます。

hslHue()関数は、QColorオブジェクトの色をHSL(色相、彩度、輝度)色空間における色相(Hue)の値として取得するためのものです。

HSL色空間における「色相(Hue)」は、色の種類を円周上の角度で表します。

  • 灰色の場合
    もし色が灰色(彩度がない)の場合、色相は意味を持たないため、不定の値(通常は-1)を返すことがあります。
  • 値の範囲
    通常、0から359の範囲の整数値を返します。

どのような時に使うか?

  • ユーザーインターフェース
    カラーピッカーなどで、ユーザーが色相を調整できるようにする際。
  • 色の分析
    画像処理などで、特定の色相を持つ領域を抽出したり、分析したりする場合。
  • 色のバリエーションを生成する
    特定の色相を基準に、明るさや鮮やかさだけを変えた色のバリエーションを生成したい場合。
#include <QColor>
#include <QDebug>

int main() {
    QColor redColor(255, 0, 0); // 赤色
    QColor greenColor(0, 255, 0); // 緑色
    QColor blueColor(0, 0, 255); // 青色
    QColor grayColor(128, 128, 128); // 灰色

    qDebug() << "赤色の色相 (HSL):" << redColor.hslHue();    // おおよそ0を返す
    qDebug() << "緑色の色相 (HSL):" << greenColor.hslHue();  // おおよそ120を返す
    qDebug() << "青色の色相 (HSL):" << blueColor.hslHue();   // おおよそ240を返す
    qDebug() << "灰色の色相 (HSL):" << grayColor.hslHue();   // -1などを返す可能性あり

    // 例:現在の色相を少しずらした新しい色を作成
    QColor originalColor(100, 150, 200); // 適当な色
    int originalHue = originalColor.hslHue();
    qDebug() << "元の色の色相:" << originalHue;

    QColor newColorWithShiftedHue = QColor::fromHsl(
        (originalHue + 30) % 360, // 色相を30度ずらす (360で割って0-359に収める)
        originalColor.hslSaturation(),
        originalColor.lightness()
    );
    qDebug() << "色相をずらした新しい色:" << newColorWithShiftedHue;

    return 0;
}


灰色の色相 (Hue)

最も一般的な問題は、色が**完全に灰色(彩度がない)**の場合です。

  • トラブルシューティング/対処法
    • hslHue()を使用する前に、QColor::hslSaturation()QColor::hsvSaturation()などを確認し、色が灰色かどうかを判断します。
    • -1が返された場合、その状況を適切にハンドリングするロジックを追加します。例えば、灰色の場合に特定の色相(例: 0)を強制的に割り当てる、または色相の概念を適用しないようにする、といった対応が考えられます。

    • QColor color = ...; // 取得したQColorオブジェクト
      if (color.hslSaturation() == 0) { // 灰色の場合
          // 灰色であることを考慮した処理
          qDebug() << "この色は灰色です。色相は意味を持ちません。";
          // 必要に応じて、特定の色相を割り当てる(例: 0)
          int effectiveHue = 0; // または別のデフォルト値
      } else {
          int hue = color.hslHue();
          // 通常の色相を使った処理
          qDebug() << "色相:" << hue;
      }
      
  • 理由
    HSL色空間において、彩度(Saturation)が0(完全に灰色)の場合、色相は意味を持ちません。どの色相の光も含まれていないため、任意の色相を割り当てても無意味だからです。Qtはこれを明確に示すために-1という特殊な値を返します。
  • エラー/問題
    QColor::hslHue()は、灰色の場合に**-1**を返します。これはエラーではありませんが、多くの人が「色相が常に0-359の範囲である」と期待するため、予期せぬ結果となりがちです。

HSLとHSVの混同

QtにはhslHue()の他にhsvHue()も存在します。これらは似ていますが、異なる色空間に基づいています。

  • トラブルシューティング/対処法
    • どちらの色空間を使用しているのか、コード全体で一貫性を持たせることが重要です。
    • ある色空間から別の色空間に変換する場合は、QColor::toHsl(), QColor::toHsv(), QColor::fromHsl(), QColor::fromHsv() などの変換関数を明示的に使用します。
    • ドキュメントをよく読み、それぞれの関数の挙動を理解しておくことが不可欠です。
  • 理由
    • HSL (Hue, Saturation, Lightness)
      人間の知覚により近いとされ、彩度と輝度は独立して操作しやすいです。
    • HSV (Hue, Saturation, Value)
      グラフィックソフトウェアなどでよく使われ、純粋な色の最大輝度を表します。
  • エラー/問題
    HSLとHSVの色相は同じように角度で表現されますが、彩度(Saturation)と明度/輝度(Value/Lightness)の定義が異なります。そのため、意図しない色変換や色の不一致が発生することがあります。

浮動小数点精度 (QColor::hslHueF())

hslHue()は整数値を返しますが、より高精度な計算が必要な場合はhslHueF()(浮動小数点数版)も利用できます。

  • トラブルシューティング/対処法
    • より細かい色相の計算や、厳密な色の比較が必要な場合は、hslHueF()の使用を検討します。
    • ただし、浮動小数点数演算には丸め誤差が伴うため、厳密な等価性比較(==)は避けるべきです。代わりに、許容誤差範囲(epsilon)を用いた比較を行います。
  • 理由
    hslHue()は色相を0-359の整数値で返しますが、hslHueF()は0.0-359.99...の浮動小数点数で返します。
  • エラー/問題
    整数値のhslHue()では、色相のグラデーションが滑らかに見えない場合や、細かい色相の差を検出できない場合があります。

QColorオブジェクトが有効でない場合、hslHue()のような関数を呼び出しても意味のある結果は得られません。

  • トラブルシューティング/対処法
    • QColor::isValid()関数を使用して、QColorオブジェクトが有効な状態であるかを確認します。
    • オブジェクトを初期化する際には、有効なRGB値、またはQt::GlobalColorのような定義済み色を使用するようにします。

    • QColor myColor; // 未初期化
      if (!myColor.isValid()) {
          qDebug() << "myColorは無効なQColorです。";
          // デフォルトの色を割り当てるなどして対処
          myColor = Qt::black;
      }
      int hue = myColor.hslHue(); // これで安全
      
  • 理由
    QColorは、RGB値などを用いて適切に初期化される必要があります。
  • エラー/問題
    未初期化のQColorオブジェクトや、無効な値で作成されたQColorオブジェクトに対してhslHue()を呼び出すと、予期しない値が返されたり、クラッシュの原因になる可能性があります。


例 1: 基本的な色相の取得と表示

最も基本的な使い方です。様々な色の hslHue() を取得し、コンソールに表示します。

#include <QCoreApplication> // コンソールアプリケーションの場合
#include <QDebug>           // デバッグ出力用
#include <QColor>           // QColor クラス

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv); // QApplication でも可

    // --- 色の定義 ---
    QColor red(255, 0, 0);       // 純粋な赤
    QColor green(0, 255, 0);     // 純粋な緑
    QColor blue(0, 0, 255);      // 純粋な青
    QColor yellow(255, 255, 0);  // 黄色
    QColor cyan(0, 255, 255);    // シアン
    QColor magenta(255, 0, 255); // マゼンタ
    QColor orange(255, 165, 0);  // オレンジ
    QColor purple(128, 0, 128);  // 紫

    QColor gray(128, 128, 128);  // 灰色(彩度0)
    QColor black(0, 0, 0);       // 黒(彩度0)
    QColor white(255, 255, 255); // 白(彩度0)

    // --- hslHue() の呼び出しと結果の表示 ---
    qDebug() << "--- 色相 (Hue) の取得 ---";

    qDebug() << "赤 (Red):" << red.name() << " -> Hue:" << red.hslHue();        // 約 0
    qDebug() << "緑 (Green):" << green.name() << " -> Hue:" << green.hslHue();      // 約 120
    qDebug() << "青 (Blue):" << blue.name() << " -> Hue:" << blue.hslHue();       // 約 240
    qDebug() << "黄 (Yellow):" << yellow.name() << " -> Hue:" << yellow.hslHue();     // 約 60
    qDebug() << "シアン (Cyan):" << cyan.name() << " -> Hue:" << cyan.hslHue();      // 約 180
    qDebug() << "マゼンタ (Magenta):" << magenta.name() << " -> Hue:" << magenta.hslHue();   // 約 300
    qDebug() << "オレンジ (Orange):" << orange.name() << " -> Hue:" << orange.hslHue();    // 約 39 (0-359の範囲で)
    qDebug() << "紫 (Purple):" << purple.name() << " -> Hue:" << purple.hslHue();    // 約 270 (0-359の範囲で)

    qDebug() << "\n--- 彩度がない色 (灰色/黒/白) の色相 ---";
    qDebug() << "灰色 (Gray):" << gray.name() << " -> Hue:" << gray.hslHue();      // -1 を返す
    qDebug() << "黒 (Black):" << black.name() << " -> Hue:" << black.hslHue();      // -1 を返す
    qDebug() << "白 (White):" << white.name() << " -> Hue:" << white.hslHue();     // -1 を返す

    return a.exec(); // コンソールアプリの場合は不要なことが多いが、QApplicationを使う場合は必要
}

実行結果の例

--- 色相 (Hue) の取得 ---
赤 (Red): "#ff0000"  -> Hue: 0
緑 (Green): "#00ff00"  -> Hue: 120
青 (Blue): "#0000ff"  -> Hue: 240
黄 (Yellow): "#ffff00"  -> Hue: 60
シアン (Cyan): "#00ffff"  -> Hue: 180
マゼンタ (Magenta): "#ff00ff"  -> Hue: 300
オレンジ (Orange): "#ffa500"  -> Hue: 39
紫 (Purple): "#800080"  -> Hue: 270

--- 彩度がない色 (灰色/黒/白) の色相 ---
灰色 (Gray): "#808080"  -> Hue: -1
黒 (Black): "#000000"  -> Hue: -1
白 (White): "#ffffff"  -> Hue: -1

この例から、彩度がない色(灰色、黒、白)の場合に hslHue()-1 を返すことが明確にわかります。

例 2: 灰色の色相の特別な扱い

hslHue()-1 を返す状況を適切に処理する例です。

#include <QCoreApplication>
#include <QDebug>
#include <QColor>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QList<QColor> colors;
    colors << QColor(200, 50, 50);   // 赤みがかった色
    colors << QColor(100, 100, 100); // 灰色
    colors << QColor(0, 0, 0);       // 黒
    colors << QColor(50, 200, 50);   // 緑がかった色
    colors << QColor(255, 255, 255); // 白

    qDebug() << "--- 色相 (Hue) の安全な取得 ---";

    for (const QColor& color : colors) {
        int hue = color.hslHue();
        // HSLの彩度を確認
        int saturation = color.hslSaturation(); // 0-255

        if (saturation == 0) { // 彩度が0の場合(灰色、黒、白)
            qDebug() << "色:" << color.name() << " -> この色は彩度がないため、色相は意味を持ちません (Hue: " << hue << ").";
            // 必要に応じて、ここでデフォルトの色相を割り当てるなどの処理を行う
            // 例えば、if (hue == -1) { int effectiveHue = 0; }
        } else {
            qDebug() << "色:" << color.name() << " -> Hue:" << hue << ", Saturation:" << saturation;
        }
    }

    return a.exec();
}

実行結果の例

--- 色相 (Hue) の安全な取得 ---
色: "#c83232"  -> Hue: 0, Saturation: 200
色: "#646464"  -> この色は彩度がないため、色相は意味を持ちません (Hue: -1).
色: "#000000"  -> この色は彩度がないため、色相は意味を持ちません (Hue: -1).
色: "#32c832"  -> Hue: 120, Saturation: 200
色: "#ffffff"  -> この色は彩度がないため、色相は意味を持ちません (Hue: -1).

この例では、hslSaturation() をチェックすることで、色が彩度を持っているかどうかを判断し、その結果に基づいて異なるメッセージを表示しています。これは、hslHue()-1 を返す場合の典型的な対処法です。

例 3: 色相を基準にした新しい色の生成

既存の色の色相だけをずらして、新しい色を生成する例です。

#include <QCoreApplication>
#include <QDebug>
#include <QColor>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QColor originalColor("#345678"); // 元の色 (例: 暗めの青緑)
    qDebug() << "元の色:" << originalColor.name();
    qDebug() << "  Hue:" << originalColor.hslHue();
    qDebug() << "  Saturation:" << originalColor.hslSaturation();
    qDebug() << "  Lightness:" << originalColor.hslLightness();

    // 元の色相を取得
    int originalHue = originalColor.hslHue();

    // HSLの色相、彩度、輝度を取得(0-255の範囲)
    int saturation = originalColor.hslSaturation();
    int lightness = originalColor.hslLightness();

    // 色相をずらして新しい色を生成
    // 色相は0-359の範囲に収めるために `% 360` を使用
    QColor newColor1 = QColor::fromHsl((originalHue + 60) % 360, saturation, lightness); // 色相を+60度
    QColor newColor2 = QColor::fromHsl((originalHue + 180) % 360, saturation, lightness); // 色相を+180度(補色に近い)
    QColor newColor3 = QColor::fromHsl((originalHue - 30 + 360) % 360, saturation, lightness); // 色相を-30度(負の値を考慮)

    qDebug() << "\n--- 色相をずらした新しい色 ---";
    qDebug() << "+60度ずらした色:" << newColor1.name();
    qDebug() << "  Hue:" << newColor1.hslHue();

    qDebug() << "+180度ずらした色:" << newColor2.name();
    qDebug() << "  Hue:" << newColor2.hslHue();

    qDebug() << "-30度ずらした色:" << newColor3.name();
    qDebug() << "  Hue:" << newColor3.hslHue();

    // 灰色の場合の考慮(重要!)
    QColor grayColor(150, 150, 150);
    qDebug() << "\n--- 灰色の場合の処理 ---";
    if (grayColor.hslSaturation() == 0) {
        qDebug() << "灰色の色相は意味を持たないので、変更しません。";
        // または、特定のデフォルト色相に設定する
        // QColor newGrayColor = QColor::fromHsl(0, 0, grayColor.hslLightness()); // 赤色相の灰色
        // qDebug() << "強制的に赤色相の灰色にした場合:" << newGrayColor.name();
    } else {
        // 通常の処理
    }

    return a.exec();
}

実行結果の例

元の色: "#345678"
  Hue: 210
  Saturation: 60
  Lightness: 69

--- 色相をずらした新しい色 ---
+60度ずらした色: "#347856"
  Hue: 270
+180度ずらした色: "#785634"
  Hue: 30
-30度ずらした色: "#343478"
  Hue: 180

--- 灰色の場合の処理 ---
灰色の色相は意味を持たないので、変更しません。

この例では、QColor::fromHsl() を使用して、取得した色相、彩度、輝度から新しい QColor オブジェクトを生成しています。色相を操作する際には、% 360 を使用して常に0-359の範囲に収めることが重要です。また、灰色の場合の特別な処理も忘れずに考慮しています。

これらの例が、QColor::hslHue() の理解と使用に役立つことを願っています。 Qt の QColor::hslHue() に関連するプログラミング例をいくつかご紹介します。これらの例はC++で書かれており、Qtの一般的な使い方を示しています。

基本的な色相の取得

最も基本的な使い方です。RGB値から色相を取得します。

#include <QColor>
#include <QDebug> // デバッグ出力用

int main() {
    // RGBで色を定義
    QColor redColor(255, 0, 0);       // 純粋な赤
    QColor greenColor(0, 255, 0);     // 純粋な緑
    QColor blueColor(0, 0, 255);      // 純粋な青
    QColor yellowColor(255, 255, 0);  // 黄色
    QColor magentaColor(255, 0, 255); // マゼンタ
    QColor cyanColor(0, 255, 255);    // シアン

    // 各色のHSL色相を取得して出力
    qDebug() << "赤色の色相:" << redColor.hslHue();     // 0
    qDebug() << "緑色の色相:" << greenColor.hslHue();   // 120
    qDebug() << "青色の色相:" << blueColor.hslHue();    // 240
    qDebug() << "黄色の色相:" << yellowColor.hslHue();  // 60
    qDebug() << "マゼンタの色相:" << magentaColor.hslHue(); // 300
    qDebug() << "シアンの色相:" << cyanColor.hslHue();  // 180

    return 0;
}

解説

  • hslHue() を呼び出すと、その色がHSL色空間で持つ色相(0〜359の整数)が返されます。
  • QColor(r, g, b) コンストラクタでRGB値から色を作成します。

灰色の色相の扱い

前の説明であったように、灰色(彩度がない)の場合にhslHue()-1を返します。この挙動を考慮したコードです。

#include <QColor>
#include <QDebug>

int main() {
    QColor grayColor(128, 128, 128); // 灰色
    QColor blackColor(0, 0, 0);      // 黒
    QColor whiteColor(255, 255, 255); // 白

    qDebug() << "灰色の彩度:" << grayColor.hslSaturation(); // 0
    qDebug() << "灰色の色相:" << grayColor.hslHue();    // -1 を返す

    qDebug() << "黒色の彩度:" << blackColor.hslSaturation();  // 0
    qDebug() << "黒色の色相:" << blackColor.hslHue();     // -1 を返す

    qDebug() << "白色の彩度:" << whiteColor.hslSaturation();  // 0
    qDebug() << "白色の色相:" << whiteColor.hslHue();     // -1 を返す

    // 灰色の場合のハンドリング例
    QColor someColor(100, 100, 100); // これも灰色
    int hueValue = someColor.hslHue();

    if (someColor.hslSaturation() == 0) { // 彩度で灰色を判定
        qDebug() << "この色は灰色です。色相は定義されません (-1)。";
        // 例えば、デフォルトの色相を使用する、または特定のエラー処理を行う
        // int defaultHue = 0;
    } else {
        qDebug() << "この色の色相は:" << hueValue;
    }

    return 0;
}

解説

  • 灰色の場合にhslHue()-1を返すことを理解し、その値をそのまま使わないように注意が必要です。
  • hslSaturation() を使って彩度をチェックし、0であれば灰色(無彩色)と判断できます。

色相を操作して新しい色を生成

hslHue()で色相を取得し、その値を変更して新しい色を作成する例です。

#include <QColor>
#include <QDebug>

int main() {
    QColor originalColor(50, 150, 200); // 青みがかった色

    // 元の色のHSL成分を取得
    int originalHue = originalColor.hslHue();
    int originalSaturation = originalColor.hslSaturation();
    int originalLightness = originalColor.lightness(); // lightness() はHSLのLに相当

    qDebug() << "元の色 (RGB):" << originalColor.red() << originalColor.green() << originalColor.blue();
    qDebug() << "元の色 (HSL): H=" << originalHue << " S=" << originalSaturation << " L=" << originalLightness;

    // 色相を90度ずらした新しい色を作成
    // 色相は0-359の範囲なので、360で剰余を取ります
    int newHue = (originalHue + 90) % 360;
    QColor shiftedColor = QColor::fromHsl(newHue, originalSaturation, originalLightness);

    qDebug() << "色相を90度ずらした新しい色 (RGB):" << shiftedColor.red() << shiftedColor.green() << shiftedColor.blue();
    qDebug() << "色相をずらした新しい色 (HSL): H=" << shiftedColor.hslHue() << " S=" << shiftedColor.hslSaturation() << " L=" << shiftedColor.lightness();

    // 彩度を上げて「より鮮やかな」同じ色相の色を作成
    int increasedSaturation = qMin(originalSaturation + 50, 255); // 255を超えないように
    QColor vividColor = QColor::fromHsl(originalHue, increasedSaturation, originalLightness);
    qDebug() << "より鮮やかな色 (RGB):" << vividColor.red() << vividColor.green() << vividColor.blue();
    qDebug() << "より鮮やかな色 (HSL): H=" << vividColor.hslHue() << " S=" << vividColor.hslSaturation() << " L=" << vividColor.lightness();

    return 0;
}

解説

  • qMinqMaxのようなQtのユーティリティ関数は、値を特定の範囲に制限するのに便利です。
  • 色相を円周上でずらすために、% 360(剰余演算子)を使います。これにより、値が359を超えても0に戻り、色相のサイクルが維持されます。
  • QColor::fromHsl(h, s, l) 静的関数を使って、HSL値から新しいQColorオブジェクトを作成できます。

hslHueF()は浮動小数点数の色相を返します。より精密な色相の操作や表示が必要な場合に有用です。

#include <QColor>
#include <QDebug>

int main() {
    QColor specificColor(255, 168, 177); // 特定のRGB値

    // 整数値の色相
    int hueInt = specificColor.hslHue();
    // 浮動小数点数の色相
    double hueFloat = specificColor.hslHueF();

    qDebug() << "RGB:" << specificColor.red() << specificColor.green() << specificColor.blue();
    qDebug() << "整数色相 (hslHue()):" << hueInt;
    qDebug() << "浮動小数点色相 (hslHueF()):" << hueFloat;

    // 浮動小数点数を使ったより精密な色相シフト
    double newHueF = fmod(hueFloat + 15.5, 360.0); // fmodは浮動小数点数の剰余
    QColor preciseShiftedColor = QColor::fromHslF(newHueF, specificColor.hslSaturationF(), specificColor.lightnessF());

    qDebug() << "精密にシフトした色 (HSL): H=" << preciseShiftedColor.hslHueF() << " S=" << preciseShiftedColor.hslSaturationF() << " L=" << preciseShiftedColor.lightnessF();

    return 0;
}
  • QColor::fromHslF() は、浮動小数点数のHSL値から色を作成するのに使われます。
  • 浮動小数点数の剰余計算には fmod() を使用します。
  • hslHueF()double 型の値を返します。


HSV (Hue, Saturation, Value) 色空間を使用する

HSL と並んで、HSV (Hue, Saturation, Value) も広く使われる色空間です。色相(Hue)の概念はHSLと同じですが、彩度(Saturation)と明度(Value)の定義が異なります。

    • HSLと同様に、HSV色空間における色相を取得します。値の範囲も0から359です。
    • 違い
      HSLのlightness()が「輝度」を指すのに対し、HSVのvalue()は「明度」を指します。HSVでは、valueが最大(255)の時に最も明るい色(純色)になります。HSLでは、lightnessが最大(255)の時に白になります。
    • 代替として使う場合
      どちらの色空間を使うかは、アプリケーションのニーズによります。例えば、Photoshopなどの一部のグラフィックソフトウェアではHSVがデフォルトで使われることが多いです。
    #include <QColor>
    #include <QDebug>
    
    int main() {
        QColor color(100, 150, 200); // ある色
    
        // HSL色相を取得
        int hslHue = color.hslHue();
        qDebug() << "HSL Hue:" << hslHue;
    
        // HSV色相を取得
        int hsvHue = color.hsvHue();
        qDebug() << "HSV Hue:" << hsvHue;
    
        // 灰色の比較(HSVもHSLと同様に-1を返す)
        QColor grayColor(128, 128, 128);
        qDebug() << "Gray HSL Hue:" << grayColor.hslHue();
        qDebug() << "Gray HSV Hue:" << grayColor.hsvHue();
    
        return 0;
    }
    

RGB から手動で HSL/HSV を計算する

QtのQColorクラスが提供する機能を使わずに、RGB値から直接HSLやHSVの色相を計算することも可能です。これは、特定のアルゴリズムを実装したい場合や、Qt以外の環境で色変換を行う場合に役立ちます。

  • 欠点
    • 自分でロジックを実装する必要があるため、コード量が増え、バグのリスクも高まる。
    • Qtが提供する最適化やエッジケース(例: 灰色の場合のHue値)のハンドリングを自分で考慮する必要がある。
  • 利点
    • Qtの依存関係がない場所でも色変換ロジックを再利用できる。
    • 独自の丸め処理や精度調整を行える。
  • 方法
    RGBからHSL/HSVへの変換アルゴリズムは公開されており、数学的な計算で実現できます。

以下は、RGBからHSVの色相(Hue)を手動で計算する簡単な例です(HSLも同様に計算できますが、ここではHSVを示します)。

#include <QColor>
#include <QDebug>
#include <algorithm> // std::max, std::min 用
#include <cmath>     // fmod, round 用

// RGBからHSVの色相を計算する関数 (0-359の範囲)
int calculateHsvHue(int r, int g, int b) {
    double r_norm = r / 255.0;
    double g_norm = g / 255.0;
    double b_norm = b / 255.0;

    double cmax = std::max({r_norm, g_norm, b_norm});
    double cmin = std::min({r_norm, g_norm, b_norm});
    double delta = cmax - cmin;

    double hue = 0.0;

    if (delta == 0) {
        hue = 0; // 無彩色の場合、色相は0(または-1、定義なし)
    } else if (cmax == r_norm) {
        hue = 60 * fmod(((g_norm - b_norm) / delta), 6);
    } else if (cmax == g_norm) {
        hue = 60 * (((b_norm - r_norm) / delta) + 2);
    } else if (cmax == b_norm) {
        hue = 60 * (((r_norm - g_norm) / delta) + 4);
    }

    if (hue < 0) {
        hue += 360;
    }

    // QtのhsvHue()は整数値を返すため、丸める
    return static_cast<int>(round(hue));
}

int main() {
    QColor qtColor(100, 150, 200);

    // Qtの関数で取得
    int qtHsvHue = qtColor.hsvHue();
    qDebug() << "Qt's HSV Hue:" << qtHsvHue;

    // 手動で計算
    int manualHsvHue = calculateHsvHue(100, 150, 200);
    qDebug() << "Manual HSV Hue:" << manualHsvHue;

    // 灰色の場合
    QColor grayColor(128, 128, 128);
    int qtGrayHsvHue = grayColor.hsvHue();
    int manualGrayHsvHue = calculateHsvHue(128, 128, 128); // 0を返す
    qDebug() << "Qt's Gray HSV Hue:" << qtGrayHsvHue;       // -1を返す
    qDebug() << "Manual Gray HSV Hue:" << manualGrayHsvHue; // 0を返す

    return 0;
}

注意
手動計算の場合、無彩色(灰色、黒、白)の色相は通常0として扱われます。QtのhslHue()hsvHue()-1を返すのとは異なる挙動を示すため、この違いを理解しておくことが重要です。

他の色空間への変換 (toHsv(), toCmyk(), convertTo())

QColorオブジェクトは、他の色空間への変換メソッドを提供しています。これらを使って、一度別の色空間のQColorオブジェクトに変換し、そこから情報を取得することも考えられます。ただし、hslHue()自体は直接HSLの色相を返すため、ほとんどの場合、これらの変換はhslHue()の直接の代替というよりは、別の色空間で作業したい場合に使うものです。

  • QColor QColor::convertTo(QColor::Spec colorSpec) const

    • 指定された色空間の新しいQColorオブジェクトを返します。QColor::Hsv, QColor::Hsl, QColor::Cmyk などの指定が可能です。
    • これもtoHsl()と似ていますが、より汎用的な変換方法です。

Qtの機能だけでは不十分な場合や、より専門的な色変換・操作が必要な場合、以下のような外部のカラーライブラリを検討することもできます。

  • Boost.GIL (Generic Image Library)
    C++の汎用画像処理ライブラリで、様々な色空間と変換をサポートしています。
  • Little Color Management System (LCMS)
    カラープロファイル(ICCプロファイル)に基づいた色変換をサポートする強力なライブラリです。非常に高度な色管理が必要な場合に検討されます。