在 PHP 中生成 RGB 渐变颜色的算法
Posted
技术标签:
【中文标题】在 PHP 中生成 RGB 渐变颜色的算法【英文标题】:Algorithm to generate RGB graduated colors in PHP 【发布时间】:2012-01-03 03:20:01 【问题描述】:我对在两种给定颜色之间生成“n”个渐变颜色的算法很感兴趣,这些颜色可以在每种颜色之间生成平滑过渡。
我尝试让静态两个通道,例如 R 和 G,以及增量变化 B,但有时两种颜色之间的差异比邻居更难。
我想检查不同的算法并分析它们的弱点和优势。
我写了这段代码,看起来很合乎逻辑,但是某些颜色之间的过渡比其他颜色之间的过渡更难(例如,0 和 1 之间的过渡比 1 和 2 之间的过渡更难):
<?php
$c1 = array(128,175,27); // Color 1
$c2 = array(255,255,140); // Color 2
$nc = 5; // Number of colors to display.
$dc = array(($c2[0]-$c1[0])/($nc-1),($c2[1]-$c1[1])/($nc-1),($c2[2]-$c1[2])/($nc-1)); // Step between colors
for ($i=0;$i<$nc;$i++)
echo '<div style="width:200px;height:50px;background-color:rgb('.round($c1[0]+$dc[0]*$i).','.round($c1[1]+$dc[1]*$i).','.round($c1[2]+$dc[2]*$i).');">'.$i.'</div>'; // Output
?>
有没有更好的算法来做到这一点?
我举个例子:在上面的代码中我使用了$c1=array(192,5,248);
和$c2 = array(142,175,240);
和$nc = 10;
并得到了这个图像:
0、1、8、9的RGB值分别为:
0 = 192,5,248 1 = 186,24,247 8 = 148,156,241 9 = 142,175,240如果您看一下,相邻颜色之间存在 6、19、1 的差异。但是 0 和 1 之间的视觉过渡比 8 和 9 之间的过渡更柔和。对于 HSV 也是如此。它是一些颜色的过渡更硬或更柔和的东西。
【问题讨论】:
那么....到目前为止,您尝试了什么? “我尝试让静态两个通道,例如 R 和 G,以及增量更改 B”是什么意思?您是否保持 R 和 G 相同而只更改 B?仅当 R 和 G 在源颜色和目标颜色中相同时才有效。 是的@mcrumley,我做到了,但后来发现最好分割渠道之间的差异。请看一下添加的代码。 为什么有人反对我的问题? 【参考方案1】:在 HSV 中,生成 n 种颜色,其色调从第一种颜色到第二种颜色呈线性变化。将每个 HSV 值转换为 RGB。
【讨论】:
您能建议一种在 PHP 中执行此操作的方法吗?看看我上面的示例代码?你建议的方式比那更好吗?谢谢你的回答。 这与 PHP 无关。在 HSV 和 RGB 之间切换只是简单的算法。谷歌是你的朋友。或者,请参阅***.com/q/3597447/21727 鉴于两种 RGB 颜色,我看不到任何优势,转换为 HSV 以再次转换为 RGB。我测试了你所说的,但是以 10 为步长改变了 V 而不是 H,结果和我上面的代码完全一样。 @Memochipan - 使用 HSV 的原因是它提供了一种简单的方法来按 ROYGBIV 顺序逐步浏览颜色。同时更改 R、G 和 B 可能适用于某些颜色对,但其他颜色会在过渡期间跳过色谱。 @Memochipan - 在 HSV 中,您实际上希望同时更改 H、S 和 V 以从一种颜色过渡到另一种颜色。我最初只改变色调的建议是基于你只处理完全饱和的颜色的假设。【参考方案2】:在下图中,您可以看到我编写的一段代码的输出,它使用 RGB 和 HSV 以相等大小的步长来比较两种颜色之间的过渡:
我发现使用 HSV 的过渡会受到色调的影响,并且取决于颜色之间的距离。如果您选择具有相同色调的两种颜色,您会发现 HSV 过渡比 RGB 中更清晰,因为您只是在玩饱和度和值(黑色),而没有像 RGB 中那样添加颜色。
<?php
// Configuration.
$nc = 6; // Number of colors.
$w = 300; // Width of divs.
$a = 50; // Height of divs.
// Colors
/* In RGB */
$c1 = array(rand(0,255),rand(0,255),rand(0,255));
$c2 = array(rand(0,255),rand(0,255),rand(0,255));
//$c1 = array(128,175,27); // Color 1: Whit these colors is not change.
//$c2 = array(255,255,140); // Color 2: Whit these colors is not change.
// $c1 = array(0,0,0); // Color 1: White.
// $c2 = array(255,255,255); // Color 2: Black.
/* In HSV */
$h3 = array(rand(0,360),rand(0,100),rand(0,100));
$h4 = array(rand(0,360),rand(0,100),rand(0,100));
//$h3 = array(145,50,50); // Color 3: To see the influence of Hue.
//$h4 = array(145,0,100); // Color 4: To see the influence of Hue.
// html
$html .= '<div style="margin:auto;width:'.($w*2).'px;">';
// RGB to RGB split
$c = graduateRGB($c1,$c2,$nc);
$html .= customHTML($w,$a,$c,'RGB->RGBs');
// RGB to HSV split
$h1 = RGBtoHSV($c1);
$h2 = RGBtoHSV($c2);
$h = graduateHSV($h1,$h2,$nc);
$html .= customHTML($w,$a,$h,'RGB->HSVs');
// HSV to HSV split
$h = graduateHSV($h3,$h4,$nc);
$html .= customHTML($w,$a,$h,'HSV->HSVs');
// HSV to RGB split
$c3 = HSVtoRGB($h3);
$c4 = HSVtoRGB($h4);
$c = graduateRGB($c3,$c4,$nc);
$html .= customHTML($w,$a,$c,'HSV->RGBs');
// Output
$html .= '</div>';
echo $html;
/* FUNCIONES DE GRADUACIÓN */
// Dados dos colores RGB (0-255,0-255,0-255) y un número de colores deseados, regresa un array con todos los colores de la gradación.
function graduateRGB($c1,$c2,$nc)
$c = array();
$dc = array(($c2[0]-$c1[0])/($nc-1),($c2[1]-$c1[1])/($nc-1),($c2[2]-$c1[2])/($nc-1));
for ($i=0;$i<$nc;$i++)
$c[$i][0]= round($c1[0]+$dc[0]*$i);
$c[$i][1]= round($c1[1]+$dc[1]*$i);
$c[$i][2]= round($c1[2]+$dc[2]*$i);
return $c;
// Dados dos colores HSV (0-360,0-100,0-100) y un número de colores deseados, regresa un array con todos los colores de la gradación en RGB. (Hay un detalle con esta función y es que la transición se podría hacer por el lado contrario del círculo cromático)
function graduateHSV($h1,$h2,$nc)
$h = array();
$dh = array(($h2[0]-$h1[0])/($nc-1),($h2[1]-$h1[1])/($nc-1),($h2[2]-$h1[2])/($nc-1));
for ($i=0;$i<$nc;$i++)
$h[$i][0]= $h1[0]+$dh[0]*$i;
$h[$i][1]= $h1[1]+$dh[1]*$i;
$h[$i][2]= $h1[2]+$dh[2]*$i;
$h[$i] = HSVtoRGB($h[$i]);
return $h;
/* FUNCIONES DE CONVERSIÓN. */
// Convierte a HSV (0-360,0-100,0-100) colores en RGB (0-255,0-255,0-255).
function RGBtoHSV(array $rgb)
$f = 0.00000001; // Factor de corrección para evitar la división por cero.
list($R,$G,$B) = $rgb;
$R = $R==0?$f:$R/255;
$G = $G==0?$f:$G/255;
$B = $B==0?$f:$B/255;
$V = max($R,$G,$B);
$X = min($R,$G,$B);
$S = ($V-$X)/$V;
$V_X = $V-$X==0?$f:$V-$X;
$r = ($V-$R)/($V_X);
$g = ($V-$G)/($V_X);
$b = ($V-$B)/($V_X);
if ($R == $V)
$H = $G==$X?(5+$b):(1-$g);
elseif ($G == $V)
$H = $B==$X?(1+$r):(3-$b);
else
$H = $R==$X?(3+$g):(5-$r);
$H /= 6;
$H = round($H*360);
$S = round($S*100);
$V = round($V*100);
return array($H, $S, $V);
// Convierte a RGB (0-255,0-255,0-255) colores en HSV (0-360,0-100,0-100).
function HSVtoRGB(array $hsv)
list($H,$S,$V) = $hsv;
$H = $H/360;
$S = $S/100;
$V = $V/100;
//1
$H *= 6;
//2
$I = floor($H);
$F = $H - $I;
//3
$M = $V * (1 - $S);
$N = $V * (1 - $S * $F);
$K = $V * (1 - $S * (1 - $F));
//4
switch ($I)
case 0:
list($R,$G,$B) = array($V,$K,$M);
break;
case 1:
list($R,$G,$B) = array($N,$V,$M);
break;
case 2:
list($R,$G,$B) = array($M,$V,$K);
break;
case 3:
list($R,$G,$B) = array($M,$N,$V);
break;
case 4:
list($R,$G,$B) = array($K,$M,$V);
break;
case 5:
case 6: //for when $H=1 is given
list($R,$G,$B) = array($V,$M,$N);
break;
$R = round($R*255);
$G = round($G*255);
$B = round($B*255);
return array($R, $G, $B);
// Función con un HTML de muestra para la visualización de colores, podría ser cualquier otro.
function customHTML($w,$a,$c,$header)
$html = '<div style="float:left;text-align:center;"><h2>'.$header.'</h2>';
foreach ($c as $color)
$html .= '<div style="width:'.$w.'px;height:'.$a.'px;background-color:rgb('.$color[0].','.$color[1].','.$color[2].');">RGB '.$color[0].','.$color[1].','.$color[2].'</div>';
$html .= '</div>';
return $html;
?>
【讨论】:
以上是关于在 PHP 中生成 RGB 渐变颜色的算法的主要内容,如果未能解决你的问题,请参考以下文章