如何将实时gaussain模糊效果应用于UWP应用程序
本文关键字:应用于 UWP 应用程序 模糊 实时 gaussain | 更新日期: 2023-09-27 18:20:57
最近我在学习UWP,并试图构建一个简单的演示,我只想生成一个像Aero一样的简单实时模糊效果。它有时很有用(例如实时相机滤镜),所以我想出了这样一个主意:
首先,我导入了win2D库,并在RootGrid:上放置了一个CanvasAnimatedControl
<canvas:CanvasAnimatedControl x:Name="BlurLayer" Draw="BlurLayer_Draw"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>
该模糊层的资源是帧:
<Frame x:Name="MainFrame" LayoutUpdated="MainFrame_LayoutUpdated"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>
并且每当帧更新时,MainFrame_LayoutUpdated方法尝试保存使用RenderTargetBitmap的快捷方式,但是win2D无法将此对象作为其CanvasBitmap接收,因此将其转换为byte[]并保存;
RenderTargetBitmap renderer = new RenderTargetBitmap();
CanvasBitmap bitmap;
byte[] RendererStream;
public static int FrameWidth;
public static int FrameHeight;
public ICanvasImage RenderFinal;
public bool Frame_Updated = false;
private async void MainFrame_LayoutUpdated(object sender, object e)
{
await renderer.RenderAsync(MainFrame);
FrameWidth = renderer.PixelWidth;
FrameHeight = renderer.PixelHeight;
RendererStream = WindowsRuntimeBufferExtensions.ToArray(await renderer.GetPixelsAsync());
if (FrameHeight != 0)
Frame_Updated = true;
}
在BlurLayer_Draw方法中,只需刷新并应用模糊效果:private void BlurLayer_Draw(ICanvasAnimatedControl发送器,
CanvasAnimatedDrawEventArgs args)
{
if (Frame_Updated)
{
bitmap = CanvasBitmap.CreateFromBytes(sender, RendererStream, FrameWidth, FrameHeight, DirectXPixelFormat.B8G8R8A8UIntNormalized);
RenderFinal = new GaussianBlurEffect
{
Source = bitmap
};
RenderFinal.BorderMode = EffectBorderMode.Hard;
RenderFinal.BlurAmount = 8.0f;
Frame_Updated = false;
}
if (RenderFinal != null)
args.DrawingSession.DrawImage(RenderFinal);
}
当所有这些都完成后,它就起了作用。但这个解决方案真的很糟糕,win2D Canvas严重延迟。那么,我应该怎么做才能使它具有高性能呢?
让我的评论成为官方答案:使用Lumia Imaging SDK。如果使用SwapChainPanelRenderer进行实时渲染,它具有非常快速的BlurEffect。我在博客文章《使用SwapChainPanelRenderer改进Lumia Imaging SDK 3中的实时渲染》中写到了这一点,我在其中使用了BlurEffect作为示例。GitHub上提供了完整的源代码。
归根结底,只要模糊KernelSize值更改为新滑块值,就可以在SwapChainPanelRenderer
实例上调用RenderAsync
。
private async void EffectRangeSlider_OnValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
if (this.renderer != null)
{
this.viewModel.blur.KernelSize = (int)e.NewValue;
await this.renderer.RenderAsync();
}
}