In che modo Photoshop unisce due immagini?

Qualcuno può spiegare come Photoshop unisce due immagini insieme in modo da poter riprodurre gli stessi effetti nella mia applicazione.

Photoshop unisce due immagini insieme eseguendo un’operazione di fusione su ciascun pixel nell’immagine A rispetto al pixel corrispondente nell’immagine B. Ogni pixel è un colore costituito da più canali. Supponendo che stiamo lavorando con pixel RGB, i canali di ciascun pixel sarebbero rossi, verdi e blu. Per unire due pixel mescoliamo i loro rispettivi canali.

L’operazione di fusione che si verifica per ciascuna modalità di fusione in Photoshop può essere riassunta nelle seguenti macro:

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

Per unire un singolo pixel RGB, procedere come segue:

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

Se volessimo eseguire un'operazione di fusione con una particolare opacità, diciamo 50%:

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

Se hai dei puntatori ai dati di immagine per le immagini A, B e T (il nostro objective), possiamo semplificare la fusione di tutti e tre i canali usando questa 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]) 

E può derivare le seguenti macro di blend di colors 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)) 

E l'esempio sarebbe:

 ColorBlend_Glow(TargetPtr, ImageAPtr, ImageBPtr); 

Il resto delle modalità di fusione di Photoshop prevede la conversione da RGB a HLS e 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]); } 

Queste funzioni saranno utili nella conversione da 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; } 

Ci sono più risorse su questo argomento, principalmente:

  1. Modalità di fusione PegTop
  2. Photoshop forense
  3. Informazioni dettagliate sulle modalità di fusione di Photoshop 7.0
  4. SF - Nozioni di base - Modalità di fusione
  5. completa le modalità di fusione
  6. Blog di Romz
  7. Funzioni di conversione ReactOS RGB-HLS

I metodi di fusione Tonalità, Colore, Saturazione in questa risposta sono errati. Nessun prodotto Adobe converte in HSB, eseguono l’operazione direttamente su valori RGB.

Ecco il GLSL per impostare la luminosità, ad esempio:

 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.rl)*l)/(ln)) : color.r; newColor.r=(x>1.0) ? l+(((color.rl)*(1.0-l))/(xl)) : color.r; newColor.g=(n<0.0) ? l+(((color.gl)*l)/(ln)) : color.g; newColor.g=(x>1.0) ? l+(((color.gl)*(1.0-l))/(xl)) : color.g; newColor.b=(n<0.0) ? l+(((color.bl)*l)/(ln)) : color.b; newColor.b=(x>1.0) ? l+(((color.bl)*(1.0-l))/(xl)) : 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); } 

Nessun supporto per le istruzioni if.. else in CIKernels, quindi l’uso di operatori ternari.

La risposta popolare è corretta al 99,9%, ma come ha detto Greyfriars, non otterrà il risultato esatto perché Adobe non usa HLS in qualsiasi momento nella fusione.

Ma non è necessario che tu stia lavorando ad Adobe per farlo … puoi raggiungere esattamente la stessa fusione seguendo tutte le regole qui in questo documento di Adobe:

in pratica i capitoli 4 e 7: http://partners.adobe.com/public/developer/en/pdf/PDFReference.pdf

Quindi otterrai il risultato esatto proprio come fa Adobe! Pixel di Pixel!

Mentre la risposta popolare è per lo più corretta, la seguente affermazione è errata. “Il resto delle modalità di fusione di Photoshop prevede la conversione da RGB a HLS e viceversa.” No, Photoshop (e solo Photoshop) usa Chroma e Luma invece di HLS.

Quindi per le modalità Tonalità, Colore, Luminosità e Saturazione, non è ansible utilizzare semplici algoritmi. Per abbinare il metodo di Photoshop in questi casi, devi lavorare per Adobe.