C实现Photoshop图层颜色混合模式_第1页
C实现Photoshop图层颜色混合模式_第2页
C实现Photoshop图层颜色混合模式_第3页
C实现Photoshop图层颜色混合模式_第4页
C实现Photoshop图层颜色混合模式_第5页
已阅读5页,还剩30页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、  Photoshop提供了丰富的图象图层混合模式,其中的颜色混合模式是用下图层图象的亮度与上图层填充颜色或者图象色彩进行混合,形成的结果既有着上图层的色彩,又保留了下层图象的灰度,基于这种混合特性,颜色混合模式常用来对灰度图象进行着色。  如何用程序代码准确地实现Photoshop的图层颜色混合模式,一直是程序员们热衷的话题。本文采用BCB2007和GDI+等工具,较好地实现了其主要功能(不考虑不透明度和填充选项)。  按照Photoshop的解释,颜色混合模式是用上图层图象颜色的色相、饱和度与下图层图象像素的明度进行的混合。如此,我们在程序代码中,就需要首先将

2、上层图象颜色的色相、饱和度和下图层图象颜色的明度(亮度)提取出来,色相、饱和度的提取是按照HSV的方式进行的,然后按照下图层颜色明度按照0.3R +0.59G + 0.11B 的比例逐像素进行运算合成,可事实上,我在颜色合成过程中,无论是采用HSV还是HSL甚或其它HSB方式,均没法达到应有的效果。例如取上层颜色R=225,G=211,B=179,提取的H,S分别为42,20%,下层灰度为179,采用HSV或者SHL合成颜色的G,B均为0,而实际合成的R,G,B应分别为192,178,146。  通过在Photoshop中反复试验,发现上层颜色中的饱和度在合成过程中似乎没起

3、什么作用,最终合成结果只要保证上层颜色色相和下层灰度的比例不变就行了,这也是颜色混合模式的2个必要条件,其中灰度比例是必须保证的,如果二者发生冲突,可不考虑色相比例(如图象某像素的灰度为0或者255)。按照这个思路,我放弃了用HSB进行合成的方法,而按照上面2个条件采用解方程的方法来实现颜色混合。为此,可列出下列等式关系:1:Max - Min = a2:Mid - Min = b3:0.3R + 0.59G + 0.11B = c其中,Max,Mid,Min分别为上层颜色R、G、B分量中的最大、中间、最小值。等式1和2代表了上层颜色色相的比例关系,等式3则代表着下层颜色的灰度比例。如果只考虑

4、60度以内的色相和假定R>G>B,那么用上面的3个等式可列为下面的三元一次方程组:1)  R - B = a2)  G - B = b3)  0.3R + 0.59G + 0.11B = c  可以将满足色相在0 - 60范围,R>G>B的任何颜色的常数代入上面的方程组进行验算,其结果是正确的。但是实际的颜色混合是用2个颜色不同的灰度和色相,采用上面的方程组解出的RGB值有可能会超出0 - 255的范围,而我们又无法在方程组中加入这种范围限制,因此对于超出范围的RGB值,还必须在程序代码中进行调整。下面是我写的一个单像素

5、合成代码。view plaincopy to clipboardprint?1. /-   2. typedef union           / 颜色分量交换结构   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、 假设最大值=R,中间值=G,最小值=B,设置方程组:   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/ 颜色分量交换结构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;/ 假设最大值=R,中间值=G,最小值=B,设置方程组:/ 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函数写出了比较详细的解方程过程代码,并作了相应的注释;解三元一次方程组时,将灰度比例值扩大了100倍,可使用定点数运算,因为灰度比例关系恒等于100的缘故,运算过程中不会产生误差;其中对值超出0 - 255范围RGB值分别使用了2组二元一次方程进行了处理;另外,由于定义了一个RgbSwap类型,使得在比较和交换最大、最小值过程中,保存了原R、G、B信息,这不仅方便了代码中的运算,也使得前面的三元一次方程组的适用范围从色相60度以内和R>G>B,扩展到了色相全范围以及任意大小的R、G、B值,同时也避免了HSB转换为RGB

43、时通常使用的switch条件语句。  经过一定量的颜色混合测试,ColorMix函数表现较好,运算结果与实际误差始终在2的范围内,这属于正常的运算误差和灰度比例取值误差。  下面是一个对灰度图象进行着色的函数和测试代码: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("像素总数:%dn"     123.               "红误差数:%d,误差率:%d%,最大误差:%dn"    124.              &

89、#160;"绿误差数:%d,误差率:%d%,最大误差:%dn"    125.               "蓝误差数:%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. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论