【问题标题】:Color overlay in android NDKandroid NDK中的颜色叠加
【发布时间】:2012-10-14 11:36:13
【问题描述】:

我想实现色相/颜色/饱和度颜色叠加。 我看到了宏:

#define ColorBlend_Saturation(T,A,B) ColorBlend_Hls(T,A,B,HueA,LuminationA,SaturationB)

我试图在 Adob​​e Photoshop 中使用颜色 #332244#557711 重现它,以获得结果颜色 - #431076。然而,在应用这些宏之后,我得到了颜色 - #320C59

问题 1:如何重现 Photoshop 的色调、饱和度和颜色算法?

问题 2:如何调整 Alpha 通道?例如,在我的颜色和光学 == 50 上,这应该在 photoshop 中 - #3b195d

【问题讨论】:

  • gamedev.net/blog/862/… - 思路一样,看算法的表达式。
  • 不,我知道这些算法。我想要颜色/饱和度/色调算法
  • 我认为我可以使用 ((uint8_t)(O * A + (1 - O) * B)) 添加 alpha 通道,但我不知道如何调整饱和度/色调/颜色混合
  • cs.rit.edu/~ncs/color/t_convert.html 怎么样 - 这里是 RGB 到 HSV 和反向的转换。您可以使用 RGB,然后将它们转换或相反,甚至可以使用 HSV 在您的算法中重新设计这些算法。
  • 罗丽丝,我知道。目前我实现了这些混合模式。但。如何设置 Alpha 通道?因为 adobe-photoshop 颜色不同于 ((uint8_t)(O * A + (1 - O) * B)) 混合。

标签: android c++ bitmap android-ndk


【解决方案1】:

问题 1:

Photoshop 的色相、饱和度、颜色和亮度混合模式基于色彩空间,其尺寸被 HSL 和 HSV 文章称为色相、色度和亮度。注意这个空间与HSL和HSV都不同,只有hue维度是三者共享的;有关详细信息,请参阅该文章。

色调混合模式保留底层的亮度和色度,同时采用顶层的色调。

饱和度混合模式保留底层的亮度和色调,同时采用顶层的色度。

颜色混合模式保留底层的亮度,同时采用顶层的色调和色度。

来自http://en.wikipedia.org/wiki/Blend_modes

经过 3 个多小时的试验,我成功将 HSV -> RGB 转换器升级为可以工作的饱和度混合器。其他混合模式应该类似。

代码如下:

#include <cmath>
#include <iostream>

using namespace std;

struct HSVColor
{
    float H,S,V;
};

struct RGBColor
{
    float R,G,B;
    RGBColor() = default;
    RGBColor(int r,int g, int b):
        R(r/255.0),
        G(g/255.0),
        B(b/255.0)
    {
    }
};

HSVColor RGBToHSV(const RGBColor& RGB)
{
    float Max;
    float Min;
    float Chroma;
    HSVColor HSV;

    Min = min(min(RGB.R, RGB.G), RGB.B);
    Max = max(max(RGB.R, RGB.G), RGB.B);
    Chroma = Max - Min;

    //If Chroma is 0, then S is 0 by definition, and H is undefined but 0 by convention.
    if(Chroma != 0)
    {
        if(RGB.R == Max)
        {
            HSV.H = (RGB.G - RGB.B) / Chroma;

            if(HSV.H < 0.0)
            {
                HSV.H += 6.0;
            }
        }
        else if(RGB.G == Max)
        {
            HSV.H = ((RGB.B - RGB.R) / Chroma) + 2.0;
        }
        else //RGB.B == Max
        {
            HSV.H = ((RGB.R - RGB.G) / Chroma) + 4.0;
        }

        HSV.H *= 60.0;
        HSV.S = Chroma / Max;
    }

    HSV.V = Max;

    return HSV;
}

RGBColor Saturate(const HSVColor& HSV,const HSVColor& overlay)
{
    float os = overlay.S;
    float ov = overlay.V;

    float Min;
    float Chroma;
    float Hdash;
    float X;
     RGBColor RGB{0,0,0};

    Chroma = os * ov; // Orginal was HSV.S * HSV.V
    Hdash = HSV.H / 60.0;
    X = Chroma * (1.0 - abs(fmod(Hdash , 2.0) - 1.0));

    if(Hdash < 1.0)
    {
        RGB.R = Chroma;
        RGB.G = X;
    }
    else if(Hdash < 2.0)
    {
        RGB.R = X;
        RGB.G = Chroma;
    }
    else if(Hdash < 3.0)
    {
        RGB.G = Chroma;
        RGB.B = X;
    }
    else if(Hdash < 4.0)
    {
        RGB.G= X;
        RGB.B = Chroma;
    }
    else if(Hdash < 5.0)
    {
        RGB.R = X;
        RGB.B = Chroma;
    }
    else if(Hdash <= 6.0)
    {
        RGB.R = Chroma;
        RGB.B = X;
    }

    Min = ov - Chroma; // Orginal was HSV.V - Chroma

    RGB.R += Min;
    RGB.G += Min;
    RGB.B += Min;

    return RGB;
}

int main(){
    RGBColor base{51, 34, 68};
    RGBColor overly{85, 119, 17};

    RGBColor r = Saturate(RGBToHSV(base),RGBToHSV(overly));

    cout << int(r.R*255) << endl;
    cout << int(r.G*255) << endl;
    cout << int(r.B*255) << endl;
}

原始 HSV RGB 转换器代码:http://wiki.beyondunreal.com/HSV-RGB_Conversion

问题 2。

使用饱和度,这实际上很容易,在饱和度混合后,在 rgb 颜色空间中使用正常的 alpha 混合。

RGBColor base;
RGBColor overly;    
RGBColor saturated = Saturate(base,overly);
RGBColor result = AlphaBlend(base,saturated,overly.alpha);

注意:这可能不适用于其他混合模式。

【讨论】:

    【解决方案2】:

    以下是不同 Photoshop 混合模式的方程式:

        inline float Blend_Normal( float Base, float Overlay )
        {
            return Base;
        }
        inline float Blend_Lighten( float Base, float Overlay )
        {
            return ( Overlay > Base ) ? Overlay : Base;
        }
        inline float Blend_Darken( float Base, float Overlay )
        {
            return ( Overlay > Base ) ? Base : Overlay;
        }
        inline float Blend_Multiply( float Base, float Overlay )
        {
            return Base * Overlay;
        }
        inline float Blend_Average( float Base, float Overlay )
        {
            return ( Base + Overlay ) / 2.0f;
        }
        inline float Blend_Add( float Base, float Overlay )
        {
            return LMin( Base + Overlay, 1.0f );
        }
        inline float Blend_Subtract( float Base, float Overlay )
        {
            return LMax( Base + Overlay - 1.0f, 0.0f );
        }
        inline float Blend_Difference( float Base, float Overlay )
        {
            return fabs( Base - Overlay );
        }
        inline float Blend_Negation( float Base, float Overlay )
        {
            return 1.0f - fabs( 1.0f - Base - Overlay );
        }
        inline float Blend_Screen( float Base, float Overlay )
        {
            return 1.0f - ( 1.0f - Base ) * ( 1.0f - Overlay );
        }
        inline float Blend_Exclusion( float Base, float Overlay )
        {
            return Base + Overlay - 2 * Base * Overlay;
        }
        inline float Blend_Overlay( float Base, float Overlay )
        {
            return ( Overlay < 0.5f ) ? ( 2.0f * Base * Overlay ) : ( 2.0f * Base - 1.0f ) * ( 1.0f - Overlay );
        }
        inline float Blend_SoftLight( float Base, float Overlay )
        {
            return ( Overlay < 0.5f ) ? ( Base + 0.5f ) * Overlay : ( Base - 0.5f ) * ( 1.0f - Overlay );
        }
        inline float Blend_HardLight( float Base, float Overlay )
        {
            return Blend_Overlay( Overlay, Base );
        }
        inline float Blend_ColorDodge( float Base, float Overlay )
        {
            return ( Overlay > 1.0f - Math::EPSILON ) ? Overlay : LMin( 1.0f, Base / ( 1.0f - Overlay ) );
        }
        inline float Blend_ColorBurn( float Base, float Overlay )
        {
            return ( Overlay < Math::EPSILON ) ? Overlay : LMax( 0.0f, 1.0f - ( 1.0f - Base ) / Overlay );
        }
        inline float Blend_LinearDodge( float Base, float Overlay )
        {
            return Blend_Add( Base, Overlay );
        }
        inline float Blend_LinearBurn( float Base, float Overlay )
        {
            return Blend_Subtract( Base, Overlay );
        }
        inline float Blend_LinearLight( float Base, float Overlay )
        {
            return ( Overlay < 0.5f ) ? Blend_LinearBurn( Base, 2 * Overlay ) : Blend_LinearDodge( Base, ( 2 * ( Overlay - 0.5f ) ) );
        }
        inline float Blend_VividLight( float Base, float Overlay )
        {
            return ( Overlay < 0.5f ) ? Blend_ColorBurn( Base, 2 * Overlay ) : Blend_ColorDodge( Base, ( 2 * ( Overlay - 0.5f ) ) );
        }
        inline float Blend_PinLight( float Base, float Overlay )
        {
            return ( Overlay < 0.5f ) ? Blend_Darken( Base, 2 * Overlay ) : Blend_Lighten( Base, ( 2 * ( Overlay - 0.5f ) ) );
        }
        inline float Blend_HardMix( float Base, float Overlay )
        {
            return ( Blend_VividLight( Base, Overlay ) < 0.5f ) ? 0.0f : 1.0f;
        }
        inline float Blend_Reflect( float Base, float Overlay )
        {
            return ( Overlay  > 1.0f - Math::EPSILON ) ? Overlay : LMin( 1.0f, Base * Base / ( 1.0f - Overlay ) );
        }
        inline float Blend_Glow( float Base, float Overlay )
        {
            return Blend_Reflect( Overlay, Base );
        }
        inline float Blend_Phoenix( float Base, float Overlay )
        {
            return LMin( Base, Overlay ) - LMax( Base, Overlay ) + 1.0f;
        }
    

    来自Linderdaum Engine SDK

    【讨论】:

    • 不不不!我是什么颜色/色调/饱和度与 alpha 混合。你可以在 photoshop/gimp/pixelmator 中重现这个:创建一个基础层并填充它,创建一个新层并填充它。下一步 - 将图层叠加层从正常更改为颜色并进行光学更改。颜色层可以使用 HSV/HSL 来实现。但我不明白如何在光学上实现。
    猜你喜欢
    • 2011-12-29
    • 1970-01-01
    • 2017-01-04
    • 2017-08-01
    • 1970-01-01
    • 2011-11-19
    • 2014-06-09
    • 2014-11-30
    • 1970-01-01
    相关资源
    最近更新 更多