¿Cómo fusiona Photoshop dos imágenes juntas? [cerrado]


84

¿Alguien podría explicar cómo Photoshop combina dos imágenes para que pueda reproducir los mismos efectos en mi aplicación?


3
Definitivamente, esta no es una pregunta sobre hardware o software informático en general. Se trata de algoritmos, C ++ y procesamiento de imágenes. Este tipo de pregunta está explícitamente permitido y fomentado activamente
Panagiotis Kanavos

Después de 8 años de generar clics en este sitio, ¿se considera fuera de tema solo ahora?
Nathan Moinvaziri

Todo lo que necesita son 5 votos cercanos de personas con al menos 3000 representantes. Es bastante obvio que esta pregunta no es considerada fuera de tema por la comunidad SO
Panagiotis Kanavos

PD: los 4 votos negativos podrían tener 8 años. Alguien pudo haber encontrado la pregunta en la cola de espera la semana pasada y votó a favor de cerrarla. SO tiene tantas preguntas en este momento que ya es difícil prestar la debida atención a las preguntas. El historial de edición muestra que la pregunta original también necesitaba un poco de edición
Panagiotis Kanavos

Quizás volver a la revisión 3, o algo similar, haría más probable que los revisores lo reabrieran. En su estado actual, es fácil confundir la pregunta con una pregunta de "cómo uso Photoshop", y también descartarla por no mostrar ningún esfuerzo de investigación.
Adam Millerchip

Respuestas:


210

Photoshop combina dos imágenes al realizar una operación de combinación en cada píxel de la imagen A con su píxel correspondiente en la imagen B. Cada píxel es un color que consta de varios canales. Suponiendo que trabajamos con píxeles RGB, los canales de cada píxel serían rojo, verde y azul. Para combinar dos píxeles combinamos sus respectivos canales.

La operación de fusión que se produce para cada modo de fusión en Photoshop se puede resumir en las siguientes macros:

#define ChannelBlend_Normal(A,B)     ((uint8)(A))
#define ChannelBlend_Lighten(A,B)    ((uint8)((B > A) ? B:A))
#define ChannelBlend_Darken(A,B)     ((uint8)((B > A) ? A:B))
#define ChannelBlend_Multiply(A,B)   ((uint8)((A * B) / 255))
#define ChannelBlend_Average(A,B)    ((uint8)((A + B) / 2))
#define ChannelBlend_Add(A,B)        ((uint8)(min(255, (A + B))))
#define ChannelBlend_Subtract(A,B)   ((uint8)((A + B < 255) ? 0:(A + B - 255)))
#define ChannelBlend_Difference(A,B) ((uint8)(abs(A - B)))
#define ChannelBlend_Negation(A,B)   ((uint8)(255 - abs(255 - A - B)))
#define ChannelBlend_Screen(A,B)     ((uint8)(255 - (((255 - A) * (255 - B)) >> 8)))
#define ChannelBlend_Exclusion(A,B)  ((uint8)(A + B - 2 * A * B / 255))
#define ChannelBlend_Overlay(A,B)    ((uint8)((B < 128) ? (2 * A * B / 255):(255 - 2 * (255 - A) * (255 - B) / 255)))
#define ChannelBlend_SoftLight(A,B)  ((uint8)((B < 128)?(2*((A>>1)+64))*((float)B/255):(255-(2*(255-((A>>1)+64))*(float)(255-B)/255))))
#define ChannelBlend_HardLight(A,B)  (ChannelBlend_Overlay(B,A))
#define ChannelBlend_ColorDodge(A,B) ((uint8)((B == 255) ? B:min(255, ((A << 8 ) / (255 - B)))))
#define ChannelBlend_ColorBurn(A,B)  ((uint8)((B == 0) ? B:max(0, (255 - ((255 - A) << 8 ) / B))))
#define ChannelBlend_LinearDodge(A,B)(ChannelBlend_Add(A,B))
#define ChannelBlend_LinearBurn(A,B) (ChannelBlend_Subtract(A,B))
#define ChannelBlend_LinearLight(A,B)((uint8)(B < 128)?ChannelBlend_LinearBurn(A,(2 * B)):ChannelBlend_LinearDodge(A,(2 * (B - 128))))
#define ChannelBlend_VividLight(A,B) ((uint8)(B < 128)?ChannelBlend_ColorBurn(A,(2 * B)):ChannelBlend_ColorDodge(A,(2 * (B - 128))))
#define ChannelBlend_PinLight(A,B)   ((uint8)(B < 128)?ChannelBlend_Darken(A,(2 * B)):ChannelBlend_Lighten(A,(2 * (B - 128))))
#define ChannelBlend_HardMix(A,B)    ((uint8)((ChannelBlend_VividLight(A,B) < 128) ? 0:255))
#define ChannelBlend_Reflect(A,B)    ((uint8)((B == 255) ? B:min(255, (A * A / (255 - B)))))
#define ChannelBlend_Glow(A,B)       (ChannelBlend_Reflect(B,A))
#define ChannelBlend_Phoenix(A,B)    ((uint8)(min(A,B) - max(A,B) + 255))
#define ChannelBlend_Alpha(A,B,O)    ((uint8)(O * A + (1 - O) * B))
#define ChannelBlend_AlphaF(A,B,F,O) (ChannelBlend_Alpha(F(A,B),A,O))

Para fusionar un solo píxel RGB, haría lo siguiente:

ImageTColorR = ChannelBlend_Glow(ImageAColorR, ImageBColorR); 
ImageTColorB = ChannelBlend_Glow(ImageAColorB, ImageBColorB);
ImageTColorG = ChannelBlend_Glow(ImageAColorG, ImageBColorG);

ImageTColor = RGB(ImageTColorR, ImageTColorB, ImageTColorG);

Si quisiéramos realizar una operación de mezcla con una opacidad particular, digamos 50%:

ImageTColorR = ChannelBlend_AlphaF(ImageAColorR, ImageBColorR, Blend_Subtract, 0.5F);

Si tiene punteros a los datos de imagen para las imágenes A, B y T (nuestro objetivo), podemos simplificar la combinación de los tres canales usando esta macro:

#define ColorBlend_Buffer(T,A,B,M)      (T)[0] = ChannelBlend_##M((A)[0], (B)[0]),
                                        (T)[1] = ChannelBlend_##M((A)[1], (B)[1]),
                                        (T)[2] = ChannelBlend_##M((A)[2], (B)[2])

Y puede derivar las siguientes macros de mezcla de colores RGB:

#define ColorBlend_Normal(T,A,B)        (ColorBlend_Buffer(T,A,B,Normal))
#define ColorBlend_Lighten(T,A,B)       (ColorBlend_Buffer(T,A,B,Lighten))
#define ColorBlend_Darken(T,A,B)        (ColorBlend_Buffer(T,A,B,Darken))
#define ColorBlend_Multiply(T,A,B)      (ColorBlend_Buffer(T,A,B,Multiply))
#define ColorBlend_Average(T,A,B)       (ColorBlend_Buffer(T,A,B,Average))
#define ColorBlend_Add(T,A,B)           (ColorBlend_Buffer(T,A,B,Add))
#define ColorBlend_Subtract(T,A,B)      (ColorBlend_Buffer(T,A,B,Subtract))
#define ColorBlend_Difference(T,A,B)    (ColorBlend_Buffer(T,A,B,Difference))
#define ColorBlend_Negation(T,A,B)      (ColorBlend_Buffer(T,A,B,Negation))
#define ColorBlend_Screen(T,A,B)        (ColorBlend_Buffer(T,A,B,Screen))
#define ColorBlend_Exclusion(T,A,B)     (ColorBlend_Buffer(T,A,B,Exclusion))
#define ColorBlend_Overlay(T,A,B)       (ColorBlend_Buffer(T,A,B,Overlay))
#define ColorBlend_SoftLight(T,A,B)     (ColorBlend_Buffer(T,A,B,SoftLight))
#define ColorBlend_HardLight(T,A,B)     (ColorBlend_Buffer(T,A,B,HardLight))
#define ColorBlend_ColorDodge(T,A,B)    (ColorBlend_Buffer(T,A,B,ColorDodge))
#define ColorBlend_ColorBurn(T,A,B)     (ColorBlend_Buffer(T,A,B,ColorBurn))
#define ColorBlend_LinearDodge(T,A,B)   (ColorBlend_Buffer(T,A,B,LinearDodge))
#define ColorBlend_LinearBurn(T,A,B)    (ColorBlend_Buffer(T,A,B,LinearBurn))
#define ColorBlend_LinearLight(T,A,B)   (ColorBlend_Buffer(T,A,B,LinearLight))
#define ColorBlend_VividLight(T,A,B)    (ColorBlend_Buffer(T,A,B,VividLight))
#define ColorBlend_PinLight(T,A,B)      (ColorBlend_Buffer(T,A,B,PinLight))
#define ColorBlend_HardMix(T,A,B)       (ColorBlend_Buffer(T,A,B,HardMix))
#define ColorBlend_Reflect(T,A,B)       (ColorBlend_Buffer(T,A,B,Reflect))
#define ColorBlend_Glow(T,A,B)          (ColorBlend_Buffer(T,A,B,Glow))
#define ColorBlend_Phoenix(T,A,B)       (ColorBlend_Buffer(T,A,B,Phoenix))

Y un ejemplo sería:

ColorBlend_Glow(TargetPtr, ImageAPtr, ImageBPtr);

El resto de los modos de fusión de Photoshop implican convertir RGB a HLS y viceversa.

#define ColorBlend_Hue(T,A,B)            ColorBlend_Hls(T,A,B,HueB,LuminationA,SaturationA)
#define ColorBlend_Saturation(T,A,B)     ColorBlend_Hls(T,A,B,HueA,LuminationA,SaturationB)
#define ColorBlend_Color(T,A,B)          ColorBlend_Hls(T,A,B,HueB,LuminationA,SaturationB)
#define ColorBlend_Luminosity(T,A,B)     ColorBlend_Hls(T,A,B,HueA,LuminationB,SaturationA)

#define ColorBlend_Hls(T,A,B,O1,O2,O3) {
    float64 HueA, LuminationA, SaturationA;
    float64 HueB, LuminationB, SaturationL;
    Color_RgbToHls((A)[2],(A)[1],(A)[0], &HueA, &LuminationA, &SaturationA);
    Color_RgbToHls((B)[2],(B)[1],(B)[0], &HueB, &LuminationB, &SaturationB);
    Color_HlsToRgb(O1,O2,O3,&(T)[2],&(T)[1],&(T)[0]);
    }

Estas funciones serán útiles para convertir RGB a HLS.

int32 Color_HueToRgb(float64 M1, float64 M2, float64 Hue, float64 *Channel)
{
    if (Hue < 0.0)
        Hue += 1.0;
    else if (Hue > 1.0)
        Hue -= 1.0;

    if ((6.0 * Hue) < 1.0)
        *Channel = (M1 + (M2 - M1) * Hue * 6.0);
    else if ((2.0 * Hue) < 1.0)
        *Channel = (M2);
    else if ((3.0 * Hue) < 2.0)
        *Channel = (M1 + (M2 - M1) * ((2.0F / 3.0F) - Hue) * 6.0);
    else
        *Channel = (M1);

    return TRUE;
}

int32 Color_RgbToHls(uint8 Red, uint8 Green, uint8 Blue, float64 *Hue, float64 *Lumination, float64 *Saturation)
{
    float64 Delta;
    float64 Max, Min;
    float64 Redf, Greenf, Bluef;

    Redf    = ((float64)Red   / 255.0F);
    Greenf  = ((float64)Green / 255.0F);
    Bluef   = ((float64)Blue  / 255.0F); 

    Max     = max(max(Redf, Greenf), Bluef);
    Min     = min(min(Redf, Greenf), Bluef);

    *Hue        = 0;
    *Lumination = (Max + Min) / 2.0F;
    *Saturation = 0;

    if (Max == Min)
        return TRUE;

    Delta = (Max - Min);

    if (*Lumination < 0.5)
        *Saturation = Delta / (Max + Min);
    else
        *Saturation = Delta / (2.0 - Max - Min);

    if (Redf == Max)
        *Hue = (Greenf - Bluef) / Delta;
    else if (Greenf == Max)
        *Hue = 2.0 + (Bluef - Redf) / Delta;
    else
        *Hue = 4.0 + (Redf - Greenf) / Delta;

    *Hue /= 6.0; 

    if (*Hue < 0.0)
        *Hue += 1.0;       

    return TRUE;
}

int32 Color_HlsToRgb(float64 Hue, float64 Lumination, float64 Saturation, uint8 *Red, uint8 *Green, uint8 *Blue)
{
    float64 M1, M2;
    float64 Redf, Greenf, Bluef;

    if (Saturation == 0)
        {
        Redf    = Lumination;
        Greenf  = Lumination;
        Bluef   = Lumination;
        }
    else
        {
        if (Lumination <= 0.5)
            M2 = Lumination * (1.0 + Saturation);
        else
            M2 = Lumination + Saturation - Lumination * Saturation;

        M1 = (2.0 * Lumination - M2);

        Color_HueToRgb(M1, M2, Hue + (1.0F / 3.0F), &Redf);
        Color_HueToRgb(M1, M2, Hue, &Greenf);
        Color_HueToRgb(M1, M2, Hue - (1.0F / 3.0F), &Bluef);
        }

    *Red    = (uint8)(Redf * 255);
    *Blue   = (uint8)(Bluef * 255);
    *Green  = (uint8)(Greenf * 255);

    return TRUE;
}

Hay más recursos sobre este tema, principalmente:

  1. Modos de fusión PegTop
  2. Photoshop forense
  3. Información sobre los modos de fusión de Photoshop 7.0
  4. SF - Básicos - Modos de fusión
  5. terminar los modos de fusión
  6. Blog de Romz
  7. Funciones de conversión de ReactOS RGB-HLS

1
si, gran respuesta, gracias! Me preguntaba si alguien sabe cómo se hace la opacidad de capa en Photoshop. es decir, quiero usar la función de oscurecimiento de mezcla pero solo el 50% ... Verifiqué los valores en Photoshop y no parece que sea suficiente para tomar solo el 50% de los valores de la imagen de mezcla ...
Maecky

2
La fórmula alfa proporcionada no está completa; solo funciona en el caso de que el fondo sea completamente opaco. Si el fondo es transparente, el resultado después del dibujo puede ser transparente. Debe aplicar una combinación alfa como la que se describe en Wikipedia para ese caso más general.
thenickdude

2
¿Qué tal el canal alfa? ¿Debería aplicarle las funciones también?
akhy

¡¡Gran respuesta!! Reflect y Glow se cambian. De lo contrario: ¡¡Genial !! (Aunque falta la composición alfa ...)
TaW

Solución c # para la composición alfa: estática Color alphaComposite (Color c1, Color c2, Color cb, float op) {float a1, a2, ab, ar = 1; ar = v [c1.A] + v [c2.A] * op - (v [c1.A] * v [c2.A] * op); flotar asr = v [c2.A] * op / ar; a1 = 1 - asr; a2 = asr * (1 - v [c1.A]); ab = asr * v [c1.A]; byte r = (byte) (c1.R * a1 + c2.R * a2 + cb.R * ab); byte g = (byte) (c1.G * a1 + c2.G * a2 + cb.G * ab); byte b = (byte) (c1.B * a1 + c2.B * a2 + cb.B * ab); return Color.FromArgb ((byte) (ar * 255), r, g, b); }
TaW

7

Los modos de combinación de Tono, Color y Saturación en esta respuesta son incorrectos. Ningún producto de Adobe se convierte a HSB, realizan la operación directamente en valores RGB.

Aquí está el GLSL para configurar la luminosidad, por ejemplo:

float lum(vec4 color)
{
    return ((0.3 * color.r) + (0.59 * color.g) + (0.11 * color.b));
}

vec4 clipColor(vec4 color)
{
    vec4 newColor=color;
    float l=lum(color);
    float n=min(min(color.r,color.g),color.b);
    float x=max(max(color.r,color.g),color.b);

    newColor.r=(n<0.0) ? l+(((color.r-l)*l)/(l-n)) : color.r;
    newColor.r=(x>1.0) ? l+(((color.r-l)*(1.0-l))/(x-l)) : color.r;

    newColor.g=(n<0.0) ? l+(((color.g-l)*l)/(l-n)) : color.g;
    newColor.g=(x>1.0) ? l+(((color.g-l)*(1.0-l))/(x-l)) : color.g;

    newColor.b=(n<0.0) ? l+(((color.b-l)*l)/(l-n)) : color.b;
    newColor.b=(x>1.0) ? l+(((color.b-l)*(1.0-l))/(x-l)) : color.b;

    return clamp(newColor,0.0,1.0);
}

vec4 setlum(vec4 color, float l)
{
    float d=l-lum(color);
    color.r+=d;
    color.g+=d;
    color.b+=d;

    return clipColor(color);    
}

kernel vec4 blendLuminosity(sampler topimage, sampler bottomimage)
{
    vec4 base=sample(bottomimage, samplerCoord(bottomimage));
    vec4 blend=sample(topimage, samplerCoord(topimage));

    float bl=lum(blend);
    return setlum(base,bl);
}

No hay soporte para declaraciones if .. else en CIKernels, de ahí el uso de operadores ternarios.


4

La respuesta popular es 99,9% correcta, pero como dijo Greyfriars, no obtendrá el resultado exacto porque Adobe no usa HLS en ningún momento en la combinación.

Pero no necesita estar trabajando en Adobe para hacer eso ... puede lograr exactamente la misma combinación siguiendo todas las reglas aquí en este documento de Adobe:

básicamente los capítulos 4 y 7: http://partners.adobe.com/public/developer/en/pdf/PDFReference.pdf

¡Entonces obtendrá el resultado exacto como lo hace Adobe! ¡Píxel a píxel!


i.imgur.com/G5MbHOH.png dice que se usa HSL en el enlace (seguí aquí porque ese enlace se rompió para mí: adobe.com/content/dam/acom/en/devnet/pdf/pdfs/… )
eri0o

0

Si bien la respuesta popular es en su mayoría correcta, la siguiente afirmación es incorrecta. "El resto de los modos de fusión de Photoshop implican convertir RGB a HLS y viceversa". No, Photoshop (y solo Photoshop) usa Chroma y Luma en lugar de HLS.

Entonces, para los modos de Tono, Color, Luminosidad y Saturación, no puede usar algoritmos simples. Para igualar el método de Photoshop en estos casos, debe trabajar para Adobe.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.