Как применить эффект размытия по Гауссену в реальном времени к приложениям UWP?

Недавно я изучал UWP и пытался создать простую демонстрацию, и я просто хочу создать простой эффект живого размытия, такой как Aero. Иногда это полезно (например, фильтры камеры в реальном времени), поэтому я придумал такую ​​идею:

Сначала я импортировал библиотеку win2D и поместил CanvasAnimatedControl в RootGrid:

<canvas:CanvasAnimatedControl x:Name="BlurLayer" Draw="BlurLayer_Draw" 
                              VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>

Ресурсом этого слоя размытия является Frame:

<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 sender,

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 серьезно задержался. Итак, что я должен сделать, чтобы добиться высокой производительности?


person EmbraceZXS    schedule 08.11.2015    source источник
comment
Может быть, вам поможет SharpDX? sharpdx.org/documentation/api/ Он использует DirectX и должен быть более производительным.   -  person sibbl    schedule 08.11.2015
comment
У меня есть запись в блоге об очень быстром размытии с помощью Lumia Imaging SDK igrali.com/2015/09/26/, а также проект находится на GitHub github.com/igrali/PropertyDescriptions, возможно, это поможет вам!   -  person Igor Ralic    schedule 08.11.2015
comment
@sibbl Я бы хотел попробовать.   -  person EmbraceZXS    schedule 09.11.2015
comment
@igrali Я прочитал ваш блог и попробовал ваш образец, это очень быстро и именно то, что я хочу. спасибо.   -  person EmbraceZXS    schedule 09.11.2015
comment
@EmbraceZXS хорошо, отлично! Я также разместил это как ответ :)   -  person Igor Ralic    schedule 09.11.2015


Ответы (1)


Делая мой комментарий официальным ответом: используйте Lumia Imaging SDK. Он имеет BlurEffect, который очень быстр, если использовать его для рендеринга в реальном времени с помощью SwapChainPanelRenderer. Я написал об этом в своем блоге Использование SwapChainPanelRenderer для улучшения рендеринга в реальном времени в Lumia Imaging SDK 3, где в качестве примера я использовал именно BlurEffect. Полный исходный код доступен на GitHub.

Это сводится к вызову RenderAsync для экземпляра SwapChainPanelRenderer всякий раз, когда значение размытия KernelSize изменяется на новое значение ползунка.

private async void EffectRangeSlider_OnValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
    if (this.renderer != null)
    {
        this.viewModel.blur.KernelSize = (int)e.NewValue;

        await this.renderer.RenderAsync();
    }
}
person Igor Ralic    schedule 09.11.2015