没画完的画

喂马 劈柴 BBQ~
posts - 37, comments - 55, trackbacks - 0, articles - 0
  C++博客 ::  :: 新随笔 :: 联系 :: 聚合  :: 管理

[Z]Alpha通道实现

Posted on 2008-09-19 16:17 没画完的画 阅读(2270) 评论(5)  编辑 收藏 引用 所属分类: VC

图形学中,Alpha指的是除了颜色的三个分量(RGB)外的第四个分量,透明度
一个真彩色的像素由四个分量组成,RGBA
Alpha 的值在 0 到 1 之间,0表示完全透明,1 表示完全覆盖
 
图像A 和 图像B 组合而成的图像为 C
A: (R_Value_A, G_Value_A, B_Value_A, Alpha_A)
B: (R_Value_B, G_Value_B, B_Value_B, Alpha_B)
混合后的C 颜色为

R_Value_C = R_Value_A * Alpha_A + R_Value_B * Alpha_B
G_Value_C = G_Value_A * Alpha_A + G_Value_B * Alpha_B
B_Value_C = B_Value_A * Alpha_A + B_Value_B * Alpha_B


具体实现代码:

/**
 * alpha 值的范围为 0 ~ 255
 */

inline COLORREF AlphaPixel(UINT alpha, COLORREF clr1, COLORREF clr2)
{
    
double k = (double)alpha / 256.0;
    
double reverse_k = 1.0 - k;
    BYTE r 
= BYTE( GetRValue(clr2) * k + GetRValue(clr1) * reverse_k );
    BYTE g 
= BYTE( GetGValue(clr2) * k + GetGValue(clr1) * reverse_k );
    BYTE b 
= BYTE( GetBValue(clr2) * k + GetBValue(clr1) * reverse_k );
    
return RGB(r, g, b);
}


透明度 
50%

 
for(int i = 0; i < size.cx; i++)
 
{
  
for ( int j = 0; j < size.cy; j++ )
  
{
   pDC
->SetPixel(i, j, AlphaPixel(255 / 2, RGB(255255255), dc.GetPixel(i, j)) );
  }
// for j
 }
// for i


如此算法,如果是1024 * 768 的图,就很慢了,需要想办法优化

饿了,先去吃饭再研究~

吃完饭,继续

windows已经提供了 实现alpha混合的API
BOOL AlphaBlend(
HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest,  int nHeightDest,
HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc,
BLENDFUNCTION blendFunction);
前面十个参数不用说了,主要在最后一个参数

typedef struct _BLENDFUNCTION
{
    BYTE   BlendOp;                    // BlendOp字段指明了源混合操作,但只支持AC_SRC_OVER,即根据源alpha值把源图像

叠加到目标图像上
                                             // OpenGL的alpha混合还支持其他的方式,如常量颜色源。
    BYTE   BlendFlags;                // 保留字段,必须是 0
    BYTE   SourceConstantAlpha; //
    BYTE   AlphaFormat;             // 0表示常量alpha值,AC_SRC_ALPHA表示每个像素有各自的alpha通道。
} BLENDFUNCTION;

BLENDFUNCTION结构控制源和目标位图的混合方式

如果AlphaFormat字段为0,源位图中的所有像素使用同样的常量alpha值,即SourceConstantAlpha字段中的值,该值实际上是0和255

,而不是0和1。这里0表示完
全透明,255表示完全不透明。目标像素以255-SourceConstantAlpha值作为alpha值。
如果AlphaFormat字段的值是AC_SRC_ALPHA,源设备表面的每个像素必须有各自的alpha通道。即,必须是32-bpp的物理设备上下文

,或是选中了32-bpp DDB和DIB
段的内存设备上下文。这些情况下,每个源像素有4个8位通道:红、绿、蓝和alpha。每个像素的alpha通道和SourceConstantAlpha

字段一起用于把源和目标混合
起来。实际用于计算的运算式如下:
Tmp.Red   = Src.Red   * SourceConstantAlpha / 255;
Tmp.Green = Src.Green * SourceConstantAlpha / 255;
Tmp.Blue  = Src.Blue  * SourceConstantAlpha / 255;
Tmp.Alpha = Src.Alpha * SourceConstantAlpha / 255;
Beta      = 255 – Tmp.alpha;
Dst.Red   = Tmp.Red   + Round((Beta * Dst.Red  )/255);
Dst.Green = Tmp.Green + Round((Beta * Dst.Green)/255);
Dst.Blue  = Tmp.Blue  + Round((Beta * Dst.Blue )/255);
Dst.Alpha = Tmp.Alpha + Round((Beta * Dst.Alpha)/255);

如果AlphaFormat字段的值是AC_SRC_ALPHA 的情况还没搞懂是什么意思

Feedback

# re: [Z]Alpha通道实现  回复  更多评论   

2008-09-19 16:36 by lonkil
去掉浮点,alpha直接用0-255处理;
乘除用移位操作;
速度可能会快一点。

# re: [Z]Alpha通道实现  回复  更多评论   

2008-09-19 17:49 by lonkil
我以前写的一个16位的混合。

//16位单像素的Alpha混合
GUI_COLOR PixelAlpha_565(U16 sour, U16 desc, U8 nAlpha )
{
U32 R=0,G=0,B=0,R1=0,G1=0,B1=0;
GUI_COLOR clr=0,clr1=0;
static int n=0;
//提取GUI_COLOR的RGB
R = ( sour >> 11 ) & 0x1f;
G = ( sour >> 5 ) & 0x3f;
B = sour & 0x1f;

R1 = ( desc >> 11 ) & 0x1f ;
G1 = ( desc >> 5 ) & 0x3f;
B1 = desc & 0x1f;

//混合
R = (( ( R - R1 ) * nAlpha ) >> 8 ) + R1;
G = (( ( G - G1 ) * nAlpha ) >> 8 ) + G1;
B = (( ( B - B1 ) * nAlpha ) >> 8 ) + B1;

clr = ( B << 19 ) | ( G << 10 ) | R<<3;

return clr;
}

其实混合算法优化还是值得研究的,如果不在windows下就没有AlphaBlend可用了。

# re: [Z]Alpha通道实现  回复  更多评论   

2008-09-19 20:30 by 没画完的画
感谢 lonkil 提出的建议.

# re: [Z]Alpha通道实现  回复  更多评论   

2008-09-19 21:29 by 陈梓瀚(vczh)
用汇编,将一个寄存器的四个字节XXXX分别写成0R0G,R和G就能一起算了。如此类推。

好象是4年前吧,我用delphi实现过一个,爆快。

# re: [Z]Alpha通道实现  回复  更多评论   

2008-09-19 21:30 by 陈梓瀚(vczh)
AlphaBlend是不能用的,他那个blend function不是完整的,需要事先做点儿事情。

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理