<!-- [if gte mso 9]><xml>
<w:WordDocument>
<w:View>Normal</w:View>
<w:Zoom>0</w:Zoom>
<w:PunctuationKerning/>
<w:DrawingGridVerticalSpacing>7.8 磅</w:DrawingGridVerticalSpacing>
<w:DisplayHorizontalDrawingGridEvery>0</w:DisplayHorizontalDrawingGridEvery>
<w:DisplayVerticalDrawingGridEvery>2</w:DisplayVerticalDrawingGridEvery>
<w:ValidateAgainstSchemas/>
<w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid>
<w:IgnoreMixedContent>false</w:IgnoreMixedContent>
<w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText>
<w:Compatibility>
<w:SpaceForUL/>
<w:BalanceSingleByteDoubleByteWidth/>
<w:DoNotLeaveBackslashAlone/>
<w:ULTrailSpace/>
<w:DoNotExpandShiftReturn/>
<w:AdjustLineHeightInTable/>
<w:BreakWrappedTables/>
<w:SnapToGridInCell/>
<w:WrapTextWithPunct/>
<w:UseAsianBreakRules/>
<w:DontGrowAutofit/>
<w:UseFELayout/>
</w:Compatibility>
<w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel>
</w:WordDocument>
</xml><![endif]--><!-- [if gte mso 9]><xml>
<w:LatentStyles DefLockedState="false" LatentStyleCount="156">
</w:LatentStyles>
</xml><![endif]--><!-- [if !mso]>
<
classid="clsid:38481807-CA0E-42D2-BF39-B33AF135CC4D" id=ieooui>
</object>
<mce:style><!--
st1\:*{behavior:url(#ieooui) }
-->
<!-- [endif]-->
<!-- [if gte mso 10]>
<mce:style><!--
/* Style Definitions */
table.MsoNormalTable
{mso-style-name:普通表格;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-parent:"";
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin:0cm;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:10.0pt;
font-family:"Times New Roman";
mso-ansi-language:#0400;
mso-fareast-language:#0400;
mso-bidi-language:#0400;}
-->
<!-- [endif]-->
Alpha
混合的算法很简单,基于下面的公式就可以实现:
D := A * (S - D) / 255 + D
D
是目标图像的像素,
S
是源图像的像素
A
是
Alpha
值,
0
为全透明,
255
为不透明。
下面是
16
位
565
格式的混合算法的实现,首先用最简单的方式实现,即逐个像素的处理:
//
一次处理一个像素,比较简单,但速度较慢
procedure AlphaBlend656(BmpDst, BmpSrc:
TBitmap; Alpha: Byte);
var
i,
j, W, H: Integer;
pSrc, pDst: PWord;
wSR, wSG, wSB: Word;
wDR, wDG, wDB: Word;
begin
//
确定高宽
if
BmpDst.Width > BmpSrc.Width then
W
:= BmpSrc.Width
else
W
:= BmpDst.Width;
if
BmpDst.Height > BmpSrc.Height then
H
:= BmpSrc.Height
else
H
:= BmpDst.Height;
for
i := 0 to H - 1do
begin
pSrc := BmpSrc.ScanLine[i];
pDst := BmpDst.ScanLine[i];
for j := 0 to W - 1 do
begin
// D := A * (S - D) / 255 + D
wSR := (pSrc^ shr 11);
wSG := (pSrc^ shr 5) and $3F;
wSB := pSrc^ and $1F;
wDR := (pDst^ shr 11);
wDG := (pDst^ shr 5) and $3F;
wDB := pDst^ and $1F;
pDst^ := (((Alpha * (wSR - wDR) shr 8) + wDR) shl 11) or
(((Alpha * (wSG - wDG) shr 8) +
wDG) shl 5) or
((Alpha * (wSB - wDB) shr 8) +
wDB);
Inc(pSrc);
Inc(pDst);
end;
end;
end;
实现起来很简单,但速度比较慢,其实存在着一次处理两个像素的算法,下面是代码:
//
一次处理两个像素
,
所以速度是
AlphaBlend656
的
2
倍
procedure AlphaBlend656Fast(BmpDst, BmpSrc:
TBitmap; Alpha: Byte);
var
i,
j, W, H: Integer;
pSrc, pDst: PWord;
dwSR, dwSG, dwSB: LongWord;
dwDR, dwDG, dwDB: LongWord;
dwAdd64 : LongWord;
dwAlphaOver4 : LongWord;
odd: Boolean;
begin
//
确定高宽
if
BmpDst.Width > BmpSrc.Width then
W
:= BmpSrc.Width
else
W
:= BmpDst.Width;
if
BmpDst.Height > BmpSrc.Height then
H
:= BmpSrc.Height
else
H
:= BmpDst.Height;
dwAdd64 := 64 or ( 64 shl 16 );
dwAlphaOver4 := ( Alpha shr 2 ) or ( ( Alpha shr 2 ) shl 16 );
if
(W and $01) = 1 then
begin
odd := True;
W
:= (W - 1) shr 1;
end
else begin
odd := False;
W
:= W shr 1;
end;
for
i := 0 to H - 1 do
begin
pSrc := BmpSrc.ScanLine[i];
pDst := BmpDst.ScanLine[i];
for j := 0 to W - 1 do
begin
// D := A * (S - D) / 255 + D
dwSR := (PLongWord(pSrc)^ shr 11) and $001F001F;
dwSG := (PLongWord(pSrc)^ shr 5) and $003F003F;
dwSB := PLongWord(pSrc)^ and $001F001F;
dwDR := (PLongWord(pDst)^ shr 11) and $001F001F;
dwDG := (PLongWord(pDst)^ shr 5) and $003F003F;
dwDB := PLongWord(pDst)^ and $001F001F;
PLongWord(pDst)^ := ((((Alpha * (dwSR + dwAdd64 - dwDR)) shr 8) + dwDR -
dwAlphaOver4) and $001F001F) shl 11 or
((((Alpha * (dwSG + dwAdd64 -
dwDG)) shr 8) + dwDG - dwAlphaOver4 ) and $003F003F)
shl 5 or
(((Alpha * (dwSB + dwAdd64 -
dwDB)) shr 8) + dwDB - dwAlphaOver4 ) and $001F001F;
Inc(pSrc, 2);
Inc(pDst, 2);
end;
if odd then
begin
dwSR := (pSrc^ shr 11);
dwSG := (pSrc^ shr 5) and $3F;
dwSB := pSrc^ and $1F;
dwDR := (pDst^ shr 11);
dwDG := (pDst^ shr 5) and $3F;
dwDB := pDst^ and $1F;
pDst^ := Word((((Alpha * (dwSR - dwDR) shr 8) + dwDR) shl 11) or
(((Alpha * (dwSG - dwDG) shr 8)
+ dwDG) shl 5) or
((Alpha * (dwSB - dwDB) shr 8) +
dwDB));
Inc(pSrc);
Inc(pDst);
end;
end;
end;
不过这还不够快,基本
MMX
指令的实现可以一次处理
4
个像素,下面是代码:
//
利用
MMX
优化指令,一次可以处理
4
个像素,因此速度应该是
AlphaBlend656
的
4
倍
procedure AlphaBlend656MMX(BmpDst, BmpSrc:
TBitmap; Alpha: Byte);
var
i,
j, W, H, Leave: Integer;
pSrc, pDst: PWord;
MaskR, MaskG, MaskB, Alpha64: Int64;
wSR, wSG, wSB: Word;
wDR, wDG, wDB: Word;
begin
//
确定高宽
if
BmpDst.Width > BmpSrc.Width then
W
:= BmpSrc.Width
else
W
:= BmpDst.Width;
if
BmpDst.Height > BmpSrc.Height then
H
:= BmpSrc.Height
else
H
:= BmpDst.Height;
Leave := W and 3;
//
剩余的像素
W
:= W shr 2;
//
一次处理
4
个像素,因此取
W
整除
4
的值
//
提取
RGB
通道的掩码
MaskR := $f800f800f800f800;
MaskG := $07e007e007e007e0;
MaskB := $001f001f001f001f;
//
Alpha
值扩展到
64
位
Alpha64 := Alpha;
Alpha64 := Alpha64 or (Alpha64 shl 16) or (Alpha64 shl 32) or (Alpha64
shl 48);
for
i := 0 to H - 1do
begin
pSrc := BmpSrc.ScanLine[i];
pDst := BmpDst.ScanLine[i];
asm
push
ecx
//
保存寄存器
mov
ecx, W
//
设宽度
cmp
ecx, 0
//
宽度是否为
0
jz
@@exit565
//
如果宽度为
0
,结束
push
esi
push
edi
mov
esi, pSrc
//
开始处理
mov
edi, pDst
@@blend565_4:
{
mmx
的作用:
mm0:
red target value
mm1:
red source value
mm2:
green target value
mm3:
green source value
mm4:
blue target value
mm5:
blue source value
mm6:
original target pixel
mm7:
original source pixel
D := A * (S - D) / 255 + D
}
movq
mm6, [edi]
movq
mm7, [esi]
movq
mm0, mm6
pand
mm0, MaskR
//
提取目标的
R
通道
movq
mm1, mm7
pand
mm1, MaskR
//
提取源的
R
通道
psrlw
mm0, 11
//
右移到最低位,便于接下来的计算
psrlw
mm1, 11
psubw
mm1, mm0
// SrcRed := SrcRed - DestRed
pmullw
mm1, Alpha64
// SrcRed := SrcRed * Alpha
psraw
mm1, 8
// SrcRed := SrcRed div 8
paddw
mm1, mm0
// SrcRed := SrcRed + DestRed
psllw
mm1, 11
//
左移回原来的位置,此已经
R
通道混合已经完毕
movq
mm2, mm6
pand
mm2, MaskG
//
提取目标的
G
通道
movq
mm3, mm7
pand
mm3, MaskG
//
提取源的
G
通道
psrlw
mm2, 5
//
右移到最低位,便于接下来的计算
psrlw
mm3, 5
psubw
mm3, mm2
// SrcGreen := SrcGreen - DestGreen
pmullw
mm3, Alpha64
// SrcGreen := SrcGreen * Alpha
psraw
mm3, 8
// SrcGreen := SrcGreen div 8
paddw
mm3, mm2
// SrcGreen := SrcGreen + DestGreen
psllw
mm3, 5
//
左移回原来的位置,此已经
G
通道混合已经完毕
movq
mm4, mm6
pand
mm4, MaskB
//
提取目标的
B
通道
movq
mm5, mm7
pand
mm5, MaskB
//
提取源的
B
通道
psubw
mm5, mm4
// SrcBlue := SrcBlue - DestBlue
pmullw
mm5, Alpha64
// SrcBlue := SrcBlue * Alpha
psraw
mm5, 8
// SrcBlue := SrcBlue div 8
paddw
mm5, mm4
// SrcBlue := SrcBlue + DestBlue
,此已经
B
通道混合已经完毕
por
mm1, mm3
//
合成像素
por
mm1, mm5
movq
[edi], mm1
//
赋给目标
add
esi, 8
//
下
4
个像素
add
edi, 8
dec
ecx
jnz
@@blend565_4
mov
pSrc, esi
mov
pDst, edi
pop
edi
pop
esi
emms
@@exit565:
pop
ecx
end;
//
处理剩下的像素
for j := 0 to Leave - 1 do
begin
wSR := (pSrc^ shr 11);
wSG := (pSrc^ shr 5) and $3F;
wSB := pSrc^ and $1F;
wDR := (pDst^ shr 11);
wDG := (pDst^ shr 5) and $3F;
wDB := pDst^ and $1F;
pDst^ := (((Alpha * (wSR - wDR) shr 8) + wDR) shl 11) or
(((Alpha * (wSG - wDG) shr 8) +
wDG) shl 5) or
((Alpha * (wSB - wDB) shr 8) +
wDB);
Inc(pSrc);
Inc(pDst);
end;
end;
end;
下面是这三个函数的速度比较,目标图像是
600*450
的
16
位位图,源图像是
399*532
的
16
位位图,分别进行了
1000
次混合,结果如下:
AlphaBlend656
:
4516
AlphaBlend656Fast
:
2562
AlphaBlend656MMX
:
1234
没有意外,
MMX
版本比普通的快了近
4
倍
对于图像处理的优化有两个比较重要的点:
<!-- [if !supportLists]-->1、
<!-- [endif]-->尽量用位移代替乘除。
<!-- [if !supportLists]-->2、
<!-- [endif]-->一次能够同时处理多个像素,利用
MMX
指令可以做到这一点。
最后是代码:
https://files.getdropbox.com/u/524963/AlphaBlend16_565.rar
分享到:
相关推荐
基于FPGA的Alpha半透明图像叠加算法硬件实现.pdf
用alpha混合,为a.png替换一张新的背景(背景图自选); 2.1:图像缩放 实现一个图像缩放函数,可以对输入图像进行任意倍数的缩放; 采用双线性插值进行重采样; X,Y方向的缩放倍数参函数参数的形式传入; 可以只考虑...
数字图像处理 图像合成 vc++6.0环境
在各类有关.Net的技术论坛上常有人问如何实现透明的图像或图形效果,答案很简单,就是Alpha Blending技术。Alpha Blending技术是一个混合各种颜色值并产生透明效果的过程。具体的实现原理也很简单:在GDI+中,任何一...
此 GUI 实现了 Image Acquisition Toolbox 文档中的演示“流式图像对的 Alpha 混合”。 它旨在展示如何创建一个简单的 GUI,该 GUI 在图像采集工具箱获取图像时执行图像处理。 该演示将背景图像与新获取的用户指定...
laplacianBlend:MATLAB脚本,使用拉普拉斯金字塔金字塔混合技术将两个图像混合在一起,并给出了将两个图像分开的alpha蒙版
易语言RGB颜色Alpha混合源码 要绘制半透明效果,当然是GDIPlus比较方便。但是GDIPlus效率太低了,不是必要的情况下...这个纯算法实现的RGB颜色Alpha混合,对于不使用GDIPlus情况下的半透明绘制,还是有一定参考作用的。
图像处理是指使用计算机算法和技术对图像进行分析、增强、修改或生成的过程。其中,背景抠图(Background ...可以使用图像融合算法(如拉普拉斯金字塔融合、Alpha混合等)将前景与背景进行平滑地混合,以实现自然的效
易语言RGB颜色Alpha混合源码例程程序调用API函数实现RGB模式下,Alpha混合,返回混合后的RGB颜色。
中文名: 图形图像处理实用教程 作者: 柳青图书分类: 软件 资源格式: PDF 版本: 文字版 出版社: 高等教育出版社书号: 978-7-04-012336-4发行时间: 2003年06月 地区: 大陆 语言: 简体中文 简介: 内容简介: 图形...
3EGame图形引擎独特的地方在于把DirectX中所有的工具封装成一个DirectX类,可以很轻松... 在这里我们主要介绍在这个图形引擎中我们是如何实现加载,绘制图形,并且实现一定的特效的(半透明效果即Alpha混合通道)。
注意:在min/max操作中会忽略混合因子。这些运算符也可用于alpha混合方程。注意,RGB混合方程和alpha混合方程可以使用不同的运算符。
该实现包括通过SIFT描述符进行特征点检测,通过KNN(来自)进行图像匹配,最后通过alpha进行混合以及多波段混合。 该项目使用了OPENCV,ANN库。 输入输出: 输入:Image_list.txt,其中包含序列图像和相应的焦距,...
考虑对两个多边形(1和2)进行alpha混合,不同的绘制次序会得到不同的结果。(这里假定多边形1离观察者最近,那么正确的过程应该先画多边形2,再画多边形1。正如您再现实中所见到的那样,从这两个<透明的>多边形背后...
nkscape是开源的矢量图像编辑软件,与Illustrator、Freehand、CorelDraw、Xara X 等软件很相似,它使用 W3C 标准的 ScalableVector Graphics (SVG) 文件格式,支持包括形状、路径、文本、标记、克隆、alpha 混合、...
本系列文章介绍了一种在图像处理、2D游戏、3D游戏中经常使用的图片混合模型:Alpha颜色混合
在第一个示例中,我们渲染一个红色视频,在第二个示例中,我们使用GDI+加载JPEG图像并渲染一次,即当frame_cnt为零时,在第三个示例中,我们显示第一个图像并慢慢与第二个图像进行alpha混合,直到它出现,在最后一个...
在第一个示例中,我们渲染一个红色视频,在第二个示例中,我们使用GDI+加载JPEG图像并渲染一次,即当frame_cnt为零时,在第三个示例中,我们显示第一个图像并慢慢与第二个图像进行alpha混合,直到它出现,在最后一个...
Graphics32图像控件是专门用于Windows Bitmap快速绘图构件及函式库,能够轻易制作半透明视觉效果,可以作出图层效果,缩放,Alpha混合,角度旋转等多种图像效果。 带有六个控件: TPaintBox32, TImage32, ...
功能极为强大,与Windows、MFC支持极好,支持图像的多种操作(线性滤波、中值滤波、直方图操作、旋 转缩放、区域选取、阈值处理、膨胀腐蚀、alpha混合等等),支持从文件、内存或者win32api定义的位图图像格式中读取...