How to fade color

后端 未结 8 1299
我寻月下人不归
我寻月下人不归 2021-02-06 05:56

I would like to fade the color of a pixel out toward white, but obviously maintain the same color. If I have a pixel (200,120,40), will adding 10 to each value to m

相关标签:
8条回答
  • 2021-02-06 06:22

    It's not that simple because in your monitor each color channel is weighted differently. I'd say the best bet is to do this in scikit image by converting to gray, dimming or brightening, and then back-converting to color. Scikit-image will take care of keeping the colors straight.

    from skimage.color import gray2rgb, rgb2gray
    scale_factor = 0.9 #90 percent
    img_new = gray2rgb(rgb2gray(img) * scale_factor)
    

    If you want to work directly with hue, saturation and value, check out this example:

    http://scikit-image.org/docs/dev/auto_examples/plot_tinting_grayscale_images.html

    0 讨论(0)
  • 2021-02-06 06:25

    The question, "to fade the color of a pixel out toward white" (not some shade of gray), is really about mixing the original pixel color with white, going from 100% original color and 0% white to 0% original color and 100% white. There's not more to it. Doing this in, for example, 101 steps would look like this:

    r0= 200; // as in the question
    g0= 120;
    b0=  40;
    for(i= 100; i >= 0; i--){
      r= (i * r0 + (100 - i) * 255) / 100;
      g= (i * g0 + (100 - i) * 255) / 100;
      b= (i * b0 + (100 - i) * 255) / 100;
      // use this color (r, g, b) somehow
    }
    
    0 讨论(0)
  • 2021-02-06 06:28

    Simply linearly interpolate between your color and white:

    def lerp(a, b, t):
        return a*(1 - t) + b*t
    
    import numpy as np
    white = np.array([255, 255, 255])
    my_color = np.array([...])
    lightened25 = lerp(my_color, white, 0.25)
    

    Or without numpy:

    lightened25 = [lerp(c, w, 0.25) for c, w in zip(my_color, white)]
    
    0 讨论(0)
  • 2021-02-06 06:28

    As MarkM suggested, HSB (or HSL) is a simple method for doing this, but will not give perfect hue constance. If this is good enough (I assume you want your own method instead of a module) then this page has code for doing it.

    In python it would look like this:

    def rgb_to_hsl(rgb):
        '''
        Converts an rgb (0..255) tuple to hsl
        '''
        r, g, b = rgb
    
        _r = r / 255                     # RGB in percentage
        _g = g / 255
        _b = b / 255
    
        rgbMin = min(_r, _g, _b)    
        rgbMax = max(_r, _g, _b)
        rgbDelta = rgbMax - rgbMin
    
        l = ( rgbMax + rgbMin ) / 2
    
        if rgbDelta == 0:                        #Greyscale
            h = 0
            s = 0
        else:                                    # Chromatic data...
            if l < 0.5: s = rgbDelta / (rgbMax + rgbMin)
            else:       s = rgbDelta / (2 - rgbMax - rgbMin)
    
            deltaR = (((rgbMax - _r) / 6) + rgbDelta/2) / rgbDelta
            deltaG = (((rgbMax - _g) / 6) + rgbDelta/2) / rgbDelta
            deltaB = (((rgbMax - _b) / 6) + rgbDelta/2) / rgbDelta
    
            if   _r == rgbMax: h = deltaB - deltaG
            elif _g == rgbMax: h = 1/3 + deltaR - deltaB
            elif _b == rgbMax: h = 2/3 + deltaG - deltaR
    
            if h < 0: h += 1
            if h > 1: h -= 1
    
        return (h, s, l)
    
    def hsl_to_rgb(hsl):
        '''
        Converts a hsl tuple to rgb(0..255)
        '''
        h, s, l = hsl
        if s == 0:                      #Greyscale
            r = l * 255
            g = l * 255
            b = l * 255
        else:
            if l < 0.5: var_2 = l * (1 + s)
            else:       var_2 = l + s - (s * l)
    
            var_1 = 2 * l - var_2
    
            r = 255 * hue_to_RGB(var_1, var_2, h + 1/3)
            g = 255 * hue_to_RGB(var_1, var_2, h)
            b = 255 * hue_to_RGB(var_1, var_2, h - 1/3)
        return r, g, b   
    
    def hue_to_RGB (v1, v2, vH):
        '''
        Helper for hsl_to_rgb
        '''
        if vH < 0: vH += 1
        if vH > 1: vH -= 1
        if (6 * vH) < 1: return v1 + (v2 - v1) * 6 * vH
        if (2 * vH) < 1: return v2
        if (3 * vH) < 2: return v1 + (v2 - v1) * 6 * (2/3 - vH)
        return v1
    

    Then to brighten:

    def lighten(rgb):
        '''
        Given RGB values, returns the RGB values of the same colour slightly
        brightened (towards white) 
        '''
        h,s, l = rgb_to_hsl(rgb)
        l = min(l+0.1, 1)              #limit to 1
        return hsl_to_rgb((h, s, l))
    

    The benefit of this method is that the increment is a percentage of the total brightness. Modifying this to take the percentage as an input would be trivial.

    You can reverse engineer the mathematical equations form this code, or see HSL to RGB.

    0 讨论(0)
  • 2021-02-06 06:30

    You might want to check out this answer by denis:

    RGB -> ^gamma -> Y -> L*

    In color science, the common RGB values, as in html rgb( 10%, 20%, 30% ), are called "nonlinear" or Gamma corrected. "Linear" values are defined as

    Rlin = R^gamma,  Glin = G^gamma,  Blin = B^gamma
    

    where gamma is 2.2 for many PCs. The usual R G B are sometimes written as R' G' B' (R' = Rlin ^ (1/gamma)) (purists tongue-click) but here I'll drop the '.

    Brightness on a CRT display is proportional to RGBlin = RGB ^ gamma, so 50% gray on a CRT is quite dark: .5 ^ 2.2 = 22% of maximum brightness. (LCD displays are more complex; furthermore, some graphics cards compensate for gamma.)

    To get the measure of lightness called L* from RGB, first divide R G B by 255, and compute

    Y = .2126 * R^gamma + .7152 * G^gamma + .0722 * B^gamma
    

    This is Y in XYZ color space; it is a measure of color "luminance". (The real formulas are not exactly x^gamma, but close; stick with x^gamma for a first pass.)

    Finally, L* = 116 * Y ^ 1/3 - 16 "... aspires to perceptual uniformity ... closely matches human perception of lightness." -- Wikipedia Lab color space

    0 讨论(0)
  • 2021-02-06 06:31

    @mark-meyer's answer is good, I answered a similar question on the StackMathematica section in great detail with examples PartOne and Part Two.

    For THIS question, gradient to full white, here are examples using my gradient explorer:

    Left column is staying in sRGB, next is linear xyY, then LAB, and far right is LAB LCh

    You'll notice that remaining in sRGB is not substantially different than using L*a*b* in most cases. This is partly because sRGB has a gamma curve that is different but similar to the perception curve of LAB.

    You'll notice though that the LCh version has some hue shifts, depending on the starting color. In the case of purple, it requires some offsets near the mid range.

    Also with LCh, the direction (clock wise or CCW) of hue rotation makes a difference.

    Looking just at the for right LCh, here is magenta start, with no offsets, and the natural rotation:

    Same rotation direction, but some offsets to smooth the LCh gradient.

    Reversing the hue rotation and different offsets we go through purple instead of orange for LCh:

    And here's from yellow, the LCh gets a green tinge without adjusting the hue offset:

    But offsetting the mid hue smooths the LCh gradient:

    And finally. BLUE is tricky with L*a*b* as it often wants to shift to purple. On the other hand, in LCh blue wants to shift to cyan:

    So in truth you can typically stay in sRGB for things like gradients to white, but for gradients between two saturated colors you might prefer to use LCh:

    So here where colors get closer to 180° apart, the middle gets desaturated for both sRGB and LAB, as the average value in the middle is a grey - a darker murky grey for sRGB and a lighter grey for LAB. But LCh maintains saturation and instead rotates through the hues.

    0 讨论(0)
提交回复
热议问题