在网站上看到过很多Alpha混合计算的相关文档,其中不乏经典之作,但大多数都是基于16位显示模式下的,而256色的却很少有人谈及。所以,决定写一个基于256色的Alpha混合算法的详细实现方法。以帮助那些初学者,给他们一点点小小的灵感:)
首先,假设你已经有了一个调色板,我们将根据这个调色板来计算和创建一个Alpha_Map[256][256]的二维整形数组,这个数组用来存放混合后的颜色对应于(或近似)这个调色板中的索引值。
然而,我们如何获得这个索引值呢?这就需要进行一个求近似值的函数Find_Index(),这个函数主要负责根据给定的三个基色的值,从调色板中找到相同颜色或最接近颜色的索引值,并返回这个索引值。此函数还需要一个结构:BEST_FIT,它的定义是:
typedef struct BEST_FIT_TYP { int sum; // 累加值 int index; // 索引值 }BEST_FIT;
有了这个结构,就可以写Find_Index()函数了,函数原形如下:
int Find_Index(BYTE R, BYTE G, BYTE B, PALETTEENTRY *palette) { int rn = 0, // Red差值分量 gn = 0, // Green差值分量 bn = 0; // Blue差值分量
BEST_FIT best; best.sum = 100; // 初始赋给累加值一个最大值 best.index = 0; // 初始化索引值
for (int index = 0; index < 256; index++) {// 遍历调色板 rn = palette[index].peRed - R; // 计算差值,以下相同 if (rn < 0) rn = -rn; // 求绝对值,以下相同 gn = palette[index].peGreen - G; if (gn < 0) gn = -gn; bn = palette[index].peBlue - B; if (bn < 0) bn = -bn;
if (best.sum > (rn + gn + bn)) // 判断三个分量的累加值是否大于原来的累加值 { best.sum = rn + gn + bn; // 更新累加值 best.index = index; // 更新索引值 if (0 == best.sum) // 如果累加值为零,即颜色匹配 { return(best.index); // 返回索引值 break; }// end if }// end if
}// end for return(best.index); // 返回近似值 }
这个函数可以返回一个索引值,这样我们就能利用这个索引值建立Alpha_Map[256][256]查色表了。
现在我们终于能够开始建立查找表了,这是一个50%的Alpha混合函数,如果需要的话,你可以改变混合级别。
首先,在这里需要说明一下函数的公式由来,以方便读者理解。
先说说PALETTEENTRY这个结构,结构定义如下:
typedef struct tagPALETTEENTRY { BYTE peRed; BYTE peGreen; BYTE peBlue; BYTE peFlags; } PALETTEENTRY;
这个结构分别用3个字节表示RGB三基色的值。
我们可以用这三个基色值进行50%的Alpha混合运算。公式如下所示:
srcRGB:原点颜色值 destRGB:目标点颜色值 RGB:结果 alpha:混合级数,开始为一个0--1之间的浮点数,我们一般将它转换为整形进行计算。因为这里是50%的混合运算,所以它的值就是0.5。 Alpha混合基本公式: RGB = 0.5 * srcRGB + (1 – 0.5) * destRGB; 将其进行化简,就得到了下式: RGB = 0.5 * (srcRGB + destRGB); 乘以0.5就相当于向右移1位,所以最后的公式就是: RGB = (srcRGB + destRGB) >> 1;
根据这个公式,就能够获得一个50%的Alpha混合的RGB的色彩值,在这里由于是用调色板做的,所以,RGB要分开来计算。
下面就是初始化Alpha_Map[256][256]的函数,里面调用了前面的Find_Index()函数;
void Alpha_Init(PALETTEENTRY *palette) { for (int index1 = 0; index1 < 256; ++index1) for (int index2 = 0; index2 < 256; ++index2) { R = (palette[index1].peRed + palette[index2].peRed) >> 1; G = (palette[index1].peGreen + palette[index2].peGreen) >> 1; B = (palette[index1].peBlue + palette[index2].peBlue) >> 1;
Alpha_Map[index1][index2] = Find_Index(R, G, B, palette);; }// end for }
这样,我们便完成了基于256色的Alpha混合运算的查找表,当我们需要进行Alpha混合运算的时候,直接可以用源色和目的色的索引值作为数组下标,来从这个表中找到一个近似的颜色。
本人第一次发表这类文档,有不足之处和疏漏的地方,还望高手指教,强烈需求一起学习和研究。我的邮箱是:song_zp@126.com。欢迎来信!
|