Colors 从RGB获取色调的最快公式

Colors 从RGB获取色调的最快公式,colors,rgb,Colors,Rgb,如果给定的红色、绿色和蓝色值范围在0-255之间,那么获得色调值的最快计算方法是什么?这个公式将以30fps(每秒920万次)的速度用于640x480图像的每个像素,因此每一点速度优化都会有所帮助 我见过其他的公式,但我不满意它们涉及多少步骤。我在寻找一个实际的公式,而不是一个内置的库函数 将RGB值转换为范围0-1,可通过将该值除以255获得8位颜色深度(r、g、b-为给定值): 求R、G和B的最小值和最大值 取决于RGB颜色通道的最大值。这三个不同的公式是: 如果红色为最大值,则Hue

如果给定的红色、绿色和蓝色值范围在0-255之间,那么获得色调值的最快计算方法是什么?这个公式将以30fps(每秒920万次)的速度用于640x480图像的每个像素,因此每一点速度优化都会有所帮助

我见过其他的公式,但我不满意它们涉及多少步骤。我在寻找一个实际的公式,而不是一个内置的库函数

  • 将RGB值转换为范围0-1,可通过将该值除以255获得8位颜色深度(r、g、b-为给定值):

  • 求R、G和B的最小值和最大值

  • 取决于RGB颜色通道的最大值。这三个不同的公式是:

    • 如果红色为最大值,则
      Hue=(G-B)/(max-min)
    • 如果绿色为最大值,则
      Hue=2.0+(B-R)/(max-min)
    • 如果蓝色为最大值,则
      Hue=4.0+(R-G)/(max-min)
  • 需要将得到的色调值乘以60,才能将其转换为颜色圆上的度数。如果色调变为负值,则需要添加360度,因为圆有360度

    以下是。

    您必须指定您使用的语言和平台,因为C#、Java和C是非常不同的语言,它们之间以及不同平台之间的性能也不同。这个问题现在太广泛了

    640×480与当前常用分辨率相比不是很大,但“最快”是主观的,您需要仔细进行基准测试,以选择最适合您的用例。由于指令周期不是固定的,而且还有许多其他因素会影响性能,例如缓存一致性和分支(mis)预测,因此看起来更长、步骤更多的算法并不一定比更短的算法慢

    对于上面提到的算法Umriyaev,您可以,这将在一个微小的可接受错误的情况下提高性能


    但是最好的方法是在某种程度上涉及到,因为现代CPU有多个内核,而且还可以加速数学和多媒体操作。例如x86具有SSE/AVX/AVX-512。。。它可以同时在8/16/32频道上执行操作。结合多线程、硬件加速、GPU计算。。。。这比这个问题的任何答案都好

    在C#和Java中,过去没有太多的矢量化选项,因此对于较旧的.NET和JVM版本,您需要在C#中运行不安全的代码。在Java中,您可以通过JNI运行本机代码。但是现在它们都有矢量化的数学支持。Java中有一个新的矢量API。在Mono中,可以在中使用向量类型。在琉璃城有一家餐馆。在.NET1.6+中,有包括和其他

    。。。启用SIMD的向量类型,包括向量2、向量3、向量4、矩阵x3x2、矩阵x4x4、平面和四元数


    除了乌姆里亚耶夫的回答:

    如果只需要色调,则不需要将0-255范围内的颜色除以255

    e.x.
    (绿-蓝)/(最大-最小)
    的结果在任何范围内都是相同的(当然,只要颜色在相同的范围内)

    下面是获取色调的java示例:

    public int getHue(int红色、int绿色、int蓝色){
    float min=Math.min(Math.min(红色、绿色)、蓝色);
    float max=Math.max(Math.max(红色、绿色)、蓝色);
    如果(最小值==最大值){
    返回0;
    }
    浮动色调=0f;
    如果(最大==红色){
    色调=(绿色-蓝色)/(最大-最小值);
    }否则如果(最大==绿色){
    色调=2f+(蓝-红)/(最大-最小);
    }否则{
    色调=4f+(红-绿)/(最大-最小);
    }
    色调=色调*60;
    如果(色调<0)色调=色调+360;
    返回Math.round(色调);
    }
    
    编辑:添加了检查最小值和最大值是否相同,因为在这种情况下不需要计算的其余部分,并避免被0除(请参见注释)

    编辑:修复了java错误

    //将rgb值转换为0-1的范围
    var h;
    r/=255,g/=255,b/=255;
    //从r、g、b分量中找出最小值和最大值
    var max=Math.max(r,g,b),min=Math.min(r,g,b);
    如果(最大==r){
    //如果红色是主要的颜色
    h=(g-b)/(最大-最小值);
    }
    否则,如果(最大==g){
    //如果绿色是最主要的颜色
    h=2+(b-r)/(最大-最小值);
    }
    否则如果(最大==b){
    //如果蓝色是最主要的颜色
    h=4+(r-g)/(最大-最小值);
    }
    h=h*60;//找到颜色所属的60度扇区
    // https://www.pathofexile.com/forum/view-thread/1246208/page/45 -色轮
    如果(h>0){
    //h是色轮中的正角度
    返回数学楼层(h);
    }
    否则{
    //h是一个负角度。
    返回数学楼层(360-h);
    }
    
    该网页涵盖了这一点,但它包含我认为是错误的内容。它规定色调计算要除以max-min,但是如果除以该分数,值会增加,并且很容易超过-1到5的完整预期范围。我发现乘以max-min可以像预期的那样工作

    与此相反:

    If Red is max, then Hue = (G-B)/(max-min)
    If Green is max, then Hue = 2.0 + (B-R)/(max-min)
    If Blue is max, then Hue = 4.0 + (R-G)/(max-min)
    
    我建议:

    If Red is max, then Hue = (G-B)*(max-min)
    If Green is max, then Hue = 2.0 + (B-R)*(max-min)
    If Blue is max, then Hue = 4.0 + (R-G)*(max-min)
    

    我看过那篇文章,这就是我目前使用的方法。我希望有更快的方法…我看到了另一种使用tan的方法,但我想当前的方法比我想象的要快,虽然应该是256而不是255,但我想我现在明白了。假设只有两种颜色0和1。如果我除以2,我会得到0和0.5,所以我应该除以颜色数减1。有人能解释一下
    2.0+
    4.0+
    部分实现了什么,因为
    (x-y)/(max-min)
    产生的最大值是1,而不是2吗?@Sphynx注意
    x-y
    可以是正的,也可以是负的,所以
    (x-y)/(最大值-最小值)
    的范围是从-1到1,而不是从0到1。如果您只需要计算
    If Red is max, then Hue = (G-B)*(max-min)
    If Green is max, then Hue = 2.0 + (B-R)*(max-min)
    If Blue is max, then Hue = 4.0 + (R-G)*(max-min)