24

在 PHP 中,将 RGB 三元组转换为 HSV 值的最直接方法是什么?

4

5 回答 5

34

这是一个简单直接的方法,它以度数和百分比的形式返回 HSV 值,这是 Photoshop 的颜色选择器使用的。

请注意,返回值不会四舍五入,如果需要,您可以自己进行。请记住H(360) == H(0),因此和更大H的值359.5应该四舍五入0

大量记录用于学习目的。

/**
 * Licensed under the terms of the BSD License.
 * (Basically, this means you can do whatever you like with it,
 *   but if you just copy and paste my code into your app, you
 *   should give me a shout-out/credit :)
 */

<?php

function RGBtoHSV($R, $G, $B)    // RGB values:    0-255, 0-255, 0-255
{                                // HSV values:    0-360, 0-100, 0-100
    // Convert the RGB byte-values to percentages
    $R = ($R / 255);
    $G = ($G / 255);
    $B = ($B / 255);

    // Calculate a few basic values, the maximum value of R,G,B, the
    //   minimum value, and the difference of the two (chroma).
    $maxRGB = max($R, $G, $B);
    $minRGB = min($R, $G, $B);
    $chroma = $maxRGB - $minRGB;

    // Value (also called Brightness) is the easiest component to calculate,
    //   and is simply the highest value among the R,G,B components.
    // We multiply by 100 to turn the decimal into a readable percent value.
    $computedV = 100 * $maxRGB;

    // Special case if hueless (equal parts RGB make black, white, or grays)
    // Note that Hue is technically undefined when chroma is zero, as
    //   attempting to calculate it would cause division by zero (see
    //   below), so most applications simply substitute a Hue of zero.
    // Saturation will always be zero in this case, see below for details.
    if ($chroma == 0)
        return array(0, 0, $computedV);

    // Saturation is also simple to compute, and is simply the chroma
    //   over the Value (or Brightness)
    // Again, multiplied by 100 to get a percentage.
    $computedS = 100 * ($chroma / $maxRGB);

    // Calculate Hue component
    // Hue is calculated on the "chromacity plane", which is represented
    //   as a 2D hexagon, divided into six 60-degree sectors. We calculate
    //   the bisecting angle as a value 0 <= x < 6, that represents which
    //   portion of which sector the line falls on.
    if ($R == $minRGB)
        $h = 3 - (($G - $B) / $chroma);
    elseif ($B == $minRGB)
        $h = 1 - (($R - $G) / $chroma);
    else // $G == $minRGB
        $h = 5 - (($B - $R) / $chroma);

    // After we have the sector position, we multiply it by the size of
    //   each sector's arc (60 degrees) to obtain the angle in degrees.
    $computedH = 60 * $h;

    return array($computedH, $computedS, $computedV);
}

?>
于 2012-12-14T23:59:14.820 回答
18
<?php
function RGB_TO_HSV ($R, $G, $B)  // RGB Values:Number 0-255
{                                 // HSV Results:Number 0-1
   $HSL = array();

   $var_R = ($R / 255);
   $var_G = ($G / 255);
   $var_B = ($B / 255);

   $var_Min = min($var_R, $var_G, $var_B);
   $var_Max = max($var_R, $var_G, $var_B);
   $del_Max = $var_Max - $var_Min;

   $V = $var_Max;

   if ($del_Max == 0)
   {
      $H = 0;
      $S = 0;
   }
   else
   {
      $S = $del_Max / $var_Max;

      $del_R = ( ( ( $var_Max - $var_R ) / 6 ) + ( $del_Max / 2 ) ) / $del_Max;
      $del_G = ( ( ( $var_Max - $var_G ) / 6 ) + ( $del_Max / 2 ) ) / $del_Max;
      $del_B = ( ( ( $var_Max - $var_B ) / 6 ) + ( $del_Max / 2 ) ) / $del_Max;

      if      ($var_R == $var_Max) $H = $del_B - $del_G;
      else if ($var_G == $var_Max) $H = ( 1 / 3 ) + $del_R - $del_B;
      else if ($var_B == $var_Max) $H = ( 2 / 3 ) + $del_G - $del_R;

      if ($H<0) $H++;
      if ($H>1) $H--;
   }

   $HSL['H'] = $H;
   $HSL['S'] = $S;
   $HSL['V'] = $V;

   return $HSL;
}
于 2009-11-20T22:59:31.327 回答
2

经过彻底测试和压缩,这是我将坚持用于将RGB转换为HSV的功能:

function RGBtoHSV($r,$g,$b) {
  $r=($r/255); $g=($g/255); $b=($b/255);
  $maxRGB=max($r,$g,$b); $minRGB=min($r,$g,$b); $chroma=$maxRGB-$minRGB;
  if($chroma==0) return array('h'=>0,'s'=>0,'v'=>$maxRGB);
  if($r==$minRGB)$h=3-(($g-$b)/$chroma);
  elseif($b==$minRGB)$h=1-(($r-$g)/$chroma); else $h=5-(($b-$r)/$chroma);
  return array('h'=>60*$h,'s'=>$chroma/$maxRGB,'v'=>$maxRGB);
} 

例子:

使用颜色“ DarkSalmon ”的示例:

echo '<pre><code>'. print_r( RGBtoHSV(233,150,122), true ) .'</code></pre>';

...返回:

Array
(
    [h] => 15.135135135135
    [s] => 0.47639484978541
    [v] => 0.91372549019608
)
于 2019-05-15T03:14:40.660 回答
0

我是这样做的

function convertRgbToHsv($rgb)
{

    $r = (int)substr($rgb, 0, 3) / 255;
    $g = (int)substr($rgb, 3, 3) / 255;
    $b = (int)substr($rgb, 6, 3) / 255;

    $max = max($r, $g, $b);
    $min = min($r, $g, $b);
    $delta = $max - $min;

    if (!$delta) {
        $h = 0;
    } else if ($r === $max) {
        $h = 60 * ((($g - $b) / $delta) % 6);
    } else if ($g === $max) {
        $h = 60 * ((($b - $r) / $delta) + 2);
    } else {
        $h = 60 * ((($r - $g) / $delta) + 4);
    }

    $s = !!$max ? $delta / $max : 0;

    $v = $max;

    $hsv = array("h" => $h, "s" => $s, "v" => $v);

    return $hsv;
}

参考资料链接在这里

于 2019-09-09T02:46:48.533 回答
-1

这是我对它的看法,以及一个单元测试。由于SV值是百分比,因此此代码将它们返回为整数 (0, 100) 而不是 (0, 1) - 示例,75而不是0.75.

final class MathService
{    
    /**
     * Converts an RGB point into HSV
     *
     * @param int $r
     * @param int $g
     * @param int $b
     * @return array
     */
    public function rgbToHsv(int $r, int $g, int $b): array
    {
        $rPrime = $r / 255;
        $gPrime = $g / 255;
        $bPrime = $b / 255;

        $max = max([$rPrime, $gPrime, $bPrime]);
        $min = min([$rPrime, $gPrime, $bPrime]);

        $delta = $max - $min;

        // Calculate H
        if ($delta == 0) {
            $h = 0;
        } else {
            if ($max === $rPrime) {
                $h = 60 * ((($gPrime - $bPrime) / $delta) % 6);
            }
            if ($max === $gPrime) {
                $h = 60 * ((($bPrime - $rPrime) / $delta) + 2);
            }
            if ($max === $bPrime) {
                $h = 60 * ((($rPrime - $gPrime) / $delta) + 4);
            }
        }

        // Calculate S
        if ($max == 0) {
            $s = 0;
        } else {
            $s = $delta / $max;
        }

        // Calculate V
        $v = $max;

        return [$h, (int)($s * 100), (int)($v * 100)];
    }
}

使用 PHP 7.2 的 PHPUnit 测试用例

/**
 * @test
 */
public function rgbToHsv_ComputesCorrectValues(): void
{
    $service = new MathService();
    $samples = [
        // [R, G, B, H, S, V]
        [0, 0, 0, 0, 0, 0],
        [255, 255, 255, 0, 0, 100],
        [255, 0, 0, 0, 100, 100],
        [0, 255, 0, 120, 100, 100],
        [0, 0, 255, 240, 100, 100],
        [255, 255, 0, 60, 100, 100],
        [0, 255, 255, 180, 100, 100],
        [255, 0, 255, 300, 100, 100],
        [192, 192, 192, 0, 0, 75],
        [128, 128, 128, 0, 0, 50],
        [128, 0, 0, 0, 100, 50],
        [128, 128, 0, 60, 100, 50],
        [0, 128, 0, 120, 100, 50],
        [128, 0, 128, 300, 100, 50],
        [0, 128, 128, 180, 100, 50],
        [0, 0, 128, 240, 100, 50],
    ];

    foreach ($samples as $sample) {
        list($r, $g, $b) = array_slice($sample, 0, 3);
        $expected = array_slice($sample, 3);
        $hsv = $service->rgbToHsv($r, $g, $b);
        list($h, $s, $v) = $hsv;

        self::assertEquals($expected, $hsv, "Error converting ({$r}, ${g}, ${b}). Got ({$h}, {$s}, {$v})");
    }
}
于 2018-03-25T04:01:55.880 回答