像素Alpha运算,能不能用移位代替除法? 本帖最后由 Soyokaze 于 2010-07-21 12:02:37 编辑 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 >> 8这个是除以256 分别用两种方法生成了一个 WS_EX_LAYERED 风格的窗口,然后置于相同的背景中。接着分别在同一位置取色进行对比,可见差别并不大。移位方法的图:除以255的图: Soyokaze 如果你不是 做专业的图像处理软件,而是在自己的界面上使用图像特效,这样做是可以的。基本上两者在视觉上无多大的差距。 移位运算效率确实高于除法运算,而且两者相差不大,不是高精度可以考虑,不过高倍加速还是建议MMX/SSE 我用内嵌汇编用MMX实现了一下,和用一般方法实现的对比了一下,发现速度不但没有提高,反倒减慢了,郁闷+不得其解中...下面是两种方法的程序段,大家给帮着看看问题出在哪里(IDE用的PureBaic):Structure Pixel32 b.a g.a r.a a.aEndStructure*pBase = DrawingBuffer()cbPerLine.l = DrawingBufferPitch()*pPixel = *pBaselPixel.l*pixel32.Pixel32 = @lPixelFor j = 1 To szBmp\cy For i = 1 To szBmp\cx lPixel = PeekL(*pPixel) *pixel32\b = (*pixel32\b * *pixel32\a) >> 8 *pixel32\g = (*pixel32\g * *pixel32\a) >> 8 *pixel32\r = (*pixel32\r * *pixel32\a) >> 8 PokeL(*pPixel, lPixel) *pPixel + 4 Next i *pPixel = *pBase + cbPerLine * jNext jPXOR mm7, mm7 ;清零MOV eax, $00ffffffMOVD mm6, eaxMOV eax, $ff000000MOVD mm5, eaxMOV ecx, szBmp\cyMOV j, ecxMOV eax, 1EntryY:MOV ecx, szBmp\cxMOV i, ecxEntryX:MOV ecx, *pPixelMOVD mm0, [ecx] ;取像素MOVQ mm2, mm0PUNPCKLBW mm0, mm7 ;拆为 0A 0R 0G 0B(每字符代表1个字节,后同)MOVQ mm1, mm0PUNPCKHWD mm1, mm1 ;拆为 0A 0A 0R 0RPUNPCKHDQ mm1, mm1 ;拆为 0A 0A 0A 0APMULLW mm0, mm1PSRLW mm0, 8PACKUSWB mm0, mm7PAND mm0, mm6PAND mm2, mm5POR mm0, mm2MOVD [ecx], mm0 ;放回ADD *pPixel, 4DEC iJNZ l_entryx ;x循环截止MOV ecx, eax ;保存(不能压栈)MUL cbPerLineADD eax, *pBaseMOV *pPixel, eax ;下一行首地址MOV eax, ecxINC eaxDEC jJNZ l_entryy ;y循环截止EMMS 编译器再怎么优化也不可能会去调用MMX的啊 __asm { PXOR MM7,MM7 //MM7=0 MOVD MM0,[esi] //MM0=src; MOVD MM2,[edi] //MM2=dst; PUNPCKLBW MM0,MM7 //MM0转QWORD AABBGGRR->00AA00BB00GG00RR PUNPCKLBW MM2,MM7 //MM2转QWORD AABBGGRR->00AA00BB00GG00RR MOVQ MM1,MM0 //MM1=MM0 PUNPCKHWD MM1,MM1 //MM1 00AA00BB00GG00RR->00AA00AA00CC00CC PUNPCKHDQ MM1,MM1 //MM1 00AA00AA00CC00CC->00AA00AA00AA00AA PSUBW MM0,MM2 //MM0 -= MM2 PSLLW MM2,8 //MM2右移8位 00AA00BB00GG00RR->AA00BB00GG00RR00 PMULLW MM0,MM1 //MM0 *= MM1 PADDW MM2,MM0 //MM2 += MM0 PSRLW MM2,8 //MM2以Word为单位右移8位 AA??BB??GG??RR??->00AA00BB00GG00RR PACKUSWB MM2,MM7 //MM2转DWORD 00AA00BB00GG00RR->AABBGGRR MOVD [edi],MM2 } 这段代码实现的是Alpha混合:Dst.Red = Src.Red * (Src.Alpha/255.0) + Dst.Red * (1.0 - (Src.Alpha/255.0))Dst.Green = Src.Green * (Src.Alpha/255.0) + Dst.Green * (1.0 - (Src.Alpha/255.0))Dst.Blue = Src.Blue * (Src.Alpha/255.0) + Dst.Blue * (1.0 - (Src.Alpha/255.0))而不是我要的预乘:Src.Red = Src.Red * Src.Alpha / 255Src.Green = Src.Green * Src.Alpha / 255Src.Blue = Src.Blue * Src.Alpha / 255不过还是谢谢,可以触类旁通。 在线等待vc源程序复制到另个地方打开程序没有类库了 关于CListCtrl右键菜单 为什么我的picture control上的图片会变花和消失 请问这些错误如何解决 有谁有读取INI文件突破64K限制的类,急求 VC++6里面有没有现成的FTP类供使用?急! 我在用VC做一个控制台应用程序,但不知道怎么清除屏幕,请各位赐教。 为什么不响应我的键盘事件 关于消息顺序:1.先post的消息一定先到达消息队列吗?2.先到达的消息一定会先被处理吗? 如何写http server,提供思路或有例子最好了 MFC最经典的开源码是哪一个! MFC的内容怎么这么多啊,学都学不完。
这个是除以256
除以255的图:
如果你不是 做专业的图像处理软件,而是在自己的界面上使用图像特效,这样做是可以的。基本上两者在视觉上无多大的差距。
Structure Pixel32
b.a
g.a
r.a
a.a
EndStructure
*pBase = DrawingBuffer()
cbPerLine.l = DrawingBufferPitch()
*pPixel = *pBase
lPixel.l
*pixel32.Pixel32 = @lPixel
For j = 1 To szBmp\cy
For i = 1 To szBmp\cx
lPixel = PeekL(*pPixel)
*pixel32\b = (*pixel32\b * *pixel32\a) >> 8
*pixel32\g = (*pixel32\g * *pixel32\a) >> 8
*pixel32\r = (*pixel32\r * *pixel32\a) >> 8
PokeL(*pPixel, lPixel)
*pPixel + 4
Next i
*pPixel = *pBase + cbPerLine * j
Next j
PXOR mm7, mm7 ;清零
MOV eax, $00ffffff
MOVD mm6, eax
MOV eax, $ff000000
MOVD mm5, eax
MOV ecx, szBmp\cy
MOV j, ecx
MOV eax, 1
EntryY:
MOV ecx, szBmp\cx
MOV i, ecx
EntryX:
MOV ecx, *pPixel
MOVD mm0, [ecx] ;取像素
MOVQ mm2, mm0
PUNPCKLBW mm0, mm7 ;拆为 0A 0R 0G 0B(每字符代表1个字节,后同)
MOVQ mm1, mm0
PUNPCKHWD mm1, mm1 ;拆为 0A 0A 0R 0R
PUNPCKHDQ mm1, mm1 ;拆为 0A 0A 0A 0A
PMULLW mm0, mm1
PSRLW mm0, 8
PACKUSWB mm0, mm7
PAND mm0, mm6
PAND mm2, mm5
POR mm0, mm2
MOVD [ecx], mm0 ;放回
ADD *pPixel, 4
DEC i
JNZ l_entryx ;x循环截止
MOV ecx, eax ;保存(不能压栈)
MUL cbPerLine
ADD eax, *pBase
MOV *pPixel, eax ;下一行首地址
MOV eax, ecx
INC eax
DEC j
JNZ l_entryy ;y循环截止
EMMS
{
PXOR MM7,MM7 //MM7=0
MOVD MM0,[esi] //MM0=src;
MOVD MM2,[edi] //MM2=dst;
PUNPCKLBW MM0,MM7 //MM0转QWORD AABBGGRR->00AA00BB00GG00RR
PUNPCKLBW MM2,MM7 //MM2转QWORD AABBGGRR->00AA00BB00GG00RR
MOVQ MM1,MM0 //MM1=MM0
PUNPCKHWD MM1,MM1 //MM1 00AA00BB00GG00RR->00AA00AA00CC00CC
PUNPCKHDQ MM1,MM1 //MM1 00AA00AA00CC00CC->00AA00AA00AA00AA
PSUBW MM0,MM2 //MM0 -= MM2
PSLLW MM2,8 //MM2右移8位 00AA00BB00GG00RR->AA00BB00GG00RR00
PMULLW MM0,MM1 //MM0 *= MM1
PADDW MM2,MM0 //MM2 += MM0
PSRLW MM2,8 //MM2以Word为单位右移8位 AA??BB??GG??RR??->00AA00BB00GG00RR
PACKUSWB MM2,MM7 //MM2转DWORD 00AA00BB00GG00RR->AABBGGRR
MOVD [edi],MM2
}
Dst.Red = Src.Red * (Src.Alpha/255.0) + Dst.Red * (1.0 - (Src.Alpha/255.0))
Dst.Green = Src.Green * (Src.Alpha/255.0) + Dst.Green * (1.0 - (Src.Alpha/255.0))
Dst.Blue = Src.Blue * (Src.Alpha/255.0) + Dst.Blue * (1.0 - (Src.Alpha/255.0))
而不是我要的预乘:
Src.Red = Src.Red * Src.Alpha / 255
Src.Green = Src.Green * Src.Alpha / 255
Src.Blue = Src.Blue * Src.Alpha / 255
不过还是谢谢,可以触类旁通。