简体   繁体   English

计算 HSP 颜色的问题 model

[英]Issues calculating HSP color model

[Intro] [介绍]

HSP color model is a made-up color model created in 2006. It uses the same values as HSV for Hue and Saturation but, for calculating the P (perceived brightness), it uses Weighted Euclidean norm of the [R, G, B] vector. HSP 颜色 model 是 2006 年创建的合成颜色 model。它使用与 HSV 相同的色相和饱和度值,但为了计算 P(感知亮度),它使用 [R, G, B] 的加权欧几里得范数向量。 More info: https://alienryderflex.com/hsp.html更多信息: https://alienryderflex.com/hsp.html

As you can see, at the bottom of the website, there are formulas for calculating between RGB and HSP that I've taken and re-formatted for Python.如您所见,在网站的底部,有我为 Python 重新格式化后计算 RGB 和 HSP 的公式。

[Issues] [问题]

In some places, I found that for calculating the Perceived brightness, you need to first linearize the RGB channels (assuming it's sRGB) but if you do so, then the formulas no longer work.在某些地方,我发现为了计算感知亮度,您需要首先线性化 RGB 通道(假设它是 sRGB),但如果您这样做,那么公式将不再有效。 For that reason, I'm not doing that and applying the formulas directly on the input RGB color.出于这个原因,我没有这样做,而是直接将公式应用于输入的 RGB 颜色。 Also, I found in a js library someone made it so the perceived brightness is in range 0-255.此外,我在一个 js 库中发现有人制作了它,因此感知亮度在 0-255 范围内。 I don't know where they got that idea, but it should be in range 0-100 (percentage).我不知道他们从哪里得到这个想法,但它应该在 0-100(百分比)范围内。

[Where it all goes wrong] [哪里出了问题]

I don't have any issues with calculating from RGB to HSP.我对从 RGB 到 HSP 的计算没有任何问题。 The problem is when calculating RGB from HSP.问题是从 HSP 计算 RGB 时。 I won't bother you with the full code since you can take it from the link above but I'm giving you a snippet of the part that doesn't work correctly (or I have a mistake that I can't find).我不会用完整的代码来打扰你,因为你可以从上面的链接中获取它,但我给你的是无法正常工作的部分片段(或者我有一个我找不到的错误)。

PS: After further investigation, it turns out that more than just this snippet gives false results! PS:经过进一步调查,事实证明不仅仅是这个片段给出了错误的结果!

elif H < 4 / 6:  # B > G > R
    H = 6 * (-H + 4 / 6)
    B = (P ** 2 / (Pb + Pg * H ** 2)) ** 0.5
    G = B * H
    R = 0

This is the part where Saturation is 100%.这是饱和度为 100% 的部分。 The problem is that when you pass it these values HSP(253, 100, 50), or any similar ones, the resulting blue is beyond the acceptable range (in this case 356).问题是,当您将这些值 HSP(253, 100, 50) 或任何类似值传递给它时,生成的蓝色超出了可接受的范围(在本例中为 356)。 I tried clamping the values to 255 but then when doing the RGB to HSV conversion, the values don't match so the problem isn't there.我尝试将值限制为 255,但是在进行 RGB 到 HSV 转换时,值不匹配,因此问题不存在。

Any ideas?有任何想法吗?

So, I found a mistake in my code which brought down the out-of-range values from 300+ to a maximum of 261 which is acceptable to be clamped at 255 (for 8-bit colors) without needing to do anything to the other values.因此,我在我的代码中发现了一个错误,该错误将超出范围的值从 300+ 降低到最大值 261,这可以被限制在 255(对于 8 位颜色)而无需对另一个进行任何操作值。 No values need to be clamped on the black side.不需要在黑色侧限制任何值。

Here's my simplified version of the calculation with comments:这是我的带有注释的计算的简化版本:

def hsp_to_rgb(HSP: tuple | list, depth: int = 8, normalized: bool = False):
    """### Takes an HSP color and returns R, G, B values.

    #### N/B: All examples below are given for 8-bit color depth that has range 0-255. \
        If you want to use this function with a different depth the actual range is 0-(max value for bit depth).

    ### Args:
        `color` (tuple | list): Either int in range 0-255 or float in range 0-1 
        `depth` (int): The bit depth of the input RGB values. Defaults to 8-bit (range 0-255)
        `normalized` (bool, optional): Returns the values in range 0-1. Defaults to False.

    Reference: http://alienryderflex.com/hsp.html

    ### Returns:
        list[int, int, int] | list[float, float, float]: (H, S, P)
    """
    H, S, P = HSP[0]/360, HSP[1]/100, HSP[2]/100
    max_value = 2 ** depth - 1

    def wrap(HSP: tuple | list, c1: float, c2: float, c3: float, S1: bool):
        """### This is an internal helper function for the hsp_to_rgb function to lift off some of the calculations.
        c1, c2, c3 - Pr, Pg, Pb in different order

        ### Args:
            `HSP` (tuple | list): Hue, Saturation, Perceived brightness in range 0-1
            `c1` (float): Constant. Either 0.299, 0.587 or 0.114
            `c2` (float): Constant. Either 0.299, 0.587 or 0.114
            `c3` (float): Constant. Either 0.299, 0.587 or 0.114
            `S1` (bool): Whether S (Saturation) is 1 (100%). Defaults to False

        ### Returns:
            tuple[float, float, float]: R, G, B values in different order depending on the constants.
        """
        if S1:
            ch1 = (HSP[2] ** 2 / (c1 + c2 * HSP[0] ** 2)) ** 0.5
            ch2 = ch1 * HSP[0]
            ch3 = 0
            return ch3, ch1, ch2

        min_over_max = 1 - HSP[1]
        part = 1 + HSP[0] * (1 / min_over_max - 1)
        ch1 = HSP[2] / (c1 / min_over_max ** 2 + c2 * part ** 2 + c3) ** 0.5
        ch2 = ch1 / min_over_max
        ch3 = ch1 + HSP[0] * (ch2 - ch1)
        return ch1, ch2, ch3

    # Get weights constants
    Pr, Pg, Pb = 0.299, 0.587, 0.114

    # Calculate R, G, B based on the Hue
    if H < 1 / 6:  # R > G > B
        H = 6 * H
        B, R, G = wrap((H, S, P), Pr, Pg, Pb, S >= 1)
    elif H < 2 / 6:  # G > R > B
        H = 6 * (-H + 2 / 6)
        B, G, R = wrap((H, S, P), Pg, Pr, Pb, S >= 1)
    elif H < 3 / 6:  # G > B > R
        H = 6 * (H - 2 / 6)
        R, G, B = wrap((H, S, P), Pg, Pb, Pr, S >= 1)
    elif H < 4 / 6:  # B > G > R
        H = 6 * (-H + 4 / 6)
        R, B, G = wrap((H, S, P), Pb, Pg, Pr, S >= 1)
    elif H < 5 / 6:  # B > R > G
        H = 6 * (H - 4 / 6)
        G, B, R = wrap((H, S, P), Pb, Pr, Pg, S >= 1)
    else:            # R > B > G
        H = 6 * (-H + 1)
        G, R, B = wrap((H, S, P), Pr, Pb, Pg, S >= 1)

    return [min(i, 1.0) for i in (R, G, B)] if normalized else [min(i*max_value, 255) for i in (R, G, B)]

This works pretty well and the conversions are really accurate.这非常有效,转换非常准确。 Note that in order to get perfect conversions, you'll need to use an exact floating-point number for the calculations.请注意,为了获得完美的转换,您需要使用精确的浮点数进行计算。 Otherwise, you'll get a number of overlapping values due to limitations of the system.否则,由于系统的限制,您将获得许多重叠的值。 Ex.前任。 RGB = 256 * 256 * 256 = 16 777 216 colors, whereas HSP = 360 * 100 * 100 = 3 600 000 unique colors. RGB = 256 * 256 * 256 = 16 777 216 colors,而 HSP = 360 * 100 * 100 = 3 600 000 个独特的 colors。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM