HSV的简单说明及HSV转RGB公式解释【转】

本文深入探讨HSV色彩模型,特别是色相(Hue)的原理及其在色彩表示中的作用。揭示了HSV与RGB转换的奥秘,并提供了实用的JS代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HSV是个好东西,比RGB来的直观一点,也适合人们调色。可惜对机器来说不够简单,尤其是网上大多数HSV与RGB互转的麻烦公式(被人为了性能简化过)让人摸不着头脑,现在着重介绍两个方面:

  • HSV中的hue到底是什么,为什么这么漂亮,有没有更好的方案
  • HSV转RGB公式的真面目。

HSV里的H

HSV里的H是hue,意为色相,在HSV三维中起到了改变颜色的作用。
Hue
看这很漂亮,但它怎么来的呢,先驱们是怎么想到这种能把所有颜色都表示出来的方法?

我一开始以为很复杂,后来一番研究后才发现其实异常简单,先人们为了把各种颜色都表示出来,采用了一种极其弱智的办法(误),将红,黄,绿,青,蓝,品红6种颜色均匀放在一条轴上(红在头和末尾都有出现,故一共七个点)。

红———-黄————绿————-青————蓝———–品红————-红

然后极其简单的采用线性插值的办法画出了色相!!!就是这么简单!
下面这张图能直白的表示:
hue

至此hue应该被介绍的很清楚了。

但作为有创造力的年轻人我怎么会就此收手!(误
在我看来先驱们创造的hue还有点缺陷,就是黄青还有品红似乎比红黄蓝看起来要窄一点,有的时候看起来不那么均匀。

那么有没有更好的解决方案呢???
我企图用了两种方法来产生hue:

  1. 红黄蓝三个点线性插值
  2. 红黄蓝三个点用正弦插值

然后用shadertoy画出来了,然而实际上的效果奇丑(真的奇丑)。。。。。。。

红黄蓝三个点线性插值:

红黄蓝三个点线性插值

红黄蓝三个点用正弦插值

红黄蓝三个点用正弦插值

为什么这么丑呢?后来分析是因为用RGB插值的缘故,所以肯定没有RGB中两维全满的情况,因此也就不可能出现消减三原色黄青品红中的任意一个。(逃

HSV转RGB公式的真面目

说完了hue的基本组成原理,我们看HSV转RGB公式就很轻松了。

HSV中的SV:

S是饱和度,S越高颜色掺杂的白越少。
V是明亮度,与S一样也是控制白色多少的。但!它的优先权比S更大,它控制着S能掺杂的白的灰度。

说了这些大家可能也是没懂,一张图表示一下:
HSV
重点看左边轴,之所以说V的优先级更大,就是因为当V是0的时候,S再怎么蹦跶也都是黑色。
V绝对的影响了上界,S影响了下界。

这样一看,HSV转RGB应该很简单了,看着图就能写出来。
我也不贴完整代码了,我就贴一个经常用到的,在程序中经常要我们生成多个不一样的颜色值,我们也不可能随机生成,那样容易重复,也不好看。一块现成的js代码:

function hsv(i,total){
    //hsv
    var rgb     = "";

    //I set the s and v to the highest and lowest
    var hue     = (6 * (i / total.toFixed(1)));
    var hue_int = Math.floor(hue);
    var inc     = Math.round((hue - hue_int) * 255);
    switch (hue_int) {
        case 0:
            rgb = "#" + "FF" + zero_fill(inc) + "00";
            break;
        case 1:
            rgb = "#" + zero_fill(255 - inc) + "FF" + "00";
            break;
        case 2:
            rgb = "#" + "00" + "FF" + zero_fill(inc);
            break;
        case 3:
            rgb = "#" + "00" + zero_fill(255 - inc) + "FF";
            break;
        case 4:
            rgb = "#" + zero_fill(inc) + "00" + "FF";
            break;
        case 5:
            rgb = "#" + "FF" + "00" + zero_fill(255 - inc);
            break;
        default:
            console.log(hue + ',' + hue_int);
    }
    return rgb;
}

function zero_fill(num){
    var result= Math.round(num).toString(16);
    if (result.length < 2)
        result="0"+result;
    return result;
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

给定一个目前值,一个最大值就能生成一个在hue’轴上对应的RGB值,我在我期末大作业和自己无聊做的小游戏(knocker.xyz)中都用到了这种方法(屡试不爽,真香)
knocker.xyz

				<script>
					(function(){
						function setArticleH(btnReadmore,posi){
							var winH = $(window).height();
							var articleBox = $("div.article_content");
							var artH = articleBox.height();
							if(artH > winH*posi){
								articleBox.css({
									'height':winH*posi+'px',
									'overflow':'hidden'
								})
								btnReadmore.click(function(){
									articleBox.removeAttr("style");
									$(this).parent().remove();
								})
							}else{
								btnReadmore.parent().remove();
							}
						}
						var btnReadmore = $("#btn-readmore");
						if(btnReadmore.length>0){
							if(currentUserName){
								setArticleH(btnReadmore,3);
							}else{
								setArticleH(btnReadmore,1.2);
							}
						}
					})()
				</script>
				</article>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值