天天看點

圖像特效---PS圖層混合模式之明度模式

本文将介紹PS圖層混合模式中比較複雜 的“明度”模式的算法原理及代碼實作内容。 說到PS的圖層混合模式,計算公式都有,具體代碼實作也能找到,但是,都沒有完整介紹所有圖層混合模式的代碼,比如“明度”模式,公式如下: 假設兩張圖的HSY顔色模式分别為: Hb,Sb,Yb---Hm,Sm,Ym 明度混合結果HSY = HbSbYm 這個公式很簡單,無非就是原圖的H,S分量+混合圖的Y分量而已,但是具體代碼如何實作,卻很少有人分享,今天,我将給大家分享本人的代碼。 HSY模式是一種彩色傳輸模型,傳輸基本的色差和亮度信号。如果直接使用HSY顔色空間,這個顔色空間好像很少見,具體HSY計算公式如下:

Y = 0.299R + 0.587G + 0.114B; Cr = R - Y; Cb = B - Y; H = arctan(Cr/Cb); S = sqrt(Cr * Cr + Cb * Cb);

大家可以看到,這個公式中運算複雜,但是是基于Cr, Cb分量計算的,而且,明度圖層混合模式結果中實際上隻改變了Y分量,是以,我們這裡可以使用YCbCr顔色空間來代替HSY顔色空間實作這個功能。 YCbCr與RGB轉換公式如下:

Y   = 0.257*R+0.564*G+0.098*B+16

Cb = -0.148*R-0.291*G+0.439*B+128

Cr  = 0.439*R-0.368*G-0.071*B+128

R = 1.164*(Y-16)+1.596*(Cr-128)

G = 1.164*(Y-16)-0.392*(Cb-128)-0.813*(Cr-128)

B = 1.164*(Y-16)+2.017*(Cb-128)

是以,按照上面的公式我們編碼實作如下: [cpp] view plain copy print

  1. #include"TRGB2YCbCr.h"  
  2. #include   
  3. #include   
  4. #include "math.h"  
  5. #include   
  6. const float YCbCrYRF = 0.299F;              // RGB轉YCbCr的系數(浮點類型)  
  7. const float YCbCrYGF = 0.587F;  
  8. const float YCbCrYBF = 0.114F;  
  9. const float YCbCrCbRF = -0.168736F;  
  10. const float YCbCrCbGF = -0.331264F;  
  11. const float YCbCrCbBF = 0.500000F;  
  12. const float YCbCrCrRF = 0.500000F;  
  13. const float YCbCrCrGF = -0.418688F;  
  14. const float YCbCrCrBF = -0.081312F;  
  15. const float RGBRYF = 1.00000F;            // YCbCr轉RGB的系數(浮點類型)  
  16. const float RGBRCbF = 0.0000F;  
  17. const float RGBRCrF = 1.40200F;  
  18. const float RGBGYF = 1.00000F;  
  19. const float RGBGCbF = -0.34414F;  
  20. const float RGBGCrF = -0.71414F;  
  21. const float RGBBYF = 1.00000F;  
  22. const float RGBBCbF = 1.77200F;  
  23. const float RGBBCrF = 0.00000F;  
  24. const int Shift = 20;  
  25. const int HalfShiftValue = 1 << (Shift - 1);  
  26. const int YCbCrYRI = (int)(YCbCrYRF * (1 << Shift) + 0.5);         // RGB轉YCbCr的系數(整數類型)  
  27. const int YCbCrYGI = (int)(YCbCrYGF * (1 << Shift) + 0.5);  
  28. const int YCbCrYBI = (int)(YCbCrYBF * (1 << Shift) + 0.5);  
  29. const int YCbCrCbRI = (int)(YCbCrCbRF * (1 << Shift) + 0.5);  
  30. const int YCbCrCbGI = (int)(YCbCrCbGF * (1 << Shift) + 0.5);  
  31. const int YCbCrCbBI = (int)(YCbCrCbBF * (1 << Shift) + 0.5);  
  32. const int YCbCrCrRI = (int)(YCbCrCrRF * (1 << Shift) + 0.5);  
  33. const int YCbCrCrGI = (int)(YCbCrCrGF * (1 << Shift) + 0.5);  
  34. const int YCbCrCrBI = (int)(YCbCrCrBF * (1 << Shift) + 0.5);  
  35. const int RGBRYI = (int)(RGBRYF * (1 << Shift) + 0.5);              // YCbCr轉RGB的系數(整數類型)  
  36. const int RGBRCbI = (int)(RGBRCbF * (1 << Shift) + 0.5);  
  37. const int RGBRCrI = (int)(RGBRCrF * (1 << Shift) + 0.5);  
  38. const int RGBGYI = (int)(RGBGYF * (1 << Shift) + 0.5);  
  39. const int RGBGCbI = (int)(RGBGCbF * (1 << Shift) + 0.5);  
  40. const int RGBGCrI = (int)(RGBGCrF * (1 << Shift) + 0.5);  
  41. const int RGBBYI = (int)(RGBBYF * (1 << Shift) + 0.5);  
  42. const int RGBBCbI = (int)(RGBBCbF * (1 << Shift) + 0.5);  
  43. const int RGBBCrI = (int)(RGBBCrF * (1 << Shift) + 0.5);  
  44. void RGBToYCbCr(int R, int G, int B, int*Y,int*Cb, int* Cr)  
  45. {  
  46.     *Y  = ((YCbCrYRI * R + YCbCrYGI * G + YCbCrYBI * B + HalfShiftValue) >> Shift);  
  47.     *Cb = (128 + ((YCbCrCbRI * R + YCbCrCbGI * G + YCbCrCbBI * B + HalfShiftValue) >> Shift));  
  48.     *Cr = (128 + ((YCbCrCrRI * R + YCbCrCrGI * G + YCbCrCrBI * B + HalfShiftValue) >> Shift));  
  49. }  
  50. void YCbCrToRGB(int Y, int Cb, int Cr, int*R,int*G, int* B)  
  51. {  
  52.     Cb = Cb - 128; Cr = Cr - 128;  
  53.     *R = Y + ((RGBRCrI * Cr + HalfShiftValue) >> Shift);  
  54.     *G = Y + ((RGBGCbI * Cb + RGBGCrI * Cr + HalfShiftValue) >> Shift);  
  55.     *B = Y + ((RGBBCbI * Cb + HalfShiftValue) >> Shift);  
  56.     if (*R > 255) *R = 255; else if (*R < 0) *R = 0;  
  57.     if (*G > 255) *G = 255; else if (*G < 0) *G = 0;     
  58.     if (*B > 255) *B = 255; else if (*B < 0) *B = 0;  
  59. }  
  60. int ColorBlendModeBrightness(unsigned char* baseData, unsigned char* mixData, int width, int height, int stride)  
  61. {  
  62.     int i, j, pos;  
  63.     int bY, bCb, bCr, mY, mCb, mCr, br, bg, bb, mr, mg, mb;  
  64.     unsigned char* pBase = baseData;  
  65.     unsigned char* pMix = mixData;  
  66.     int offset = stride - width * 4;  
  67.     for(j = 0; j < height; j++)  
  68.     {  
  69.         for(i = 0; i < width; i++)  
  70.         {  
  71.             bb = pBase[0];  
  72.             bg = pBase[1];  
  73.             br = pBase[2];  
  74.             mb = pMix[0];  
  75.             mg = pMix[1];  
  76.             mr = pMix[2];  
  77.             RGBToYCbCr(mr,mg,mb,&mY,&mCb,&mCr);  
  78.             RGBToYCbCr(br,bg,bb,&bY,&bCb,&bCr);  
  79.             YCbCrToRGB((mY+bY)/2, bCb, bCr, &br,&bg,&bb);//(mY+bY)/2表示透明度為50%  
  80.             pBase[0] = bb;  
  81.             pBase[1] = bg;  
  82.             pBase[2] = br;  
  83.             pBase += 4;  
  84.             pMix  += 4;  
  85.         }  
  86.         pBase += offset;  
  87.         pMix  += offset;  
  88.     }  
  89.     return 0;  
  90. }  

這個就是所有編碼了,而且這個顔色空間轉換的代碼已經經過優化,大家可以直接使用,下面我給出效果圖(該效果是按照明度圖層混合模式50%透明度設定得到的):

圖像特效---PS圖層混合模式之明度模式
圖像特效---PS圖層混合模式之明度模式

大家可以看到,效果圖和PS的效果圖幾乎一緻 demo: Release.zip