• WPF/C#实现图像滤镜优化方案:打造炫目视觉体验!


    原因:我之所以想做这个项目,是因为在之前查找关于C#/WPF相关资料时,我发现讲解图像滤镜的资源非常稀缺。此外,我注意到许多现有的开源库主要基于CPU进行图像渲染。这种方式在处理大量图像时,会导致CPU的渲染负担过重。因此,我将在下文中介绍如何通过GPU渲染来有效实现图像的各种滤镜效果。

    生成的效果

    生成效果的方法:我主要是通过参考Shazzam Shader Editor来编写HLSL像素着色器。

    HLSL(High Level Shader Language,高级着色器语言)是Direct3D着色器模型所需的一种语言。WPF不仅支持Direct3D 9,还支持使用HLSL来创建着色器。虽然可以使用多种编辑器来编写HLSL,但Shazzam Shader Editor是一款专为WPF设计的编辑器,它专门用于实现像素着色器。使用Shazzam可以简化将像素着色器集成到WPF项目中所需的各种手动操作。(关于如何使用Shazzam,可在线查找详细教程。)

    在我的项目中,我根据所需的效果生成相应的.PS和.CS文件,并将这些文件添加到类库中。接着,我会在具体的项目中引入这个库来实现效果

    项目实现细节

    开发环境

    • 使用的MVVM库:CommunityToolkit.Mvvm
    • 目标框架:.NET 8.0
    • 开发工具:Visual Studio 2022

    使用的样式库

    项目中采用了AduSkin样式库。个人建议:​我不特别推荐使用AduSkin,主要是因为它缺乏官方文档,需要通过查看源代码来学习使用。此外,一些样式的命名与源代码中的不一致,这可能会导致一些困惑。(备注:我最初选择使用AduSkin是因为其UI设计在网络上获得了好评,尽管某些效果确实很吸引人,但缺少文档导致使用上的不便。)

    项目结构概述

    项目在构建过程中,考虑到几种特效之间存在一些共同的重复元素,如图片展示和图片导入功能,因此我将这些共用功能模块化。

    • 操作区域的定制化:​对于每种不同的特效,操作区的需求也不尽相同。在Common控件中,我使用了Option控件来进行替代,以便于在外部进行定制。
    • 特效的动态调整:​每种特效的具体实现都有所不同,因此我设定了一个独立的属性ImageEffect,允许从外部动态修改。
    • 公共控件:CommonEffectControl作为一个公共控件,用于整合图片显示和图片导入的共通功能。

    具体引用的步骤

    需要添加命令空间

    •  xmlns:common="clr-namespace:CT.WPF.MagicEffects.Demo.UserControls.Common"

    前台代码

    查看代码
     <common:CommonEffectControl ImageEffect="{Binding SelectedOrdinary.ObjectShaderEffect}">
         <common:CommonEffectControl.Option>
             <StackPanel Orientation="Vertical">
                 <Border BorderBrush="Transparent" BorderThickness="0">
                     <Skin:MetroScrollViewer ScrollViewer.VerticalScrollBarVisibility="Visible">
                         <ListView
                             Width="240"
                             Height="550"
                             BorderThickness="0"
                             ItemsSource="{Binding Ordinarys}"
                             ScrollViewer.HorizontalScrollBarVisibility="Disabled"
                             ScrollViewer.VerticalScrollBarVisibility="Hidden"
                             SelectedItem="{Binding SelectedOrdinary, Mode=TwoWay}"
                             SelectionMode="Single">
                             <ListView.ItemTemplate>
                                 <DataTemplate>
                                     <StackPanel
                                         MinHeight="110"
                                         VerticalAlignment="Center"
                                         Orientation="Vertical">
                                         <Viewbox
                                             Width="99"
                                             Height="78"
                                             Margin="2">
                                             <Image Effect="{Binding ObjectShaderEffect}" Source="{Binding Path=Main.SelectedImagePath, Source={StaticResource Locator}}" />
                                         Viewbox>
                                         <TextBlock
                                             HorizontalAlignment="Center"
                                             FontSize="14"
                                             Foreground="{Binding RelativeSource={RelativeSource AncestorType={x:Type Skin:MetroWindow}}, Path=BorderBrush, Mode=TwoWay}"
                                             Text="{Binding Title}"
                                             TextWrapping="Wrap" />
                                     StackPanel>
                                 DataTemplate>
                             ListView.ItemTemplate>
                             <ListView.ItemsPanel>
                                 <ItemsPanelTemplate>
                                     <WrapPanel Orientation="Horizontal" />
                                 ItemsPanelTemplate>
                             ListView.ItemsPanel>
                         ListView>
    
                     Skin:MetroScrollViewer>
                 Border>
             StackPanel>
         common:CommonEffectControl.Option>
     common:CommonEffectControl>

    ViewModel部分

    查看代码
       partial class OrdinaryEffectViewModel : ObservableObject {
          public OrdinaryEffectViewModel() {
              Ordinarys = new ObservableCollection<Ordinarys> {
                  new Ordinarys(){ Title="灰度", ObjectShaderEffect= new GrayScaleEffect ()},
                  new Ordinarys(){ Title="位移", ObjectShaderEffect= new DirectionalBlurEffect ()},
                  new Ordinarys(){ Title="老电影", ObjectShaderEffect= new OldMovieEffect ()},
                  new Ordinarys(){ Title="锐化", ObjectShaderEffect= new SharpenEffect ()},
              };
          }
          [ObservableProperty]
          private ObservableCollection<Ordinarys> ordinarys;
          [ObservableProperty]
          private Ordinarys selectedOrdinary;
      }

    model部分

    查看代码
      partial class Ordinarys : ObservableObject {
         [ObservableProperty]
         private string? title;
         [ObservableProperty]
         private ShaderEffect? objectShaderEffect;
     }

    还有摄像头滤镜覆盖的效果欢迎大家体验!!!

    已经发布nuget:dotnet add package MagicEffects --version 1.0.0

    github:CT.WPF.MagicEffects

     

  • 相关阅读:
    单词规律(C++解法)
    Java常用机制 - SPI机制详解
    Linux学习系列--如何在Linux中进行文件的管理
    上采样之反卷积操作
    GPS北斗时钟服务器(NTP网络时钟系统)施工部署方案
    从零开始打造一款基于SpringBoot+SpringCloud的后台权限管理系统
    【力扣】两数相除(c/c++)
    设计模式——模板方法模式
    Java 数据结构与算法 堆
    烟台企业专利质押需要签署质押合同吗
  • 原文地址:https://www.cnblogs.com/qingxi11/p/18138196