欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

WPF实现将图像转化成粒子效果

程序员文章站 2022-05-28 14:30:22
...

实现效果如下:

WPF实现将图像转化成粒子效果

这里的处理逻辑首先是将图像进行马赛克处理,然后对于每一个需要填充的粒子按照颜色的深浅度计算粒子大小,最后按照坐标进行填充。

1、粒子类

    public class Particle
    {
        public Point Position;//位置
        public double Size;//尺寸
    }

2、图像处理类

    public class MosaicHelper
    {
        /// <summary>
        /// 马赛克处理
        /// </summary>
        /// <param name="bitmap"></param>
        /// <param name="effectWidth"> 影响范围 每一个格子数 </param>
        public static List<Particle> AdjustTobMosaic(System.Drawing.Bitmap bitmap, int effectWidth)
        {
            List<Particle> particleList = new List<Particle>();

            for (int heightOfffset = 0; heightOfffset < bitmap.Height; heightOfffset += effectWidth)
            {
                for (int widthOffset = 0; widthOffset < bitmap.Width; widthOffset += effectWidth)
                {
                    int avgR = 0, avgG = 0, avgB = 0;
                    int blurPixelCount = 0;

                    for (int x = widthOffset; (x < widthOffset + effectWidth && x < bitmap.Width); x++)
                    {
                        for (int y = heightOfffset; (y < heightOfffset + effectWidth && y < bitmap.Height); y++)
                        {
                            System.Drawing.Color pixel = bitmap.GetPixel(x, y);

                            avgR += pixel.R;
                            avgG += pixel.G;
                            avgB += pixel.B;

                            blurPixelCount++;
                        }
                    }

                    avgR = avgR / blurPixelCount;
                    avgG = avgG / blurPixelCount;
                    avgB = avgB / blurPixelCount;

                    for (int x = widthOffset; (x < widthOffset + effectWidth && x < bitmap.Width); x += effectWidth)
                    {
                        for (int y = heightOfffset; (y < heightOfffset + effectWidth && y < bitmap.Height); y += effectWidth)
                        {
                            particleList.Add(new Particle { Position = new Point(x, y), Size = CalculateSize(avgR, avgG, avgB, effectWidth) });
                        }
                    }
                }
            }
            return particleList; 
        }

        /// <summary>
        /// 计算粒子大小
        /// </summary>
        public static double CalculateSize(int avgR, int avgG, int avgB, int effectWidth)
        {
             return (255 -(avgR * 0.299 + avgG * 0.587 + avgB * 0.114)) / 255 * effectWidth;
        }
    }

3、主窗体xaml

<Window x:Class="NewMosaicDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:NewMosaicDemo"
        mc:Ignorable="d"
        Title="MainWindow" SizeToContent="WidthAndHeight" Background="#f0f0f0" WindowStartupLocation="CenterScreen">
    <Grid Margin="20">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="250"></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Canvas x:Name="mainCanvas" Grid.Column="1" Background="White" MinWidth="500" MinHeight="400" Margin="20,0,0,0"
                HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ClipToBounds="True">
        </Canvas>
        <GroupBox Grid.Column="0" Header="操作区">
            <StackPanel Orientation="Vertical">
                <Button x:Name="btnChooseImg" Content="选择图片" VerticalAlignment="Center" HorizontalAlignment="Center" Height="26" Width="80" Margin="10" Click="btnChooseImg_Click"></Button>
                <Image x:Name="showImage" Width="200" Height="200" Stretch="Uniform"></Image>
                <StackPanel Margin="18">
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="5" Margin="2,0,0,0"/>
                        <TextBlock Text="10" Margin="50,0,0,0"/>
                        <TextBlock Text="15" Margin="50,0,0,0"/>
                        <TextBlock Text="20" Margin="50,0,0,0"/>
                    </StackPanel>
                    <Slider x:Name="particleSizeSlider" Minimum="5" Maximum="20" TickFrequency="5" IsSnapToTickEnabled="True" TickPlacement="TopLeft" ValueChanged="particleSizeSlider_ValueChanged"></Slider>
                </StackPanel>
            </StackPanel>
        </GroupBox>
    </Grid>
</Window>

交互逻辑

    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        private System.Drawing.Bitmap map;//待处理的图源

        public MainWindow()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 选择图片
        /// </summary>
        private void btnChooseImg_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.Title = "选择图片";
            openFileDialog.Filter = "图片(*.jpg,*.png,*.bmp)|*.jpg;*.png;*.bmp"; ;
            openFileDialog.FileName = string.Empty;
            openFileDialog.Multiselect = false;
            openFileDialog.InitialDirectory = @"C:\Image";
            if (openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                this.showImage.Source = ImageHelper.LoadBitmapImageByPath(openFileDialog.FileName);
                System.Drawing.Image img = System.Drawing.Image.FromFile(openFileDialog.FileName);
                map = new System.Drawing.Bitmap(img);
                HandleImage(Convert.ToInt32(this.particleSizeSlider.Value));
            }
        }

        private void particleSizeSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (!this.particleSizeSlider.IsLoaded) return;
            HandleImage(Convert.ToInt32(this.particleSizeSlider.Value));
        }

        /// <summary>
        /// 处理图片
        /// </summary>
        private void HandleImage(int effectWidth)
        {
            if (map == null) return;
            this.mainCanvas.Children.Clear();
            List<Particle> particleList = MosaicHelper.AdjustTobMosaic(map, effectWidth);
            foreach (var pd in particleList)
            {
                var ep = new Ellipse
                {
                    Width = pd.Size,
                    Height = pd.Size,
                    Fill = new SolidColorBrush(Colors.Black),
                };
                Canvas.SetTop(ep, pd.Position.Y);
                Canvas.SetLeft(ep, pd.Position.X);
                this.mainCanvas.Children.Add(ep);
            }
        }
    }