C實現(xiàn)Photoshop圖層顏色混合模式_第1頁
C實現(xiàn)Photoshop圖層顏色混合模式_第2頁
C實現(xiàn)Photoshop圖層顏色混合模式_第3頁
C實現(xiàn)Photoshop圖層顏色混合模式_第4頁
C實現(xiàn)Photoshop圖層顏色混合模式_第5頁
已閱讀5頁,還剩30頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、  Photoshop提供了豐富的圖象圖層混合模式,其中的顏色混合模式是用下圖層圖象的亮度與上圖層填充顏色或者圖象色彩進(jìn)行混合,形成的結(jié)果既有著上圖層的色彩,又保留了下層圖象的灰度,基于這種混合特性,顏色混合模式常用來對灰度圖象進(jìn)行著色。  如何用程序代碼準(zhǔn)確地實現(xiàn)Photoshop的圖層顏色混合模式,一直是程序員們熱衷的話題。本文采用BCB2007和GDI+等工具,較好地實現(xiàn)了其主要功能(不考慮不透明度和填充選項)。  按照Photoshop的解釋,顏色混合模式是用上圖層圖象顏色的色相、飽和度與下圖層圖象像素的明度進(jìn)行的混合。如此,我們在程序代碼中,就需要首先將

2、上層圖象顏色的色相、飽和度和下圖層圖象顏色的明度(亮度)提取出來,色相、飽和度的提取是按照HSV的方式進(jìn)行的,然后按照下圖層顏色明度按照0.3R +0.59G + 0.11B 的比例逐像素進(jìn)行運算合成,可事實上,我在顏色合成過程中,無論是采用HSV還是HSL甚或其它HSB方式,均沒法達(dá)到應(yīng)有的效果。例如取上層顏色R=225,G=211,B=179,提取的H,S分別為42,20%,下層灰度為179,采用HSV或者SHL合成顏色的G,B均為0,而實際合成的R,G,B應(yīng)分別為192,178,146。  通過在Photoshop中反復(fù)試驗,發(fā)現(xiàn)上層顏色中的飽和度在合成過程中似乎沒起

3、什么作用,最終合成結(jié)果只要保證上層顏色色相和下層灰度的比例不變就行了,這也是顏色混合模式的2個必要條件,其中灰度比例是必須保證的,如果二者發(fā)生沖突,可不考慮色相比例(如圖象某像素的灰度為0或者255)。按照這個思路,我放棄了用HSB進(jìn)行合成的方法,而按照上面2個條件采用解方程的方法來實現(xiàn)顏色混合。為此,可列出下列等式關(guān)系:1:Max - Min = a2:Mid - Min = b3:0.3R + 0.59G + 0.11B = c其中,Max,Mid,Min分別為上層顏色R、G、B分量中的最大、中間、最小值。等式1和2代表了上層顏色色相的比例關(guān)系,等式3則代表著下層顏色的灰度比例。如果只考慮

4、60度以內(nèi)的色相和假定R>G>B,那么用上面的3個等式可列為下面的三元一次方程組:1)  R - B = a2)  G - B = b3)  0.3R + 0.59G + 0.11B = c  可以將滿足色相在0 - 60范圍,R>G>B的任何顏色的常數(shù)代入上面的方程組進(jìn)行驗算,其結(jié)果是正確的。但是實際的顏色混合是用2個顏色不同的灰度和色相,采用上面的方程組解出的RGB值有可能會超出0 - 255的范圍,而我們又無法在方程組中加入這種范圍限制,因此對于超出范圍的RGB值,還必須在程序代碼中進(jìn)行調(diào)整。下面是我寫的一個單像素

5、合成代碼。view plaincopy to clipboardprint?1. /-   2. typedef union           / 顏色分量交換結(jié)構(gòu)   3.   4.     int tmp;            /&

6、#160;交換時用的臨時變量   5.     struct  6.       7.         short value;    / 顏色分量值   8.         short index;

7、0;   / 顏色分量索引:blue=0,green=1,red=2   9.       10. RgbSwap, *PRgbSwap;  11.   12. typedef struct  13.   14.     unsigned char v4;  15. ArgbArray; 

8、 16. /-   17. inline void SwapRgb(RgbSwap &a, RgbSwap &b)  18.   19.     a.tmp += b.tmp;  20.     b.tmp = a.tmp - b.tmp;  21.   

9、0; a.tmp -= b.tmp;  22.   23. /-   24. Color ColorMix(Color color, int gray)  25.   26.     const double ys = 0.11, 0.59, 0.30;  27.   28.  

10、   int e14, e24, e34, e44, e54, e64;  29.     RgbSwap max, mid, min;  30.     int newMax, newMid, newMin;  31.     int max_min,

11、60;mid_min;  32.     double hueCoef;  33.     Color result;  34.   35.     max.tmp = color.GetRed() + 0x20000;  36.     mid.tmp = 

12、color.GetGreen() + 0x10000;  37.     min.tmp = color.GetBlue();  38.   39.     if (max.value < mid.value)  40.         SwapRgb(max, mid);

13、  41.     if (max.value < min.value)  42.         SwapRgb(max, min);  43.     if (min.value > mid.value)  44.      

14、;   SwapRgb(min, mid);  45.   46.     max_min = max.value - min.value;  47.     / 飽和度為0,返回灰度   48.     if (max_min = 0) return Col

15、or(gray, gray, gray);  49.   50.     mid_min = mid.value - min.value;  51.     hueCoef = (double)mid_min / (double)max_min;  52.   53.     /

16、 假設(shè)最大值=R,中間值=G,最小值=B,設(shè)置方程組:   54.     /   1): -B + R = max - min   55.     /   2): -B + G = mid - min   56.    

17、; /   3): 11B + 59G + 30R = Gray * 100   57.     e1max.index = 1;  58.     e1mid.index = 0;  59.     e1min.index = 

18、-1;  60.     e13 = max_min;  61.     e2max.index = 0;  62.     e2mid.index = 1;  63.     e2min.index = -1;  64.    

19、 e23 = mid_min;  65.     e30 = 11;  66.     e31 = 59;  67.     e32 = 30;  68.     e33 = gray * 100;  69.

20、  70.     / 解方程組:   71.     /  4): (1) - 2) * 30   72.     /  5): 2) * 11   73.     /  6): 3) -

21、 4) + 5)    74.     for (int i = 0; i < 4; i +)  75.       76.         e4i = (e1i - e2i) * e

22、3max.index;  77.         e5i = e2i * e3min.index;  78.         e6i = e3i - e4i + e5i;  79.       80.  

23、60;81.     / 求G解:6) / 100  (因灰度公式緣故,等式右邊恒等于100)   82.     newMid = (e63 + 50) / 100;  83.     / 求B解:G代入 2)   84.     newMin&#

24、160;= newMid - e23;  85.     / 如果B < 0,B = 0,同時按灰度比例和色相比例解二元一次方程求R、G   86.     / 方程式:1-1): 0.3R + 0.59G = Gray   87.     /  

25、60;      1-2): HueCoef * R - G = 0   88.     if (newMin < 0 | newMid <= 0)  89.       90.      

26、0;  newMax = (int)(gray / (ysmax.index + ysmid.index * hueCoef) + 0.5);  91.         newMid = (int)(newMax * hueCoef + 0.5);  92.    &#

27、160;    newMin = 0;  93.       94.     / 否則求R解:G、B代入 1)   95.     else  96.       97.        &#

28、160;newMax = newMin + e13;  98.         / 如果R > 255,R = 255,同時按灰度比例和色相比例解二元一次方程求G、B   99.         / 方程式:2-1): 0.59G + 0.11B =&#

29、160;gray - 0.3 * 255   100.         /         2-2): G + (hueCoef - 1)B = 255 * hueCoef   101.       

30、  if (newMax > 255)  102.           103.             newMin = (int)(gray - (ysmax.index + ysmid.index * hueCoef)

31、 * 255) /  104.                         (ysmin.index - ysmid.index * (hueCoef - 1) + 1.0);  105.  &#

32、160;          newMid = (int)(newMin + (255 - newMin) * hueCoef + 0.5);  106.             newMax = 255;  107. &

33、#160;         108.       109.   110.     (ArgbArray*)&result)->vmax.index = newMax;  111.     (ArgbArray*)&result)->vmid.index = ne

34、wMid;  112.     (ArgbArray*)&result)->vmin.index = newMin;  113.     return result;  114.   /-typedefunion/ 顏色分量交換結(jié)構(gòu)int tmp;/ 交換時用的臨時變量structshort value;/ 顏色分量值short index;/ 顏色分量索引:blue=0,green=1,re

35、d=2 ;RgbSwap, *PRgbSwap;typedef structunsigned char v4;ArgbArray;/-inline void SwapRgb(RgbSwap &a, RgbSwap &b)a.tmp += b.tmp;b.tmp = a.tmp - b.tmp;a.tmp -= b.tmp;/-Color ColorMix(Color color, int gray)const double ys = 0.11, 0.59, 0.30;int e14, e24, e34, e44, e54, e64;RgbSwap max, mid, min;i

36、nt newMax, newMid, newMin;int max_min, mid_min;double hueCoef;Color result;max.tmp = color.GetRed() + 0x20000;mid.tmp = color.GetGreen() + 0x10000;min.tmp = color.GetBlue();if (max.value < mid.value)SwapRgb(max, mid);if (max.value < min.value)SwapRgb(max, min);if (min.value > mid.value)Swap

37、Rgb(min, mid);max_min = max.value - min.value;/ 飽和度為0,返回灰度if (max_min = 0) return Color(gray, gray, gray);mid_min = mid.value - min.value;hueCoef = (double)mid_min / (double)max_min;/ 假設(shè)最大值=R,中間值=G,最小值=B,設(shè)置方程組:/ 1): -B + R = max - min/ 2): -B + G = mid - min/ 3): 11B + 59G + 30R = Gray * 100e1max.in

38、dex = 1;e1mid.index = 0;e1min.index = -1;e13 = max_min;e2max.index = 0;e2mid.index = 1;e2min.index = -1;e23 = mid_min;e30 = 11;e31 = 59;e32 = 30;e33 = gray * 100;/ 解方程組:/ 4): (1) - 2) * 30/ 5): 2) * 11/ 6): 3) - 4) + 5) for (int i = 0; i < 4; i +)e4i = (e1i - e2i) * e3max.index;e5i = e2i * e3min.

39、index;e6i = e3i - e4i + e5i;/ 求G解:6) / 100 (因灰度公式緣故,等式右邊恒等于100)newMid = (e63 + 50) / 100;/ 求B解:G代入 2)newMin = newMid - e23;/ 如果B < 0,B = 0,同時按灰度比例和色相比例解二元一次方程求R、G/ 方程式:1-1): 0.3R + 0.59G = Gray/ 1-2): HueCoef * R - G = 0if (newMin < 0 | newMid <= 0)newMax = (int)(gray / (ysmax.index + ysmid

40、.index * hueCoef) + 0.5);newMid = (int)(newMax * hueCoef + 0.5);newMin = 0;/ 否則求R解:G、B代入 1)elsenewMax = newMin + e13;/ 如果R > 255,R = 255,同時按灰度比例和色相比例解二元一次方程求G、B/ 方程式:2-1): 0.59G + 0.11B = gray - 0.3 * 255/ 2-2): G + (hueCoef - 1)B = 255 * hueCoefif (newMax > 255)newMin = (int)(gray - (ysmax.in

41、dex + ysmid.index * hueCoef) * 255) /(ysmin.index - ysmid.index * (hueCoef - 1) + 1.0);newMid = (int)(newMin + (255 - newMin) * hueCoef + 0.5);newMax = 255;(ArgbArray*)&result)->vmax.index = newMax;(ArgbArray*)&result)->vmid.index = newMid;(ArgbArray*)&result)->vmin.index = newM

42、in;return result;  ColorMix函數(shù)寫出了比較詳細(xì)的解方程過程代碼,并作了相應(yīng)的注釋;解三元一次方程組時,將灰度比例值擴大了100倍,可使用定點數(shù)運算,因為灰度比例關(guān)系恒等于100的緣故,運算過程中不會產(chǎn)生誤差;其中對值超出0 - 255范圍RGB值分別使用了2組二元一次方程進(jìn)行了處理;另外,由于定義了一個RgbSwap類型,使得在比較和交換最大、最小值過程中,保存了原R、G、B信息,這不僅方便了代碼中的運算,也使得前面的三元一次方程組的適用范圍從色相60度以內(nèi)和R>G>B,擴展到了色相全范圍以及任意大小的R、G、B值,同時也避免了HSB轉(zhuǎn)換為RGB

43、時通常使用的switch條件語句。  經(jīng)過一定量的顏色混合測試,ColorMix函數(shù)表現(xiàn)較好,運算結(jié)果與實際誤差始終在2的范圍內(nèi),這屬于正常的運算誤差和灰度比例取值誤差。  下面是一個對灰度圖象進(jìn)行著色的函數(shù)和測試代碼:view plaincopy to clipboardprint?1. / 圖像著色。bmp:灰度背景圖象,color:顏色   2. void PSGrayImageTint(Bitmap *bmp, Color color)  3.   4. &

44、#160;   const double ys = 0.11, 0.59, 0.3;  5.   6.     RgbSwap max, mid, min;  7.     int newMax, newMid, newMin;  8.     in

45、t max_min, mid_min;  9.     double hueCoef;  10.   11.     max.tmp = color.GetRed() + 0x20000;  12.     mid.tmp = color.GetGreen() + 0x10000;

46、0; 13.     min.tmp = color.GetBlue();  14.   15.     if (max.value < mid.value)  16.         SwapRgb(max, mid);  17.     i

47、f (max.value < min.value)  18.         SwapRgb(max, min);  19.     if (min.value > mid.value)  20.         SwapRgb(min, mid)

48、;  21.   22.     max_min = max.value - min.value;  23.     / 飽和度為0,不著色返回   24.     if (max_min = 0) return;  25.   26.   

49、0; mid_min = mid.value - min.value;  27.     hueCoef = (double)mid_min / (double)max_min;  28.   29.     BitmapData data;  30.     Gdiplus:Rect r

50、(0, 0, bmp->GetWidth(), bmp->GetHeight();  31.     bmp->LockBits(&r, ImageLockModeRead | ImageLockModeWrite, PixelFormat24bppRGB, &data);  32.     try  33.    

51、;   34.         unsigned char *p = (unsigned char*)data.Scan0;  35.         int offset = data.Stride - data.Width * 3;  36. &

52、#160;       for (unsigned y = 0; y < data.Height; y +, p += offset)  37.           38.          &

53、#160;  for (unsigned x = 0; x < data.Width; x +, p += 3)  39.               40.            &

54、#160;    newMid = (int)(*p - (max_min - mid_min) * ysmax.index +  41.                     mid_min * ysmin.index

55、0;+ 0.5);  42.                 newMin = newMid - mid_min;  43.                 if (newMin&

56、#160;< 0 | newMid <= 0)  44.                   45.                    

57、0;newMax = (int)(*p / (ysmax.index + ysmid.index * hueCoef) + 0.5);  46.                     newMid = (int)(newMax * hue

58、Coef + 0.5);  47.                     newMin = 0;  48.                  

59、60;49.                 else  50.                   51.            

60、;         newMax = newMin + max_min;  52.                     if (newMax > 255)  53.   

61、                    54.                         newMin = (int)(*p 

62、;- (ysmax.index + ysmid.index * hueCoef) * 255) /  55.                             (ysmin.index - ys

63、mid.index * (hueCoef - 1) + 0.5);  56.                         newMid = (int)(newMin + (255 - newMin) *&#

64、160;hueCoef + 0.5);  57.                         newMax = 255;  58.             

65、          59.                   60.                 pmax.index = newMa

66、x;  61.                 pmid.index = newMid;  62.                 pmin.index = newMin;  63

67、.               64.           65.       66.     _finally  67.       68.    

68、     bmp->UnlockBits(&data);  69.       70.   71.   72.   73. void ImageCompare(Bitmap *bmp1, Bitmap *bmp2)  74.   75.     int count,

69、 r_count = 0, g_count = 0, b_count = 0;  76.     int diff, r_diff = 0, g_diff = 0, b_diff = 0;  77.     BitmapData data1, data2; &

70、#160;78.     Gdiplus:Rect r(0, 0, bmp1->GetWidth(), bmp1->GetHeight();  79.   80.     bmp1->LockBits(&r, ImageLockModeRead, PixelFormat24bppRGB, &data1);  81.    &

71、#160;bmp2->LockBits(&r, ImageLockModeRead, PixelFormat24bppRGB, &data2);  82.     try  83.       84.         PRGBTRIPLE p1 = (PRGBTriple)data1.Scan0;

72、  85.         PRGBTRIPLE p2 = (PRGBTriple)data2.Scan0;  86.         int offset = data1.Stride - data1.Width * sizeof(RGBTRIPLE);  87.  

73、       for (unsigned y = 0; y < data1.Height; y +, (char*)p1 += offset, (char*)p2 += offset)  88.           89.   

74、60;         for (unsigned x = 0; x < data1.Width; x +, p1 +, p2 +)  90.               91.    

75、;             diff = p1->rgbtRed - p2->rgbtRed;  92.                 if (diff)  93.    &#

76、160;              94.                     r_count +;  95.          

77、60;          if (diff < 0) diff = -diff;  96.                     if (r_diff < diff) 

78、;r_diff = diff;  97.                   98.                 diff = p1->rgbtGreen - p2-&g

79、t;rgbtGreen;  99.                 if (diff)  100.                   101.      &#

80、160;              g_count +;  102.                     if (diff < 0) diff = -diff;

81、  103.                     if (g_diff < diff) g_diff = diff;  104.              &#

82、160;    105.                 diff = p1->rgbtBlue - p2->rgbtBlue;  106.                

83、60;if (diff)  107.                   108.                     b_count +;  109. &

84、#160;                   if (diff < 0) diff = -diff;  110.                  &#

85、160;  if (b_diff < diff) b_diff = diff;  111.                   112.               113.

86、           114.       115.     _finally  116.       117.         bmp2->UnlockBits(&data2);  118.  

87、       bmp1->UnlockBits(&data1);  119.       120.     count = data1.Width * data1.Height;  121.     String s;  122.    

88、; s.sprintf("像素總數(shù):%dn"     123.               "紅誤差數(shù):%d,誤差率:%d%,最大誤差:%dn"    124.              &

89、#160;"綠誤差數(shù):%d,誤差率:%d%,最大誤差:%dn"    125.               "藍(lán)誤差數(shù):%d,誤差率:%d%,最大誤差:%d",  126.               count,

90、60;r_count, (r_count * 100) / count, r_diff,  127.               g_count, (g_count * 100) / count, g_diff,  128.       &

91、#160;       b_count, (b_count * 100) / count, b_diff);  129.     ShowMessage(s);  130.   131. /-   132. void _fastcall TForm1:Button2Click(TObject *Sender) 

92、; 133.   134.     Bitmap *bmp1 = new Bitmap(WideString("d:GraySource.bmp");  135.     PSGrayImageTint(bmp1, 0x314ead);  136.   137.     Gdiplus:Graphics *g

93、 = new Gdiplus:Graphics(Canvas->Handle);  138.     g->DrawImage(bmp1, 0, 0);  139.     delete g;  140.   141.     / 同PS混合圖比較,bmp2為PS混合圖像   142.  

94、;   Bitmap *bmp2 = new Bitmap(WideString("d:Source314ead.bmp");  143.     ImageCompare(bmp1, bmp2);  144.   145.     delete bmp2;  146.     delet

95、e bmp1;  147.   148. /-  / 圖像著色。bmp:灰度背景圖象,color:顏色void PSGrayImageTint(Bitmap *bmp, Color color)const double ys = 0.11, 0.59, 0.3;RgbSwap max, mid, min;int newMax, newMid, newMin;int max_min, mid_min;double hueCoef;max.tmp = color.GetRed() + 0x20000;mid.tmp = colo

96、r.GetGreen() + 0x10000;min.tmp = color.GetBlue();if (max.value < mid.value)SwapRgb(max, mid);if (max.value < min.value)SwapRgb(max, min);if (min.value > mid.value)SwapRgb(min, mid);max_min = max.value - min.value;/ 飽和度為0,不著色返回if (max_min = 0) return;mid_min = mid.value - min.value;hueCoef =

97、 (double)mid_min / (double)max_min;BitmapData data;Gdiplus:Rect r(0, 0, bmp->GetWidth(), bmp->GetHeight();bmp->LockBits(&r, ImageLockModeRead | ImageLockModeWrite, PixelFormat24bppRGB, &data);tryunsigned char *p = (unsigned char*)data.Scan0;int offset = data.Stride - data.Width * 3;

98、for (unsigned y = 0; y < data.Height; y +, p += offset)for (unsigned x = 0; x < data.Width; x +, p += 3)newMid = (int)(*p - (max_min - mid_min) * ysmax.index +mid_min * ysmin.index + 0.5);newMin = newMid - mid_min;if (newMin < 0 | newMid <= 0)newMax = (int)(*p / (ysmax.index + ysmid.inde

99、x * hueCoef) + 0.5);newMid = (int)(newMax * hueCoef + 0.5);newMin = 0;elsenewMax = newMin + max_min;if (newMax > 255)newMin = (int)(*p - (ysmax.index + ysmid.index * hueCoef) * 255) /(ysmin.index - ysmid.index * (hueCoef - 1) + 0.5);newMid = (int)(newMin + (255 - newMin) * hueCoef + 0.5);newMax =

100、 255;pmax.index = newMax;pmid.index = newMid;pmin.index = newMin;_finallybmp->UnlockBits(&data);void ImageCompare(Bitmap *bmp1, Bitmap *bmp2)int count, r_count = 0, g_count = 0, b_count = 0;int diff, r_diff = 0, g_diff = 0, b_diff = 0;BitmapData data1, data2;Gdiplus:Rect r(0, 0, bmp1->GetW

101、idth(), bmp1->GetHeight();bmp1->LockBits(&r, ImageLockModeRead, PixelFormat24bppRGB, &data1);bmp2->LockBits(&r, ImageLockModeRead, PixelFormat24bppRGB, &data2);tryPRGBTRIPLE p1 = (PRGBTriple)data1.Scan0;PRGBTRIPLE p2 = (PRGBTriple)data2.Scan0;int offset = data1.Stride - data

102、1.Width * sizeof(RGBTRIPLE);for (unsigned y = 0; y < data1.Height; y +, (char*)p1 += offset, (char*)p2 += offset)for (unsigned x = 0; x < data1.Width; x +, p1 +, p2 +)diff = p1->rgbtRed - p2->rgbtRed;if (diff)r_count +;if (diff < 0) diff = -diff;if (r_diff < diff) r_diff = diff;dif

103、f = p1->rgbtGreen - p2->rgbtGreen;if (diff)g_count +;if (diff < 0) diff = -diff;if (g_diff < diff) g_diff = diff;diff = p1->rgbtBlue - p2->rgbtBlue;if (diff)b_count +;if (diff < 0) diff = -diff;if (b_diff < diff) b_diff = diff;_finallybmp2->UnlockBits(&data2);bmp1->UnlockBits(&data1);count = data1.Width * data1.Height;String s;s.

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論