HSL Interpolation

*爱你&永不变心* 提交于 2019-12-10 19:42:57

问题


If the hue component of my HSL color is in degrees, how can I correctly interpolate between two hues? Using (h1 + h2) / 2 does not seem to produce desirable results in all cases. Here are two examples that illustrate why:

Let:

red = 0°
yellow = 60°
blue = 240°

(red + yellow) / 2 = 30° (orange)
(yellow + blue) / 2 = 150° (blue green)
(red + blue) / 2 = 120° (green)

As you can see, averaging red and blue produces green instead purple/magenta! However, if we let:

red = 360°
yellow = 60°
blue = 240°

(red + yellow) / 2 = 210° (blue green)
(yellow + blue) / 2 = 150° (blue green)
(red + blue) / 2 = 300° (magenta)

Now, red and blue produce the expected color, but red and yellow produce a blue green color! In what way can I interpolate the hue component of the color so that the result matches what would be expected of mixing actual paint? Thanks!


回答1:


You're basically doing this right to get what I assume you want, which is a color that looks midrange between your two inputs, but you just need to deal with the fact that this calculation is done on a circle which wraps. (I assume that you don't really want "mixing like paint" but just a midrange color -- i.e. you don't want red and green to give brown, right?)

Here's a Python function that will pick the angle between two angles on a circle. It basically just tries the two options (adding 360 or not) and picks the one that gives the angle closest to the original angles:

pairs = [(0, 60), (60, 239), (60, 241), (0, 240), (350, 30)]

def circ_ave(a0, a1):
    r = (a0+a1)/2., ((a0+a1+360)/2.)%360 
    if min(abs(a1-r[0]), abs(a0-r[0])) < min(abs(a0-r[1]), abs(a1-r[1])):
        return r[0]
    else:
        return r[1]

for a0, a1 in pairs:
    print a0, a1, circ_ave(a0, a1)

produces:

0 60    30.0
60 239  149.5  # 60, 240 is ambiguous
60 241  330.5
0 240   300.0
350 30  10.0

(I feel there should be an easier way to do this calculation, but it didn't occur to me.)




回答2:


You probably didn't want to hear this, but convert to RGB, interpolate and convert back.

edit: just saw "would be expected of mixing actual paint"

In that case you probably want to convert to CMY colour space rather than RGB. Have a look at colour mixing on Wikipedia.




回答3:


For every color value x, x < 360, it could be x or x+360. You then have 4 pairs of color values. If you find the smallest distance pair, then use the pair to interpolate the color. It might give you the right visual effect.

For example,

red = 0° or 360°
yellow = 60° or 420°
blue = 240° or 600°

the smallest distance of red and yellow is 60(red 0 yellow 60), so the interpolation should be 30.
the smallest distance of yellow and blue is 180(yellow 60 blue 240), so the interpolation should be 150.
the smallest distance of red and blue is 60(red 360 blue 240), so the interpolation should be 300.



来源:https://stackoverflow.com/questions/1416560/hsl-interpolation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!