我有以下代码需要以25fps或更高的速度运行,我们现在可以。最终我们将使用高清视频,因此需要进一步优化以适应。
有什么方法可以优化这种方法吗?
public unsafe void OverlayImage(Bitmap overlay, Bitmap background, Bitmap output)
{
Rectangle lrEntire = new Rectangle(new Point(), background.Size);
BitmapData bdBack = background.LockBits(lrEntire, ImageLockMode.ReadOnly, background.PixelFormat);
BitmapData bdOverlay = overlay.LockBits(lrEntire, ImageLockMode.ReadOnly, overlay.PixelFormat);
BitmapData bdOut = output.LockBits(lrEntire, ImageLockMode.WriteOnly, output.PixelFormat);
uint* pBack = (uint*) bdBack.Scan0;
uint* pOverlay = (uint*) bdOverlay.Scan0;
uint* pOut = (uint*) bdOut.Scan0;
for (int luiToProcess = (bdBack.Height*bdBack.Stride) >> 2; luiToProcess != 0; luiToProcess--)
{
//get each pixel component
uint red = (*pBack & 0x00ff0000) >> 16; // red color component
uint green = (*pBack & 0x0000ff00) >> 8; // green color component
uint blue = *pBack & 0x000000ff; // blue color component
uint oalpha = (*pOverlay & 0xff000000) >> 24;
uint ored = (*pOverlay & 0x00ff0000) >> 16; // red color component
uint ogreen = (*pOverlay & 0x0000ff00) >> 8; // green color component
uint oblue = *pOverlay & 0x000000ff; // blue color component
//get each pixel color component
uint rOut = (red*(255 - oalpha) + (ored*oalpha))/255;
uint gOut = (green*(255 - oalpha) + (ogreen*oalpha))/255;
uint bOut = (blue*(255 - oalpha) + (oblue*oalpha))/255;
*pOut = bOut | gOut << 8 | rOut << 16 | 0x00 << 24;
//move to the next pixel
pBack++;
pOverlay++;
pOut++;
}
overlay.UnlockBits(bdOverlay);
background.UnlockBits(bdBack);
output.UnlockBits(bdOut);
}
答案 0 :(得分:1)
警告:答案很长,很多数字。
简短版本:这取决于您的叠加层,以下代码是否会使您的帧速率几乎翻倍。
查看发布的代码会想到几件事:
由于颜色通道是字节似乎更自然地对待它们而不是所有的屏蔽和移位,尽可能便宜..
你用oalpha
进行了不少计算;除非你期望它大部分是不相等的255或0额外的分支将节省一些乘法..(每个像素6个)
因为没有显示你如何调用你可能已经在做的例程,但这种事情需要并行处理;如果你在一个核心HD上获得25fps不应该是多核机器上的一个问题,即使是Parallel.For
简单的声音也会使你的输出倍增..
此外,您可以选择使用Lockbits & Mashalling
代替unsafe
;不确定这是否会更快,但我想我会写一个基准来做一些测试..
BTW:您的代码中有错误,afaiks,我认为您需要更改此
*pOut = bOut | gOut << 8 | rOut << 16 | 0x00 << 24;
,否则输出的alpha通道= 0
*pOut = (bOut | gOut << 8 | rOut << 16 ) | 0xff000000;
或者您可能想要计算最终的alpha ..
更新1:首次测试显示您的代码比Lockbits&amp;更快(~2x)。 Mashalling`版本,除非我搞砸了..)所以我从现在开始忽略#4 ..
更新2:
初步数字:
在i7-3770T 2.5GHz,W8.1 64的UI线程(!)上运行代码
更新3:
改为运行DrawImage:
使用此代码:
public void DrawImage(Bitmap overlay, Bitmap background, Bitmap output)
{
overlay.SetResolution(96, 96);
background.SetResolution(96, 96);
output.SetResolution(96, 96);
using (Graphics G = Graphics.FromImage(output) )
{
G.DrawImage(background, 0, 0);
G.CompositingMode = CompositingMode.SourceOver;
G.DrawImage(overlay, 0, 0);
}
}
更新4:
我现在尝试了更多的东西,可以说
public unsafe void OverlayImage3(Bitmap overlay, Bitmap background, Bitmap output)
{
Rectangle lrEntire = new Rectangle(new Point(), background.Size);
BitmapData bdBack = background.LockBits(lrEntire,
ImageLockMode.ReadOnly, background.PixelFormat);
BitmapData bdOverlay = overlay.LockBits(lrEntire,
ImageLockMode.ReadOnly, overlay.PixelFormat);
BitmapData bdOut = output.LockBits(lrEntire,
ImageLockMode.WriteOnly, output.PixelFormat);
byte* pBack = (byte*)bdBack.Scan0;
byte* pOverlay = (byte*)bdOverlay.Scan0;
byte* pOut = (byte*)bdOut.Scan0;
for (int luiToProcess = (bdBack.Height * bdBack.Stride) >> 2;
luiToProcess > 0; luiToProcess--)
{
//get each pixel component
byte red = *(pBack + 2);
byte green = *(pBack + 1);
byte blue = *(pBack + 0);
byte oalpha = *(pOverlay + 3);
byte ored = *(pOverlay + 2);
byte ogreen = *(pOverlay + 1);
byte oblue = *(pOverlay + 0);
//get each pixel color component
byte rOut, gOut, bOut;
if (oalpha == 255)
{ rOut = ored; gOut = ogreen; bOut = oblue; }
else if (oalpha == 0)
{ rOut = red; gOut = green; bOut = blue; }
else
{
rOut = (byte)((red * (255 - oalpha) + (ored * oalpha)) / 255);
gOut = (byte)((green * (255 - oalpha) + (ogreen * oalpha)) / 255);
bOut = (byte)((blue * (255 - oalpha) + (oblue * oalpha)) / 255);
}
*(pOut + 3) = 0xff;
*(pOut + 2) = rOut;
*(pOut + 1) = gOut;
*(pOut + 0) = bOut;
//move to the next pixel
pBack += 4; pOverlay += 4; pOut += 4;
}
还有一些数字:
HD_size(1920x1080)52,1 fps
OverlayImage3,其中60%的像素都有alpha混合
HD_size(1920x1080)46,7 fps
OverlayImage3,95%的所有像素都有alpha混合
DrawImage也可以从缺乏alpha混合中获益:
HD_size(1920x1080)41,8 fps
DrawImage,95%的所有像素都有alpha混合
第3点,并行处理显然会有所帮助,具体取决于您的硬件。
结论:我不知道你当前的分辨率,但是从SD到HD将在所有测试中花费5-6倍的时间,所以如果你现在只需要25fps,你需要的不仅仅是上面的代码;你需要并行处理,我要说..