在ARM上的快速AlphaBlend算法解析。透明框体实现。

1 篇文章 0 订阅

近来小弟研究AlphaBlend算法,即透明框在TQ2440+4.3寸屏上的显示透明框问题。几经周转  总结如下:


混合算法目前在常用到的算法是AlphaBlend。所谓Alpha-Blending,其实就是按照“Alpha”混合向量的值来混合源像素和目标像素。alpha-blending技术:渲染包含alpha通道值的图形即称为alpha-blending技术。渲染的意思是把包含alpha通道值的象素画在目标设备上。而目标设备本来就有背景色或者背景图片,目标设备可以是真正的显示屏,也可以是内存中的一块逻辑屏。

计算公式如下:假设一幅图象是A,另一幅透明的图象是B,那么透过B去看A,看上去的图象C就是B和A的混合图象,设B图象的透明度为alpha(取值为0-1,1为完全透明,0为完全不透明). Alpha混合公式如下:

                 R(C)=(1-alpha)*R(B) +alpha*R(A)

                  G(C)=(1-alpha)*G(B) +alpha*G(A)

                  B(C)=(1-alpha)*B(B) +alpha*B(A)

R(x)、G(x)、B(x)分别指颜色x的RGB分量原色值。从上面的公式可以知道,Alpha其实是一个决定混合透明度的数值。改变这个 alpha 值可以得到一个渐变的效果。分离RGB色用"位与"、"移位"运算的方法;透明的比例按2的N次幂来分级,这样可以快速运算。如果是按32级Alpha = 1/32,B图的权重 = (32-n)/32,则A图的权重=n/32,可以得到这样的算法:

R(C)=(32-n) * R(B)+ n* R(A);

再对R(C)右移5位(除以32)就可以了

具体算法如下:1)先把源像素和目标像素的 RGB 三个颜色分量分离。2)然后把源像素的三个颜色分量分别乘上 Alpha 的值,并把目标像素的三个颜色分量分别乘上 Alpha 的反值。3)把结果按对应颜色分量相加。4)对最后求得的每个分量结果除以 Alpha 的最大值(alpha值,16位色的色深为32级,故alpha取值0-32,故右移5位,编译器处理位移比除法快的多)。5)最后把三个颜色分量重新合成为一个像素输出。

在程序上,首先的读会某一像素点的值,这点可以借鉴天嵌的打印像素点函数,反向读取某一点对应的像素即可,程序修改为读取值c =LCD_BUFFER[(y)][(x)];读取后就将对就是对数据的分离了,用公式src2=((src<<16)|src)&0x07E0F81F;对目标像素进行转换成32为像素,并且像素格式由R:G:B改为了G:R:B格式,同样对源像素进行处理,把源图像乘以Alpha正直,目标图像乘以反值,将俩图像分量相加,dst2= src2*alpha+ (1- alpha)*dst2,alpha最大取值32则:dst2= src2*alpha+(32-alpha)*dst2/32,变形可得:dst2=(src2-dst2)*alpha/32+dst2,将处法变为位移得:dst2=((src2-dst2)*alpha)>>5+dst2,对得到结果去掉溢出位可得:dst2=((((src2-dst2)*alpha)>>5)+dst2)&0x07E0F81F;最后用(dst2>>16)|dst2;变回16位数据格式,则该dst2即为实现了透明框的像素点。依次转换需要实现的透明框的像素点即可实现透明框。从上面的流程可以看出,alpha值越大,透明效果就越弱。当alpha值达到最大时,就是不透明的,相反,如果alpha值为0。则是全透明。


快速ALPHA BLENDIN算法

//src:源颜色 //dst:目标颜色 //alpha:透明程度(0~32) //返回值:混合后的颜色.

u16 gui_alpha_blend565(u16src,u16 dst,u8 alpha)

{

    u32 src2;

    u32 dst2;  

    src2=((src<<16)|src)&0x07E0F81F;

    dst2=((dst<<16)|dst)&0x07E0F81F;   

    //dst2=((((dst2-src2)*alpha)>>5)+src2)&0x07E0F81F;

    dst2=((((src2-dst2)*alpha)>>5)+ dst2)&0x07E0F81F

    return (dst2>>16)|dst2;  

int GetPixel(U32 x, U32 y)  //读取原图像素点 由上面的函数改编过来

{

    U32 c;

    if((x < SCR_XSIZE_TFT) && (y < SCR_YSIZE_TFT))

        c = LCD_BUFFER[(y)][(x)];

    return c;

}

//x,y,width,height:区域设置//color:alphablend的颜色//aval:透明度(0~32)

void gui_alphablend_area(U16x,U16 y,U16 width,U16 height,U16 color,U8 aval)

{

    U16 i,j;

    U16 tempcolor;

    for(i=0;i<width;i++)

    {

        for(j=0;j<height;j++)

        {

            tempcolor=GetPixel(x+i, y+j);

            tempcolor=gui_alpha_blend565(tempcolor,color,aval);

            PutPixel(x+i,y+j,tempcolor);

        }

    }

}


在这里透过B去看A,或者透过A去看B,其实无非不过区别就是alpha的正值和alpha反值区别。程序的体现就在于

dst2=((((dst2-src2)*alpha)>>5)+src2)&0x07E0F81F;

    dst2=((((src2-dst2)*alpha)>>5)+ dst2)&0x07E0F81F;

最终效果都一样能实现透明框算法。无非不过 透明度取值问题。


64K 色模式下的快速 Alpha混合算法

在 32/64k 色模式下,由于每个点的 RGB 值是放在一个字里,以 16bit 色为例, 一般是按 RGB 或 BGR 565 存放. 传统的软件 Alpha 混合算法是先将 RGB 分离出来, 分开运算,然后再合成. 这造成了 16bit 模式下的 alpha 混合比 24bit 模式下慢 的现象,但使用 16bitcolor 真的那么慢吗? 我认为如果不使用 MMX 指令, 15/16 的比 24bit 的快. 因为我们可以使用一个小的技巧来同时计算 RGB. 而 24 bit 颜色,除非使用 MMX 指令,否则必须分开计算 R G B.

先设 color 是 RGB 565 的, 那么按 2 进制看, 这个颜色字是这样分布的:

RRRRR     GGGGGG   BBBBB

5位                    6位           5位

而 386 以上 CPU 都有 32 位的寄存器,我们只需要将 16bit RGB 变形为

00000       GGGGGG 00000       RRRRR     000000     BBBBB

5位                    6位 5位        5位           6位           5位

储存在 32 位寄存器中,(就是把绿色提到前 16 位里) 由于64k 色下颜色深度是 32 级的,所以 alpha 也只用分 32 级就能满足需要. 那么对上面变形过的双字处理,可以同时算 RGB 了. (Color1*Alpha+Color2*(32-Alpha))/32 能不能简化为(Color1-Color2)*Alpha/32+Color2.? 我思考过这个问题,以为减法将产生负数,这样再算乘法时有可能出问题,但是经过测试,这样简化似乎又没有问题. 毕竟极小的误差是可以忽略的

来源一:http://blog.csdn.net/xhhjin/article/details/6445460

 

alpha混合其实很简单,要做的只是分解源颜色c1,目的颜色c2,然后将颜色分量r1,g1,b1和r2,g2,b2分别按照公式(clr*alpha+clr*(32-alpha))/32来计算,最后再组合成一个颜色值即可,可是如此计算,运算量很大速度很慢。 所以现在就要用到一个技巧,首先,就16位色来说一般的格式是565,表示rgb分量的二进制位数,如图1。 那么我们就可以利用一个32位的变量来把这个颜色的绿色分量提前,变为如图2的格式。这样每个颜色分量中间就有了进位的空间,也就不用分解这个颜色值了。然后,将变形完的两个颜色值按照上面公式进行计算,计算完毕再变回565的格式就完成了一次alpha混合的计算。 

c语言源代码如下:

__inline void MakeAlpha(WORD* wpSrc, WORD* wpDes, WORD wAlpha)
{
   register DWORD d1; // 计算用的中间变量,声明为寄存器变量快些
   register WORD wa = *wpSrc; // 源颜色 
   register WORD wb = *wpDes; // 目的颜色
   register DWORD alpha = wAlpha; // alpha值,16位色的色深为32级,故alpha取值0-32
// (c1-c2)*alpha/32+c2
(c1*alpha+c2*(32-alpha))/32变形

// 而来,减少了一次乘法运算
//
下面的式子故意写成这样,编译器会把它处理的很好
//
要比这样快一些
// c1 = (((wa << 16) | wa) & 0x7e0f81f);

// 16位变形32 0x7e...f为二进制的00000111111000001111100000011111
// c2 = (((wb << 16) | wb) & 0x7e0f81f); 
// d1 = ((c1-c2)*alpha)>>5+c2;

// 除以32等于右移5位,但是位移操作要比乘除法快的多,

// 例如:a*320可以写成a*256+a*64=>(a<<8)+(a<<6)

   d1 = (((((((wa << 16) | wa) & 0x7e0f81f) - (((wb << 16) | wb) & 0x7e0f81f)) * alpha) >> 5) + (((wb << 16) | wb) &0x7e0f81f)) & 0x7e0f81f;
        wa = (d1 & 0xffff0000)>>16; // g...r...b => ..g..
        wb = d1 & 0xffff; // g...r...b => r...b
        *wpDes = wa | wb; // rgb
}

来源二:http://blog.chinaunix.net/uid-8272118-id-2033330.html


w_201505于百叶路

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值