今日も適当ダイアリー

PHP や Javascript や Symfony、BEAR.Sunday などのWeb周りのことを中心に。それ以外のことも気まぐれに投稿します。

RGB色空間とHSV色空間の相互変換 PHP版

PHP配列とCSS色表現の相互変換 - 今日も適当ダイアリー に続いて、 relColors に使った関数を公開します。

色の明度や色相を計算するために、いったんRGBで表現された色情報を、HSV色空間に変換した上で計算を行いました。
HSV色空間については HSV色空間 - Wikipedia を参照してください。

RGB から HSV色空間へのコンバート

変換式は、上記したWikipediaに載っているので、それを素直にPHPで書きました。

<?php
/**
 * RGB配列 を HSV配列 へ変換します
 *
 * @param   array   $arr            array(r, g, b) ※ r/g/b は 0〜255 の数値
 * @param   bool    $coneModel      円錐モデルにするか
 * @return  array   array(h, s, v) ※h は 0〜360の数値、s/v は 0〜255 の数値
 */
function RGBtoHSV($arr, $coneModel = false)
{
    $h = 0; // 0..360
    $s = 0; // 0..255
    $v = 0; // 0..255

    $max = max($arr);
    $min = min($arr);

    // hue の計算
    if ($max == $min) {
        $h = 0; // 本来は定義されないが、仮に0を代入
    } else if ($max == $arr[0]) {
        // MAX = R
        // 60 * (G-B)/(MAX-MIN) + 0
        $h = 60 * ($arr[1] - $arr[2]) / ($max - $min) + 0;
    } else if ($max == $arr[1]) {
        // MAX = G
        // 60 * (B-R)/(MAX-MIN) + 120
        $h = (60 * ($arr[2] - $arr[0]) / ($max - $min)) + 120;
    } else {
        // MAX = B
        // 60 * (R-G)/(MAX-MIN) + 240
        $h = (60 * ($arr[0] - $arr[1]) / ($max - $min)) + 240;
    }

    while ($h < 0) {
        $h += 360;
    }

    // saturation の計算
    if ($coneModel) {
        // 円錐モデルの場合
        $s = $max - $min;
    } else {
        if ($max == 0) {
            // 本来は定義されないが、仮に0を代入
            $s = 0;
        } else {
            $s = ($max - $min) / $max * 255;
        }
    }

    // value の計算
    $v = $max;

    return array(
        $h, // H
        $s, // S
        $v, // V
    );
}

HSV から RGB色空間へのコンバート

<?php

/**
 * HSV配列 を RGB配列 へ変換します
 *
 * @param   array   $arr            array(h, s, v) ※h は 0〜360の数値、s/v は 0〜255 の数値
 * @return  array   array(r, g, b) ※ r/g/b は 0〜255 の数値
 */
function HSVtoRGB($arr)
{
    $r = 0; // 0..255
    $g = 0; // 0..255
    $b = 0; // 0..255

    while ($arr[0] < 0) {
      $arr[0] += 360;
    }

    $arr[0] = $arr[0] % 360;

    // 特別な場合
    if ($arr[1] == 0) {
        // S = 0.0
        // → RGB は V に等しい
        return array(
            round($arr[2]),
            round($arr[2]),
            round($arr[2]),
        );
    }

    $arr[1] = $arr[1] / 255;


    // Hi = floor(H/60) mod 6
    $i = floor($arr[0] / 60) % 6;
    // f = H/60 - Hi
    $f = ($arr[0] / 60) - $i;

    // p = V (1 - S)
    $p = $arr[2] * (1 - $arr[1]);
    // q = V (1 - fS)
    $q = $arr[2] * (1 - $f * $arr[1]);
    // t = V (1 - (1 - f) S)
    $t = $arr[2] * (1 - (1 - $f) * $arr[1]);

    switch ($i) {
        case 0 :
            // R = V, G = t, B = p
            $r = $arr[2];
            $g = $t;
            $b = $p;
            break;
        case 1 :
            // R = q, G = V, B = p
            $r = $q;
            $g = $arr[2];
            $b = $p;
            break;
        case 2 :
            // R = p, G = V, B = t
            $r = $p;
            $g = $arr[2];
            $b = $t;
            break;
        case 3 :
            // R = p, G = q, B = V
            $r = $p;
            $g = $q;
            $b = $arr[2];
            break;
        case 4 :
            // R = t, G = p, B = V
            $r = $t;
            $g = $p;
            $b = $arr[2];
            break;
        case 5 :
            // R = V, G = p, B = q
            $r = $arr[2];
            $g = $p;
            $b = $q;
            break;
    }

    return array(
        round($r), // r
        round($g), // g
        round($b), // b
    );
}