Comment Photoshop mélange-t-il deux images ensemble? [fermé]

84

Quelqu'un peut-il expliquer comment Photoshop mélange deux images afin que je puisse reproduire les mêmes effets dans mon application.

Nathan Moinvaziri
la source
3
Ce n'est certainement pas une question sur le matériel informatique général ou les logiciels. Il s'agit d'algorithmes, de C ++ et de traitement d'image. Ce type de question est explicitement autorisé et activement encouragé
Panagiotis Kanavos
Après 8 ans à générer des clics vers ce site, il est considéré comme hors sujet seulement maintenant?
Nathan Moinvaziri
Tout ce dont il a besoin, c'est de 5 votes serrés de personnes ayant au moins 3000 représentants. Il est assez évident que cette question n'est pas considérée comme hors sujet par la communauté SO
Panagiotis Kanavos
PS: les 4 votes négatifs pourraient avoir 8 ans. Quelqu'un a peut-être rencontré la question dans la file d'attente de fermeture la semaine dernière et a voté pour la fermeture. SO a tellement de questions en ce moment qu'il est difficile de prêter une attention particulière aux questions. L'historique des modifications montre que la question originale avait également besoin d'un peu de modification
Panagiotis Kanavos
Peut-être que le fait de revenir à la révision 3, ou quelque chose de similaire, rendrait celle-ci plus susceptible d'être rouverte par les réviseurs. Dans son état actuel, il est facile de confondre la question avec une question «comment utiliser Photoshop», et aussi de la rejeter comme ne montrant aucun effort de recherche.
Adam Millerchip

Réponses:

210

Photoshop fusionne deux images en effectuant une opération de fusion sur chaque pixel de l'image A par rapport à son pixel correspondant dans l'image B. Chaque pixel est une couleur constituée de plusieurs canaux. En supposant que nous travaillons avec des pixels RVB, les canaux de chaque pixel seraient rouges, verts et bleus. Pour mélanger deux pixels, nous mélangeons leurs canaux respectifs.

L'opération de fusion qui se produit pour chaque mode de fusion dans Photoshop peut être résumée dans les macros suivantes:

#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))

Pour mélanger un seul pixel RVB, procédez comme suit:

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

ImageTColor = RGB(ImageTColorR, ImageTColorB, ImageTColorG);

Si nous voulions effectuer une opération de fusion avec une opacité particulière, disons 50%:

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

Si vous avez des pointeurs vers les données d'image pour les images A, B et T (notre cible), nous pouvons simplifier le mélange des trois canaux à l'aide de cette 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])

Et peut dériver les macros de mélange de couleurs RVB suivantes:

#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))

Et l'exemple serait:

ColorBlend_Glow(TargetPtr, ImageAPtr, ImageBPtr);

Le reste des modes de fusion Photoshop impliquent la conversion RVB en HLS et inversement.

#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]);
    }

Ces fonctions seront utiles pour convertir RVB en 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;
}

Il existe plus de ressources sur ce sujet, principalement:

  1. Modes de fusion PegTop
  2. Forensic Photoshop
  3. Aperçu des modes de fusion de Photoshop 7.0
  4. SF - Bases - Modes de fusion
  5. terminer les modes de fusion
  6. Blog de Romz
  7. Fonctions de conversion ReactOS RGB-HLS
Nathan Moinvaziri
la source
1
ouais, bonne réponse, merci! Je me demandais si quelqu'un savait comment l'opacité des calques est effectuée dans Photoshop? c'est-à-dire que je veux utiliser la fonction blend darken mais seulement 50% ... J'ai vérifié les valeurs dans Photoshop et il ne semble pas que ce soit suffisant pour prendre seulement 50% des valeurs de l'image blend ...
Maecky
2
La formule alpha donnée n'est pas complète - elle ne fonctionne que dans le cas où l'arrière-plan est totalement opaque. Si l'arrière-plan est transparent, le résultat après le dessin peut être transparent. Vous devez appliquer un mélange alpha tel que celui décrit sur Wikipedia pour ce cas plus général.
thenickdude
2
Et le canal alpha? Dois-je également lui appliquer les fonctions?
akhy
Très bonne réponse!! Reflect et Glow sont commutés. Sinon: génial !! (Bien que l'alpha-compositing soit absent ..)
TaW
Solution c # pour la composition alpha: statique 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); float asr = v [c2.A] * op / ar; a1 = 1 - asr; a2 = asr * (1 - v [c1.A]); ab = asr * v [c1.A]; octet r = (octet) (c1.R * a1 + c2.R * a2 + cb.R * ab); octet g = (octet) (c1.G * a1 + c2.G * a2 + cb.G * ab); octet b = (octet) (c1.B * a1 + c2.B * a2 + cb.B * ab); renvoie Color.FromArgb ((octet) (ar * 255), r, g, b); }
TaW
7

Les modes de fusion Teinte, Couleur et Saturation de cette réponse sont erronés. Aucun produit Adobe ne convertit en HSB, ils effectuent l'opération directement sur les valeurs RVB.

Voici le GLSL pour régler la luminosité, par exemple:

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);
}

Pas de support pour les instructions if .. else dans CIKernels, d'où l'utilisation d'opérateurs ternaires.

Jon Gilkison
la source
4

La réponse populaire est correcte à 99,9%, mais comme l'a dit Greyfriars, elle n'obtiendra pas le résultat exact car Adobe n'utilise HLS à aucun moment dans le mélange.

Mais vous n'avez pas besoin de travailler chez Adobe pour ce faire ... vous pouvez atteindre exactement le même mélange en suivant toutes les règles ici dans ce document d'Adobe:

essentiellement les chapitres 4 et 7: http://partners.adobe.com/public/developer/en/pdf/PDFReference.pdf

Ensuite, vous atteindrez le résultat exact comme Adobe le fait! Pixel par Pixel!

Wagner Patriota
la source
i.imgur.com/G5MbHOH.png il dit que HSL est utilisé dans le lien (j'ai suivi ici parce que ce lien a été rompu pour moi: adobe.com/content/dam/acom/en/devnet/pdf/pdfs/… )
eri0o
0

Bien que la réponse populaire soit généralement correcte, la déclaration suivante est fausse. "Le reste des modes de fusion Photoshop impliquent la conversion RVB en HLS et inversement." Non, Photoshop (et uniquement Photoshop) utilise Chroma et Luma au lieu de HLS.

Donc, pour les modes Teinte, Couleur, Luminosité et Saturation, vous ne pouvez pas utiliser d'algorithmes simples. Pour correspondre à la méthode de Photoshop dans ces cas, vous devez travailler pour Adobe.

Greyfriars Bobby
la source